# 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:

\[\mathop{f}(x) = \sum_{k=0}^∞ f_k \mathop{T}_k(x),\]

where $\mathop{T}_k(x) = \cos(k\arccos{x})$, which are orthogonal polynomials with respect to the weight

\[\frac{1}{\sqrt{1-x^2}} \quad\text{for}\quad -1 ≤ x ≤ 1.\]

Note that there is an intrinsic link between `Chebyshev`

and `CosSpace`

:

\[\mathop{g}(θ) = \mathop{f}(\cos{θ}) = \sum_{k=0}^∞ f_k \cos{kθ}.\]

In other words:

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

### 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)^{λ - \frac{1}{2}}$ for $-1 ≤ x ≤ 1$.

Note that `Ultraspherical(1)`

corresponds to the Chebyshev basis of the second kind: $\mathop{U}_k(x) = \frac{\sin((k+1)\arccos{x})}{\sin(\arccos{x})}$. The relationship with Chebyshev polynomials follows from trigonometric identities: $\mathop{T}_k'(x) = k \mathop{U}_{k-1}(x)$.

Converting between ultraspherical polynomials (with integer orders) is extremely efficient: it requires $\mathop{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:

\[\mathop{f}(θ) = \sum_{k=0}^∞ f_k \cos{kθ}.\]

`SinSpace`

represents expansion in sine series:

\[\mathop{f}(θ) = \sum_{k=0}^∞ f_k \sin{(k+1)θ}.\]

`Fourier`

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

\[\mathop{f}(θ) = f_0 + \sum_{k=1}^∞ \left(f_k^\mathrm{s} \sin{kθ} + f_k^\mathrm{c} \cos{kθ}\right),\]

then the coefficients of the resulting `Fun`

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

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

`Taylor`

represents expansion with only non-negative complex exponential terms:

\[\mathop{f}(θ) = \sum_{k=0}^∞ f_k \mathop{e}^{ikθ}.\]

`Hardy{false}`

represents expansion with only negative complex exponential terms:

\[\mathop{f}(θ) = \sum_{k=0}^∞ f_k \mathop{e}^{-i(k+1)θ}.\]

`Laurent`

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

\[\mathop{f}(θ) = \sum_{k=-∞}^∞ f_k \mathop{e}^{ikθ},\]

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) ≈ 1 + 2exp(-im*0.1) + 3exp(im*0.1) + 4exp(-2im*0.1)
true
```

## 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 $\mathop{ψ}_k(x)$ and the domain is the unit interval `-1..1`

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

is $(1+x)^α(1-x)^β \mathop{ψ}_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 $\mathop{M}(x)$ is the map dictated by `tocanonical(space, x)`

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

, then

\[\mathop{M}(x) = \frac{2x-b-a}{b-a},\]

and the basis becomes

\[\left(\frac{2}{b-a}\right)^{α+β} (x-a)^α (b-x)^β \mathop{ψ}_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) == JacobiWeight(0.5, 0.5, Chebyshev(-1..1)) + Chebyshev(-1..1)
true
julia> a, b = components(f);
julia> a(0.2) ≈ cos(0.2-0.1)*sqrt(1-0.2^2)
true
julia> b(0.2) ≈ exp(0.2)
true
julia> f(0.2) ≈ a(0.2) + b(0.2)
true
julia> norm(coefficients(f)[1:2:end] - coefficients(a))
0.0
julia> norm(coefficients(f)[2:2:end] - coefficients(b))
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 $\mathop{f}$ by a Chebyshev series because the derivatives of $\mathop{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.

`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) isa ApproxFun.ArraySpace
true
julia> a, b = components(f);
julia> norm(f(0.5) - [a(0.5); b(0.5)])
0.0
julia> norm(coefficients(f)[1:2:end] - coefficients(a))
0.0
julia> norm(coefficients(f)[2:2:end] - coefficients(b))
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 the 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.