backyard/library/finite_difference.py

69 lines
1.6 KiB
Python

#!/usr/bin/env python3
# implementing: https://web.media.mit.edu/~crtaylor/calculator.html
import numpy as np
# from math import factorial
_factorials = ( # all the factorials that fit into 53 bits
1,
1,
2,
6,
24,
120,
720,
5040,
40320,
362880,
3628800,
39916800,
479001600,
6227020800,
87178291200,
1307674368000,
20922789888000,
355687428096000,
6402373705728000,
)
__noisy = False
def fd(offsets, degree):
if degree < 0:
raise RuntimeError("the degree must be greater than or equal to zero")
elif degree > 18:
raise RuntimeError("degrees greater than 18 are unsupported")
if len(offsets) <= degree:
raise RuntimeError("the number of offsets must be greater than the degree")
mat = np.array([[o**n for o in offsets] for n in range(len(offsets))])
vec = np.array([_factorials[i] if i == degree else 0 for i in range(len(offsets))])
if __noisy:
print("mat:", mat, "vec:", vec, sep="\n")
res = np.linalg.lstsq(mat, vec, rcond=None)[0]
return res
if __name__ == "__main__":
__noisy = True
assert np.allclose(fd([-2, 0, 2], 1), [-1 / 4, 0, 1 / 4])
# + A * f(x - 2 * h)
# + B * f(x - 1 * h)
# + C * f(x)
# + D * f(x + 1 * h)
# + E * f(x + 2 * h)
assert np.allclose(fd([-2, -1, 0, 1, 2], 4), [1, -4, 6, -4, 1])
print("", "#" * 40, "", sep="\n")
ans = fd([-2, 7], 1)
print("ans:", ans)
ans = fd([-2, 0, 7], 1)
print("ans:", ans)
ans = fd([-0.2, 0.0, 0.7], 1)
print("ans:", ans)
__all__ = ("fd",)