# Spaces

A `Space`

is an abstract type whose subtypes indicate which space a function lives in. This typically corresponds to the span of a (possibly infinite) basis.

## Classical orthogonal polynomial spaces

`Chebyshev`

, `Ultraspherical`

, `Jacobi`

, `Hermite`

, and `Laguerre`

are spaces corresponding to expansion in classical orthogonal polynomials.

Note that we always use the classical normalization: the basis are *not* orthonormal. This is because this normalization leads to rational recurrence relationships, which are more efficient than their normalized counterparts. See the Digital Library of Mathematical Functions for more information.

### Chebyshev space

The default space in ApproxFun is `Chebyshev`

, which represents expansions in Chebyshev polynomials:

where $T_k(x) = \cos k \,{\rm acos} x$, which are orthogonal polynomials with respect to the weight $ {1 \over \sqrt{1-x^2}} \qquad\hbox{for}\qquad -1 \leq x \leq 1. $ Note that there is an intrinsic link between `Chebyshev`

and `CosSpace`

:

In other words:

```
julia> f=Fun(exp,Chebyshev());
julia> g=Fun(CosSpace(),f.coefficients); # specify the coefficients directly
julia> f(cos(0.1))
2.70473560723178
julia> g(0.1)
2.7047356072317794
```

### Ultraspherical spaces

A key tool for solving differential equations are the ultraspherical spaces, encoded as `Ultraspherical(λ)`

for `λ ≠ 0`

, which can be defined by the span of derivatives of Chebyshev polynomials, or alternatively as polynomials orthogonal with respect to the weight $ (1-x^2)^{\lambda - 1/2} \qquad\hbox{for}\qquad -1 \leq x \leq 1. $

Note that `Ultraspherical(1)`

corresponds to the Chebyshev basis of the second kind: $U_k(x) = {\sin (k+1) {\rm acos} x \over \sin {\rm acos} x}$. The relationship with Chebyshev polynomials follows from trigonemetric identities: $T_k'(x) = k U_{k-1}(x)$.

Converting between ultraspherical polynomials (with integer orders) is extremely efficient: it requires $O(n)$ operations, where $n$ is the number of coefficients.

### Jacobi spaces

`Jacobi(b,a)`

represents the space spanned by the Jacobi polynomials, which are orthogonal polynomials with respect to the weight $ (1+x)^b(1-x)^a $ using the standard normalization.

## Fourier and Laurent spaces

There are several different spaces to represent functions on periodic domains, which are typically a `PeriodicSegment`

, `Circle`

or `PeriodicLine`

.

`CosSpace`

represents expansion in cosine series:

`SinSpace`

represents expansion in sine series:

`Taylor`

represents expansion with only non-negative complex exponential terms:

`Hardy{false}`

represents expansion with only negative complex exponential terms:

`Fourier`

represents functions that are sums of sines and cosines. Note that if a function has the form

then the coefficients of the resulting `Fun`

are order as $[f_0,f_1^{\rm s},f_1^{\rm c},…]$. For example:

```
julia> f = Fun(Fourier(),[1,2,3,4]);
julia> f(0.1)
4.979356652307978
julia> 1 + 2sin(0.1) + 3cos(0.1) + 4sin(2*0.1)
4.979356652307979
```

`Laurent`

represents functions that are sums of complex exponentials. Note that if a function has the form

then the coefficients of the resulting `Fun`

are order as $[f_0,f_{-1},f_1,…]$. For example:

```
julia> f = Fun(Laurent(),[1,2,3,4]);
julia> f(0.1)
9.895287137755096 - 0.694843906533417im
julia> 1 + 2exp(-im*0.1) + 3exp(im*0.1) + 4exp(-2im*0.1)
9.895287137755094 - 0.6948439065334167im
```

## Modifier spaces

Some spaces are built out of other spaces:

`JacobiWeight`

`JacobiWeight(β,α,space)`

weights `space`

, which is typically `Chebyshev()`

or `Jacobi(b,a)`

, by a Jacobi weight `(1+x)^α*(1-x)^β`

