Sciences Po, Spring 2019
where
We will construct a grid of $M\geq J$ points ${x_1,\dots,x_M}$ within the domain $\mathbb{R}^d$, and we will denote the residuals at each grid point by $\epsilon = {\epsilon_1,\dots,\epsilon_M}$:
$$ \left[\begin{array}{c} \epsilon_1 \\ \vdots \\ \epsilon_M \\ \end{array} \right] = \left[\begin{array}{c} f(x_1) \\ \vdots \\ f(x_M) \end{array} \right] - \left[\begin{array}{ccc} \phi_1(x_1) & \dots & \phi_J(x_1) \\ \vdots & \ddots & \vdots \\ \phi_1(x_M) & \dots & \phi_J(x_M) \end{array} \right] \cdot \left[\begin{array}{c} c_1 \\ \vdots \\ c_J \end{array} \right] \\ \mathbf{\epsilon} = \mathbf{y} - \mathbf{\Phi c} $$where the second line uses vector notation, and $\mathbf{y}$ has all values of $f$.
for the case with $m$ evaluation nodes for $x$, and $n$ basis functions for each $x_i$.
0 & n\ne m \\ \pi & n=m=0 \\ \frac{\pi}{2} & n=m\ne 0
\end{cases}
$$ T_0(x) & = 1 \\
T_1(x) & = x \\
T_{n+1}(x) & = 2xT_n(x) - T_{n-1}(x).
\end{align}function T(x,n)
@assert (x >= -1) & (x <= 1)
if n == 0
return 1.0
elseif n==1
return x
else
2*x*T(x,n-1) - T(x,n-2)
end
end
T2(x,n) = cos(n* acos(x))
@show T(0.5,3)
using Test
@assert T2(0.5,3) == T(0.5,3)
T(0.5, 3) = -1.0
# weighting function
w(x) = 1.0 / sqrt(1-x^2)
using Statistics
using Test
# simple integration works for n not equal m
@assert isapprox(mean(T(x,0) * T(x,1) * w(x) for x in range(-0.99,stop = 0.99, length=100)), 0.0, atol = 1e-16)
@assert isapprox(mean(T(x,4) * T(x,5) * w(x) for x in range(-0.99,stop = 0.99, length=100)), 0.0, atol = 1e-16)
using Plots
using FastGaussQuadrature
gcnodes = gausschebyshev(21) # generate 11 Chebyshev Nodes
gr()
scatter(gcnodes,ones(21),ylims=(0.9,1.1),m=(:red,:+),legend=false,size=(600,100),yticks=nothing)
using BasisMatrices
x = range(-4, stop = 4 ,length = 10)
ϕ = Basis(ChebParams(length(x),-4,4))
ϕ
┌ Info: Recompiling stale cache file /Users/florian.oswald/.julia/compiled/v1.1/BasisMatrices/65PSC.ji for BasisMatrices [08854c51-b66b-5062-a90d-8e7ae4547a49] └ @ Base loading.jl:1184
1 dimensional Basis on the hypercube formed by (-4.0,) × (4.0,). Basis families are Cheb
S, y = nodes(ϕ)
([-3.95075, -3.56403, -2.82843, -1.81596, -0.625738, 0.625738, 1.81596, 2.82843, 3.56403, 3.95075], ([-3.95075, -3.56403, -2.82843, -1.81596, -0.625738, 0.625738, 1.81596, 2.82843, 3.56403, 3.95075],))
Φ = BasisMatrix(ϕ, Expanded(), S, 0)
BasisMatrix{Expanded} of order [0]
Φ.vals[1]' * Φ.vals[1]
10×10 Array{Float64,2}: 10.0 -1.11022e-16 -2.22045e-16 … -2.10942e-15 -5.32907e-15 -1.11022e-16 5.0 -1.41698e-15 -4.571e-15 -2.46571e-15 -2.22045e-16 -1.41698e-15 5.0 -2.33515e-15 -5.35038e-15 -1.88738e-15 -5.05353e-16 -1.91117e-15 -4.6033e-15 -2.2613e-15 -1.22125e-15 -2.38199e-15 -1.46093e-15 -2.66302e-15 -4.90537e-15 -2.77556e-15 -1.43304e-15 -2.71577e-15 … -4.67867e-15 -2.25549e-15 -1.66533e-15 -3.38498e-15 -2.09657e-15 -2.23671e-15 -4.98201e-15 -3.88578e-15 -1.76844e-15 -3.9379e-15 -4.87009e-15 -2.42363e-15 -2.10942e-15 -4.571e-15 -2.33515e-15 5.0 -4.90931e-15 -5.32907e-15 -2.46571e-15 -5.35038e-15 -4.90931e-15 5.0
Julia
: ApproxFun.jl
¶ApproxFun.jl
is a Julia package based on the Matlab package chebfun
. It is quite amazing.using LinearAlgebra, SpecialFunctions, Plots, ApproxFun
x = Fun(identity,0..10)
f = sin(x^2)
g = cos(x)
h = f + g^2
r = roots(h)
rp = roots(h')
using Plots
plot(h,labels = "h")
scatter!(r,h.(r),labels="roots h")
scatter!(rp,h.(rp),labels = "roots h'")
# works even with discontinuities!
ff = x->sign(x-0.1)/2 + cos(4*x); # sign introduces a jump at 0.1
x = Fun(identity) # set up a function space
space(x)
f = ff(x) # define ff on that space
plot(f) # plot
# whats the first deriv of that function at at 0.785?
println(f'(0.785))
# and close to the jump, at 0.100001?
println(f'(0.1000001))
# integral of f?
g1 = cumsum(f)
g = g1 + f(-1)
integral = norm(f-g)
integral
-0.006370611665950006 -1.5576748429320297
2.357186284506263
S = Chebyshev(1..2);
n = 100; m = 50;
p = range(1,stop=2,length=n); # a non-default grid
v = exp.(p); # values at the non-default grid
V = Array{Float64}(undef,n,m); # Create a Vandermonde matrix by evaluating the basis at the grid
for k = 1:m
V[:,k] = Fun(S,[zeros(k-1);1]).(p)
end
f = Fun(S,V\v);
@show f(1.1)
@show exp(1.1)
f(1.1) = 3.004166023946432 exp(1.1) = 3.0041660239464334
3.0041660239464334
ApproXD
):= length(z)
)We can define $B_j^{k,\mathbf{z}} (x)$ recursively like this:
$$ B_j^{k,\mathbf{z}} (x) = \frac{x-z_{j-k}}{z_j - z_{j-k}} B_{j-1}^{k-1,\mathbf{z}} (x) + \frac{z_{j+1}-x}{z_{j+1} - z_{j+1-k}} B_{j}^{k-1,\mathbf{z}} (x), j=1,\dots,n $$
The derivative wrt to it's argument $x$ is
$$ \frac{d B_j^{k,\mathbf{z}} (x)}{dx} = \frac{k}{z_j - z_{j-k}} B_{j-1}^{k-1,\mathbf{z}} (x) + \frac{k}{z_{j+1} - z_{j+1-k}} B_{j}^{k-1,\mathbf{z}} (x), j=1,\dots,n $$
Similarly, the Integral is just the sum over the basis functions: $$ \int_a^x B_j^{k,\mathbf{z}} (y) dy = \sum_{i=j}^n \frac{z_i - z_{i-k}}{k} B_{i+1}^{k+1,\mathbf{z}} (x) $$
using ApproXD
# ] dev https://github.com/floswald/ApproXD.jl
bs = BSpline(7,3,0,1) #7 knots, degree 3 in [0,1]
# how many basis functions? (go back 1 slide.)
# getNumCoefs(bs)
x = range(0,stop =1.0, length = 500)
B = Array(getBasis(collect(x),bs))
plot(x,B,layout=(3,3),grid=false,ylim=(-0.1,1.1),legend=false,linewidth=2,linecolor=:black)
# Notice that placing each of those panels on top of each other generates a sparse matrix!
plot(x,B,grid=false,ylim=(-0.1,1.1),legend=false)
bs = BSpline(9,1,0,1) #9 knots, degree 1 in [0,1]
x = range(0,stop = 1.0,length = 500)
B = Array(getBasis(collect(x),bs))
plot(x,B,layout=(3,3),grid=false,ylim=(-0.1,1.1),legend=false,linewidth=2,linecolor=:black)
julia
implements searchsortedlast
. gg(x) = (1+25x^2)^(-1)
plot(gg)
Interpolations.jl
¶1:N
1:N
to different domains# interpolation
# restart kernel!
using Interpolations
A = rand(10,5)
itp = interpolate(A, Interpolations.BSpline(Quadratic(Reflect(OnCell()))))
itp(1.9,4.9)
0.2609001368014953
A
10×5 Array{Float64,2}: 0.0440558 0.0759254 0.424806 0.0733616 0.0104042 0.131006 0.692091 0.435421 0.363613 0.789312 0.423814 0.765224 0.962783 0.48646 0.768033 0.35892 0.394449 0.938537 0.729178 0.706436 0.54336 0.148386 0.236388 0.580917 0.192891 0.507772 0.517813 0.207813 0.930954 0.707769 0.868053 0.959416 0.726591 0.741459 0.283866 0.293944 0.547819 0.851113 0.550485 0.270864 0.134517 0.998558 0.975837 0.704406 0.862646 0.452014 0.307677 0.469785 0.365602 0.178347
A[2,5]
0.7893123641918425
A_x = 1.:2.:40. # x in [1,40]
A = [log(x) for x in A_x] # f(x)
itp = interpolate(A, Interpolations.BSpline(Cubic(Interpolations.Line(OnGrid()))))
sitp = scale(itp, A_x) # scale x-axis of interpolator
@show sitp(3.) # exactly log(3.)
@show sitp(3.5) # approximately log(3.5)
@show itp(3); # is the 3rd index(!) in A, not the *value* 3
sitp(3.0) = 1.0986122886681098 sitp(3.5) = 1.2748716241925298 itp(3) = 1.6094379124341
# Same for 2D
A_x1 = 1:.1:10
A_x2 = 1:.5:20
fff(x1, x2) = log(x1+x2)
A = [fff(x1,x2) for x1 in A_x1, x2 in A_x2]
itp = interpolate(A, Interpolations.BSpline(Cubic(Interpolations.Line(OnGrid()))))
sitp = scale(itp, A_x1, A_x2)
sitp(5., 10.) # exactly log(5 + 10)
sitp(5.6, 7.1) # approximately log(5.6 + 7.1)
2.541602006923902
GriddedInterpolation
type is useful.A = rand(20)
A_x = collect(1.0:2.0:40.0)
knots = (A_x,)
itp = interpolate(knots, A, Gridded(Linear()))
itp(2.0)
0.5342315736445034
# 2D
A = rand(8,20)
knots = ([x^2 for x = 1:8], [0.2y for y = 1:20])
itp = interpolate(knots, A, Gridded(Linear()))
itp(4,1.2) # approximately A[2,6]
0.6334118989442268
# we can mix modes across dimensions!
itp = interpolate(knots, A, (Gridded(Linear()),Gridded(Constant())))
itp(4,1.2)
0.633411898944227
using StaticArrays
x = range(1,stop = 3, length = 200) # cash on hand
a = Float64[log(1+j)*i for j in x, i in 1:2] # cons and save function
b = reinterpret(SVector{2,Float64}, a')[:]
itp = interpolate(b, Interpolations.BSpline(Quadratic(Reflect(OnCell()))))
@show itp(3)
sitp = scale(itp,x)
@show sitp(3);
itp(3) = [0.703147, 1.40629] sitp(3) = [1.38629, 2.77259]
v = sitp(1.75) # get interpolated values for both function
plot(x,a,labels=["save","cons"],yticks=convert(Array{Float64},v),xlabel="current cash")
vline!([1.75],lab="")
hline!([v[1],v[2]],lab="")
\Phi =& \Phi_D \otimes \Phi_{D-1} \otimes \dots \otimes \Phi_{1} \end{aligned} $$
using ApproXD
gr()
bs = ApproXD.BSpline(7,3,0,1) #7 knots, degree 3 in [0,1]
n = 500
eval_points = collect(range(0,stop = 1.0,length = n))
B = Array(ApproXD.getBasis(eval_points,bs))
ys = [string("Basis",i) for i = size(B)[2]-1:-1:0]
xs = reverse(eval_points)
heatmap(xs,ys,reverse(B',dims=1))
heatmap(xs,ys,reverse(B',dims=1) .> 0, cbar = false)
B
by typing B
and typeof(B)
ApproXD.jl
for example viafunction evalTensor2{T}(mat1::SparseMatrixCSC{T,Int64},
mat2::SparseMatrixCSC{T,Int64},
c::Vector{T})
This proceeds as in the previouses cases:
BasisMatrices
¶BasisMatrices
provides general support for all kinds of basis matrices.Cheb
for chebyshev basis matrixSpline
for splineLin
for linearParams
for each type: bounds, grid points, degrees, etcbasis
nodes(basis)
BasisMatrix(basis)
using BasisMatrices
grid1 = range(1,stop = 3,length = 10)
lp = LinParams(grid1)
sp = SplineParams(collect(grid1),0,3) # nodes, whether only 2 nodes, degree of spline
sm = SmolyakParams(2,1,[3],[2]) # dims,mu,lower bound(s), upper bound(s)
sm2 = SmolyakParams(2,[1,2],[0,-0.5],[3,4.4]) # dims,mu,lower bound(s), upper bound(s)
sm3 = SmolyakParams(3,[1,2,2],[0,-0.5,1],[3,4.4,5]) # dims,mu,lower bound(s), upper bound(s)
Smolyak interpolation parameters in 3 dimensions from [0.0, -0.5, 1.0] × [3.0, 4.4, 5.0]
# simple interpolation
fi(x) = x.^2 - 0.5*x.^3
sp = SplineParams(collect(grid1),0,3) # nodes, whether only 2 nodes, degree of spline
sb = Basis(sp)
s,n = BasisMatrices.nodes(sb)
sv =fi(s)
coef, bs_direct = funfitxy(sb, s, sv) # compute coefficients
plot(fi,1,3,label="truth")
newx = 1 .+ rand(10)*2
newy = funeval(coef,sb,newx) # evaluate basis at new points
scatter!(newx,newy,label="approx")
# multiple dimensions
basis = Basis(SplineParams(25, -1, 1, 2),SplineParams(20, -1, 2, 1)) # quadratic and linear spline
# get nodes
X, x12 = BasisMatrices.nodes(basis)
# function to interpolate
f2(x1, x2) = cos.(x2) ./ exp.(x1)
f2(X::Matrix) = f2.(X[:, 1], X[:, 2])
# f at nodes
y = f2(X)
Ymat = [f2(i,j) for i in x12[1], j in x12[2]]
coefs, bbs = funfitxy(basis, X, y)
ynew = funeval(coefs, basis, X[5:5, :])[1]
using Test
@test maximum(abs, ynew - y[5]) <= 1e-12
# plotlyjs()
surface(x12[1],x12[2],Ymat',alpha=0.7,cbar=false)
xnew=hcat(-1 .+ rand(10)*2 , -1 .+ rand(10)*3)
ynew = [funeval(coefs, basis, xnew[i,:]) for i in 1:size(xnew,1)]
scatter!(xnew[:,1],xnew[:,2],ynew,markersize=2,markershape=:rect)
# same with the smolyak grid
# multiple dimensions
using LinearAlgebra
sp = SmolyakParams(2,3, [-1,-1],[1,2])
basis = Basis(sp)
# get nodes
X, x12 = BasisMatrices.nodes(basis)
# # f at nodes
y = f2(X)
Ymat = [f2(i,j) for i in unique(X[:,1]), j in unique(X[:,2])]
# map domain into unit hypercube
cube = BasisMatrices.dom2cube(X, basis.params[1])
# evaluate basis matrix
eb = BasisMatrices.build_B(sp.d, sp.mu, cube, sp.pinds)
coef = pinv(eb) * y
xnew = hcat(-1 .+ rand(30)*2 , -1 .+ rand(30)*3)
cube = BasisMatrices.dom2cube(xnew, sp)
eb = BasisMatrices.build_B(sp.d, sp.mu, cube, sp.pinds)
ynew = eb * coef
scatter(X[:,1],X[:,2],y,markersize=2)
scatter!(xnew[:,1],xnew[:,2],ynew,markersize=2,markershape=:rect)
using Tasmanian
Tasmanian.ex2()
┌ Info: error on initial grid: 0.06798, with 13 points └ @ Tasmanian /Users/florian.oswald/.julia/dev/Tasmanian/examples/examples.jl:88 ┌ Info: refinement level 1 error: 0.02096, with 16 points └ @ Tasmanian /Users/florian.oswald/.julia/dev/Tasmanian/examples/examples.jl:102 ┌ Info: refinement level 2 error: 0.00896, with 36 points └ @ Tasmanian /Users/florian.oswald/.julia/dev/Tasmanian/examples/examples.jl:102 ┌ Info: refinement level 3 error: 0.00314, with 80 points └ @ Tasmanian /Users/florian.oswald/.julia/dev/Tasmanian/examples/examples.jl:102 ┌ Info: refinement level 4 error: 0.00097, with 176 points └ @ Tasmanian /Users/florian.oswald/.julia/dev/Tasmanian/examples/examples.jl:102 ┌ Info: refinement level 5 error: 0.00031, with 384 points └ @ Tasmanian /Users/florian.oswald/.julia/dev/Tasmanian/examples/examples.jl:102 ┌ Info: refinement level 6 error: 9.0e-5, with 824 points └ @ Tasmanian /Users/florian.oswald/.julia/dev/Tasmanian/examples/examples.jl:102 ┌ Info: refinement level 7 error: 2.0e-5, with 1688 points └ @ Tasmanian /Users/florian.oswald/.julia/dev/Tasmanian/examples/examples.jl:102
0