-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathtaylor_approximation.py
More file actions
102 lines (73 loc) · 3.42 KB
/
taylor_approximation.py
File metadata and controls
102 lines (73 loc) · 3.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
import numpy as np
import itertools
from findiff import FinDiff
from scipy.special import factorial
def taylor_approximate(pars, x0s, derivs, order=None):
'''
Computes the nth order Taylor series approximation to a function given
- derivs: a list of n derivatives
- x0s: the point about which we are expanding
- pars: the coordinates at which we want to expand the function
If order is specified it will go to that order instead of using the full list of derivatives.
'''
Nparams = len(x0s)
output_shape = derivs[0].shape
if order is None:
order = len(derivs) - 1
print("Taking the order %d Taylor series."%(order))
Fapprox = np.zeros(output_shape)
diffs = [ (pars[ii] - x0s[ii]) for ii in range(Nparams) ]
for oo in range(order+1):
if oo == 0:
Fapprox += derivs[oo]
else:
param_inds = np.meshgrid( * (np.arange(Nparams),)*oo, indexing='ij')
PInds = [ind.flatten() for ind in param_inds]
term = 0
for iis in zip(*PInds):
term += derivs[oo][iis] * np.prod([ diffs[ii] for ii in iis ])
Fapprox += 1/factorial(oo) * term
return Fapprox
def compute_derivatives(Fs, dxs, center_ii, order):
'''
Computes all the partial derivatives up to order 'order' given a function on a grid Fs
The grid separation is given by dxs, and the derivatives are computed at the grid point 'center_ii.'
Assumes that Fs is gridded in the standard matrix way (i.e. indexing = 'ij' in numpy) as
opposed to Cartesian indexing that one uses for plotting.
'''
# assume the structure of the input is
# [Npoints,]*Nparams + output_shape, where Nparams is also the length of dxs
Nparams = len(dxs)
output_shape = Fs.shape[len(dxs):]
derivs = []
for oo in range(order+1):
if oo == 0:
derivs += [Fs[center_ii]]
else:
dnFs = np.zeros( (Nparams,)*oo + output_shape)
# Want to get a list of all the possible d/dx_i dx_j dx_k ...
param_inds = np.meshgrid( * (np.arange(Nparams),)*oo, indexing='ij')
PInds = [ind.flatten() for ind in param_inds]
# First list the indices that are unique
# We want to only compute
# d/dx_i dx_j ... for i <= j <= k ...
# Otherwise we will copy the results
unique_inds = []
for iis in zip(*PInds):
if (np.diff(iis) >= 0).all():
unique_inds += [iis]
for nn, iis in enumerate(unique_inds):
# Want to compute derivatives but in parallel
# build a string of (xk, dxk, 1) for taking the d/dxk derivative in sequence
deriv_tuple = []
for ii in iis:
deriv_tuple += [(ii, dxs[ii],1),]
dndx = FinDiff(*deriv_tuple)
deriv = dndx(Fs)[center_ii]
# Fill in all permutations of iis
# use "set" here to identify unique permutations
for jj in set(itertools.permutations(iis)):
dnFs[jj] += deriv
del(deriv)
derivs += [dnFs]
return derivs