: in other words, if the basis for `space`

is $\psi_k(x)$ and the domain is the unit interval `-1 .. 1`

, then the basis for `JacobiWeight(β,α,space)`

is $(1+x)^α(1-x)^β \psi_k(x)$. If the domain is not the unit interval, then the basis is determined by mapping back to the unit interval: that is, if $M(x)$ is the map dictated by `tocanonical(space, x)`

, where the canonical domain is the unit interval, then the basis is $(1+M(x))^α(1-M(x))^β \psi_k(x)$. For example, if the domain is another interval `a .. b`

, then $ M(x) = {2x-b-a \over b-a} $ and the basis becomes $ \left({2 \over (b-a)}\right)^{\alpha+\eta} (x-a)^α(b-x)^β \psi_k(x) $

`SumSpace`

`SumSpace((space_1,space_2,…,space_n))`

represents the direct sum of the spaces, where evaluation is defined by adding up each component. A simple example is the following, showing that the coefficients are stored by interlacing:

```
julia> x = Fun(identity,-1..1);
julia> f = cos(x-0.1)*sqrt(1-x^2) + exp(x);
julia> space(f) # isa SumSpace
(1-x^2)^0.5[Chebyshev(【-1.0,1.0】)]⊕Chebyshev(【-1.0,1.0】)
julia> a, b = components(f);
julia> a(0.2) # cos(0.2-0.1)*sqrt(1-0.2^2)
0.9749009987500246
julia> b(0.2) # exp(0.2)
1.2214027581601699
julia> f(0.2) # a(0.2) + b(0.2)
2.1963037569101944
julia> norm(f.coefficients[1:2:end] - a.coefficients)
0.0
julia> norm(f.coefficients[2:2:end] - b.coefficients)
0.0
```

More complicated examples may interlace the coefficients using a different strategy. Note that it is difficult to represent the first component of function $f$ by a Chebyshev series because the derivatives of $f$ at its boundaries blow up, whereas the derivative of a polynomial is a polynomial.

Note that `Fourier`

and `Laurent`

are currently implemented as `SumSpace`

, but this may change in the future.

`PiecewiseSpace`

`PiecewiseSpace((space_1,space_2,…,space_n))`

represents the direct sum of the spaces, where evaluation is defined in a piecewise way. A simple example is the following:

```
julia> x = Fun(Domain(-1 .. 0) ∪ Domain( 1 .. 2));
julia> f = exp(x);
julia> a, b = components(f);
julia> f(-0.5) - a(-0.5)
0.0
julia> f(1.5) - b(1.5)
0.0
julia> f(0.5) # outside domain components
0.0
julia> norm(f.coefficients[2:2:end] - b.coefficients)
0.0
julia> norm(f.coefficients[1:2:end] - a.coefficients)
0.0
```

More complicated examples may interlace the coefficients using a different strategy.

`ArraySpace`

`ArraySpace(::Array{<:Space})`

represents the direct sum of the spaces, where evaluation is defined in an array-wise manner. A simple example is the following:

```
julia> x = Fun(identity,-1..1);
julia> f = [exp(x); sqrt(1-x^2)*cos(x-0.1)];
julia> space(f)
2-element ArraySpace:
Chebyshev(【-1.0,1.0】)
(1-x^2)^0.5[Chebyshev(【-1.0,1.0】)]
julia> a, b = components(f);
julia> norm(f(0.5) - [a(0.5); b(0.5)])
0.0
julia> norm(f.coefficients[1:2:end] - a.coefficients)
0.0
julia> norm(f.coefficients[2:2:end] - b.coefficients)
0.0
```

More complicated examples may interlace the coefficients using a different strategy.

`TensorSpace`

`TensorSpace((space_1,space_2))`

represents the tensor product of two spaces. See documentation of `TensorSpace`

for more details on how the coefficients are interlaced. Note that more than two spaces is only partially supported.

## Unset space

`UnsetSpace`

is a special space that is used as a stand in when a space has not yet been determined, particularly by operators.