Skip to content

Commit 8af5b23

Browse files
authored
Merge pull request #38 from EconForge/albop/code_generation
Albop/code generation
2 parents f4e89d6 + 0dac817 commit 8af5b23

29 files changed

+2821
-2971
lines changed

README.md

Lines changed: 139 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,56 +2,119 @@
22

33
[![Build Status](https://travis-ci.org/EconForge/interpolation.py.svg?branch=master)](https://travis-ci.org/EconForge/interpolation.py)
44

5-
This library provides fast numba-accelerated interpolation routines
6-
for the following cases:
5+
The library contains:
6+
- splines.*: fast numba-compatible multilinear and cubic interpolation
7+
- multilinear.*: fast numba-compatible multilinear interpolation (alternative implementation)
8+
- smolyak.*: smolyak polinomials
9+
- complete polynomials
710

8-
## multilinear and cubic splines in any dimension
11+
## multilinear and cubic interpolation
12+
13+
Fast numba-accelerated interpolation routines
14+
for multilinear and cubic interpolation, with any number of dimensions.
15+
Several interfaces are provided.
16+
17+
### eval_linear
18+
19+
Preferred interface for multilinear interpolation. It can interpolate on uniform
20+
and nonuniform cartesian grids. Several extrapolation options are available.
921

10-
Here is an example in 3 dimensions:
1122

1223
```python
13-
from interpolation.splines import LinearSpline, CubicSpline
14-
a = np.array([0.0,0.0,0.0]) # lower boundaries
15-
b = np.array([1.0,1.0,1.0]) # upper boundaries
16-
orders = np.array([50,50,50]) # 50 points along each dimension
17-
values = np.random.random(orders) # values at each node of the grid
18-
S = np.random.random((10**6,3)) # coordinates at which to evaluate the splines
24+
import numpy as np
1925

20-
# multilinear
21-
lin = LinearSpline(a,b,orders,values)
22-
V = lin(S)
23-
# cubic
24-
spline = CubicSpline(a,b,orders,values) # filter the coefficients
25-
V = spline(S) # interpolates -> (100000,) array
26+
from interpolation.splines import UCGrid, CGrid, nodes
2627

27-
```
28+
# we interpolate function
29+
f = lambda x,y: np.sin(np.sqrt(x**2+y**2+0.00001))/np.sqrt(x**2+y**2+0.00001)
2830

29-
Unfair timings: (from `misc/speed_comparison.py`)
30-
```
31-
# interpolate 10^6 points on a 50x50x50 grid.
32-
Cubic: 0.11488723754882812
33-
Linear: 0.03426337242126465
34-
Scipy (linear): 0.6502540111541748
35-
```
31+
# uniform cartesian grid
32+
grid = UCGrid((-1.0, 1.0, 10), (-1.0, 1.0, 10))
3633

37-
More details are available as an example [notebook](https://github.com/EconForge/interpolation.py/blob/master/examples/cubic_splines_python.ipynb)
34+
# get grid points
35+
gp = nodes(grid) # 100x2 matrix
3836

39-
Other available features are:
40-
- linear extrapolation
41-
- computation of derivatives
42-
- interpolate many functions at once (multi-splines or vector valued splines)
37+
# compute values on grid points
38+
values = f(gp[:,0], gp[:,1]).reshape((10,10))
4339

44-
Experimental
45-
- evaluation on the GPU (with numba.cuda)
46-
- parallel evaluation (with guvectorize)
40+
from interpolation.splines import eval_linear
41+
# interpolate at one point
42+
point = np.array([0.1,0.45]) # 1d array
43+
val = eval_linear(grid, values, point) # float
4744

48-
In the near future:
49-
- JIT classes for all interpolation objects
45+
# interpolate at many points:
46+
points = np.random.random((10000,2))
47+
eval_linear(grid, values, points) # 10000 vector
5048

49+
# output can be preallocated
50+
out = np.zeros(10000)
51+
eval_linear(grid, values, points, out) # 10000 vector
5152

5253
## jitted, non-uniform multilinear interpolation
5354

54-
There is a simple `interp` function with a flexible API which does multinear on uniform or non uniform cartesian grids.
55+
# default calls extrapolate data by using the nearest value inside the grid
56+
# other extrapolation options can be chosen among NEAREST, LINEAR, CONSTANT
57+
58+
from interpolation.splines import extrap_options as xto
59+
points = np.random.random((100,2))*3-1
60+
eval_linear(grid, values, points, xto.NEAREST) # 100
61+
eval_linear(grid, values, points, xto.LINEAR) # 10000 vector
62+
eval_linear(grid, values, points, xto.CONSTANT) # 10000 vector
63+
64+
65+
# one can also approximate on nonuniform cartesian grids
66+
67+
grid = CGrid(np.linspace(-1,1,100)**3, (-1.0, 1.0, 10))
68+
69+
points = np.random.random((10000,2))
70+
eval_linear(grid, values, points) # 10000 vector
71+
72+
73+
# it is also possible to interpolate vector-valued functions in the following way
74+
75+
f = lambda x,y: np.sin(x**3+y**2+0.00001)/np.sqrt(x**2+y**2+0.00001)
76+
g = lambda x,y: np.sin(x**3+y**2+0.00001)/np.sqrt(x**2+y**2+0.00001)
77+
grid = UCGrid((-1.0, 1.0, 10), (-1.0, 1.0, 10))
78+
gp = nodes(grid) # 100x2 matrix
79+
mvalues = np.concatenate([
80+
f(gp[:,0], gp[:,1]).reshape((10,10))[:,:,None],
81+
g(gp[:,0], gp[:,1]).reshape((10,10))[:,:,None]
82+
],axis=2) # 10x10x2 array
83+
points = np.random.random((1000,2))
84+
eval_linear(grid, mvalues, points[:,1]) # 2 elements vector
85+
eval_linear(grid, mvalues, points) # 1000x2 matrix
86+
out = np.zeros((1000,2))
87+
eval_linear(grid, mvalues, points, out) # 1000x2 matrix
88+
89+
90+
91+
# finally, the same syntax can be used to interpolate using cubic splines
92+
# one just needs to prefilter the coefficients first
93+
# the same set of options apply but nonuniform grids are not supported (yet)
94+
95+
f = lambda x,y: np.sin(x**3+y**2+0.00001)/np.sqrt(x**2+y**2+0.00001)
96+
grid = UCGrid((-1.0, 1.0, 10), (-1.0, 1.0, 10))
97+
gp = nodes(grid) # 100x2 matrix
98+
values = f(gp[:,0], gp[:,1]).reshape((10,10))
99+
100+
# filter values
101+
from interpolation.splines import filter_cubic
102+
coeffs = filter_cubic(grid, values) # a 12x12 array
103+
104+
from interpolation.splines import eval_cubic
105+
points = np.random.random((1000,2))
106+
eval_cubic(grid, coeffs, points[:,1]) # 2 elements vector
107+
eval_cubic(grid, coeffs, points) # 1000x2 matrix
108+
out = np.zeros((1000,2))
109+
eval_cubic(grid, coeffs, points, out) # 1000x2 matrix
110+
111+
```
112+
113+
114+
### interp
115+
116+
Simpler interface. Mimmicks default `scipy.interp`: mutlilinear interpolation with constant extrapolation.
117+
55118

56119
```
57120
### 1d grid
@@ -66,10 +129,51 @@ interp(x,y,0.5)
66129
# or at many points:
67130
u = np.linspace(0,1,1000) # points
68131
interp(x,y,u)
132+
133+
```
134+
135+
136+
### object interface
137+
138+
This is for compatibility purpose only, until a new jittable model object is found.
139+
140+
```python
141+
from interpolation.splines import LinearSpline, CubicSpline
142+
a = np.array([0.0,0.0,0.0]) # lower boundaries
143+
b = np.array([1.0,1.0,1.0]) # upper boundaries
144+
orders = np.array([50,50,50]) # 50 points along each dimension
145+
values = np.random.random(orders) # values at each node of the grid
146+
S = np.random.random((10**6,3)) # coordinates at which to evaluate the splines
147+
148+
# multilinear
149+
lin = LinearSpline(a,b,orders,values)
150+
V = lin(S)
151+
# cubic
152+
spline = CubicSpline(a,b,orders,values) # filter the coefficients
153+
V = spline(S) # interpolates -> (100000,) array
154+
69155
```
70156

157+
### development notes
71158

159+
Old, unfair timings: (from `misc/speed_comparison.py`)
72160

161+
```
162+
# interpolate 10^6 points on a 50x50x50 grid.
163+
Cubic: 0.11488723754882812
164+
Linear: 0.03426337242126465
165+
Scipy (linear): 0.6502540111541748
166+
```
167+
168+
More details are available as an example [notebook](https://github.com/EconForge/interpolation.py/blob/master/examples/cubic_splines_python.ipynb) (outdated)
169+
170+
Missing but available soon:
171+
- splines at any order
172+
- derivative
173+
174+
Feasible (some experiments)
175+
- evaluation on the GPU (with numba.cuda)
176+
- parallel evaluation (with guvectorize)
73177

74178

75179

interpolation/multilinear/fungen.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,8 @@ def gen_tensor_reduction(X, symbs, inds=[]):
185185

186186
@generated_jit(nopython=True)
187187
def tensor_reduction(C,l):
188-
ex = gen_tensor_reduction('C', ['l[{}]'.format(i) for i in range(len(l.types))])
188+
d = len(l.types)
189+
ex = gen_tensor_reduction('C', ['l[{}]'.format(i) for i in range(d)])
189190
dd = dict()
190191
s = "def tensor_reduction(C,l): return {}".format(ex)
191192
eval(compile(ast.parse(s),'<string>','exec'), dd)

interpolation/splines/__init__.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,14 @@
11
from .splines import CubicSpline, CubicSplines
22
from .multilinear import LinearSpline, LinearSplines
3+
from .eval_splines import options, eval_linear, eval_cubic
4+
from .prefilter_cubic import filter_cubic
5+
from .option_types import options as extrap_options
6+
7+
# dummy functions
8+
def UCGrid(*args):
9+
return tuple(args)
10+
def CGrid(*args):
11+
return tuple(args)
12+
def nodes(grid):
13+
from interpolation.cartesian import mlinspace
14+
return mlinspace([g[0] for g in grid],[g[1] for g in grid],[g[2] for g in grid])

interpolation/splines/basis_splines.py

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,30 +14,30 @@ def B(p, u, i, x):
1414
else:
1515
return (((x - u[i]) / (u[i + p] - u[i])) * B(p - 1, u, i, x) + ((u[i + p + 1] - x) / (u[i + p + 1] - u[i + 1])) * B(p - 1, u, i + 1, x))
1616

17-
18-
from pylab import *
19-
20-
xvec = linspace(-5, 5, 11)
21-
22-
tvec = linspace(-5, 5, 1000)
23-
24-
yvec = array([B0(xvec, 5, x) for x in tvec])
25-
y2vec = array([B(2, xvec, 5, x) for x in tvec])
26-
y3vec = array([B(3, xvec, 5, x) for x in tvec])
27-
28-
29-
print(B(3, xvec, 5, 0))
30-
print(B(3, xvec, 5, 1))
31-
print(B(3, xvec, 5, 2))
32-
print(B(3, xvec, 5, 3))
33-
print(B(3, xvec, 5, 4))
34-
35-
36-
plot(xvec, xvec * 0, 'o-')
37-
38-
plot(tvec, yvec)
39-
plot(tvec, y2vec)
40-
plot(tvec, y3vec)
41-
42-
43-
show()
17+
#
18+
# from pylab import *
19+
#
20+
# xvec = linspace(-5, 5, 11)
21+
#
22+
# tvec = linspace(-5, 5, 1000)
23+
#
24+
# yvec = array([B0(xvec, 5, x) for x in tvec])
25+
# y2vec = array([B(2, xvec, 5, x) for x in tvec])
26+
# y3vec = array([B(3, xvec, 5, x) for x in tvec])
27+
#
28+
#
29+
# print(B(3, xvec, 5, 0))
30+
# print(B(3, xvec, 5, 1))
31+
# print(B(3, xvec, 5, 2))
32+
# print(B(3, xvec, 5, 3))
33+
# print(B(3, xvec, 5, 4))
34+
#
35+
#
36+
# plot(xvec, xvec * 0, 'o-')
37+
#
38+
# plot(tvec, yvec)
39+
# plot(tvec, y2vec)
40+
# plot(tvec, y3vec)
41+
#
42+
#
43+
# show()

0 commit comments

Comments
 (0)