Source code for k1lib._higher

# AUTOGENERATED FILE! PLEASE DON'T EDIT
"""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
Func = Callable[[float], float]
[docs]def polyfit(x:List[float], y:List[float], deg:int=6) -> Func: """Returns a function that approximate :math:`f(x) = y`. :param deg: degree of the polynomial of the returned function """ params = np.polyfit(x, y, deg) def _inner(_x): answer = np.zeros_like(_x, dtype=np.float) for expo, param in enumerate(params): answer += param * _x**(len(params)-expo-1) return answer return _inner
[docs]def derivative(f:Func, delta:float=1e-6) -> Func: """Returns the derivative of a function. Example:: f = lambda x: x**2 df = k1lib.derivative(f) df(3) # returns roughly 6 """ return lambda x: (f(x + delta) - f(x)) / delta
[docs]def optimize(f:Func, v:float=1, threshold:float=1e-6, **kwargs) -> float: 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`. """ if len(kwargs) > 0: f = partial(f, **kwargs) fD = derivative(f) for i in range(20): v = v - f(v)/fD(v) if abs(f(v)) > threshold: warnings.warn("k1lib.optimize not converging") return v
[docs]def inverse(f:Func) -> Func: """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.""" return lambda y: optimize(lambda x: f(x) - y)
[docs]def integral(f:Func, _range:k1lib.Range) -> float: """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.""" _range = k1lib.Range(_range) n = 1000; xs = np.linspace(*_range, n) return sum([f(x)*_range.delta/n for x in xs])