# AUTOGENERATED FILE! PLEASE DON'T EDIT HERE. EDIT THE SOURCE NOTEBOOKS INSTEAD
"""Higher order functions"""
__all__ = ["Func", "polyfit", "derivative", "optimize", "inverse", "integral"]
from typing import Callable, List
import k1lib, numpy as np, warnings
from functools import partial
import matplotlib.pyplot as plt
Func = Callable[[float], float]
[docs]def polyfit(x:List[float], y:List[float], deg:int=6) -> Func: # polyfit
"""Returns a function that approximate :math:`f(x) = y`.
Example::
xs = [1, 2, 3]
ys = [2, 3, 5]
f = k1.polyfit(xs, ys, 1)
This will create a best-fit function. You can just use it as a regular,
normal function. You can even pass in :class:`numpy.ndarray`::
# returns some float
f(2)
# plots fit function from 0 to 5
xs = np.linspace(0, 5)
plt.plot(xs, f(xs))
:param deg: degree of the polynomial of the returned function""" # polyfit
params = np.polyfit(x, y, deg) # polyfit
def _inner(_x): # polyfit
answer = np.zeros_like(_x, dtype=float) # polyfit
for expo, param in enumerate(params): # polyfit
answer += param * _x**(len(params)-expo-1) # polyfit
return answer # polyfit
return _inner # polyfit
[docs]def derivative(f:Func, delta:float=1e-6) -> Func: # derivative
"""Returns the derivative of a function.
Example::
f = lambda x: x**2
df = k1lib.derivative(f)
df(3) # returns roughly 6 """ # derivative
return lambda x: (f(x + delta) - f(x)) / delta # derivative
[docs]def optimize(f:Func, v:float=1, threshold:float=1e-6, **kwargs) -> float: # optimize
r"""Given :math:`f(x) = 0`, solves for x using Newton's method with initial value
`v`. Example::
f = lambda x: x**2-2
# returns 1.4142 (root 2)
k1lib.optimize(f)
# returns -1.4142 (negative root 2)
k1lib.optimize(f, -1)
Interestingly, for some reason, result of this is more accurate than :meth:`derivative`.
""" # optimize
if len(kwargs) > 0: f = partial(f, **kwargs) # optimize
fD = derivative(f) # optimize
for i in range(20): # optimize
v = v - f(v)/fD(v) # optimize
if abs(f(v)) > threshold: warnings.warn("k1lib.optimize not converging") # optimize
return v # optimize
[docs]def inverse(f:Func) -> Func: # inverse
"""Returns the inverse of a function.
Example::
f = lambda x: x**2
fInv = k1lib.inverse(f)
# returns roughly 3
fInv(9)
.. warning::
The inverse function takes a long time to run, so don't use this
where you need lots of speed. Also, as you might imagine, the
inverse function isn't really airtight. Should work well with
monotonic functions, but all bets are off with other functions.""" # inverse
return lambda y: optimize(lambda x: f(x) - y) # inverse
[docs]def integral(f:Func, _range:k1lib.Range) -> float: # integral
"""Integrates a function over a range.
Example::
f = lambda x: x**2
# returns roughly 9
k1lib.integral(f, [0, 3])
There is also the cli :class:`~k1lib.cli.modifier.integrate`
which has a slightly different api.""" # integral
_range = k1lib.Range(_range) # integral
n = 1000; xs = np.linspace(*_range, n) # integral
return sum([f(x)*_range.delta/n for x in xs]) # integral