Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add docstring #19

Merged
merged 6 commits into from
Jul 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 93 additions & 16 deletions src/xspline/bspl.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,24 @@


def cache_bspl(function: RawFunction) -> RawFunction:
"""Cache implementation for bspline basis functions, to avoid repetitively
evaluate functions.

Parameters
----------
function
Raw value, derivative and definite integral functions.

Returns
-------
describe
Cached version of the raw functions.

"""
cache = {}

def wrapper_function(*args, **kwargs) -> NDArray:
key = tuple(
tuple(x.ravel()) if isinstance(x, np.ndarray) else x for x in args
)
key = tuple(tuple(x.ravel()) if isinstance(x, np.ndarray) else x for x in args)
if key in cache:
return cache[key]
result = function(*args, **kwargs)
Expand All @@ -28,6 +40,22 @@ def cache_clear():

@cache_bspl
def bspl_val(params: BsplParams, x: NDArray) -> NDArray:
"""Value of the bspline function.

Parameters
----------
params
Bspline function parameters as a tuple including, knots, degree and the
index of the spline basis.
x
Data points.

Returns
-------
describe
Function value of the bspline function.

"""
# knots, degree, and index
t, k, i = params

Expand All @@ -44,10 +72,10 @@ def bspl_val(params: BsplParams, x: NDArray) -> NDArray:

if t[ii[0]] != t[ii[2]]:
n0 = bspl_val((t, k - 1, i), x)
val0 = (x - t[ii[0]])*n0/(t[ii[2]] - t[ii[0]])
val0 = (x - t[ii[0]]) * n0 / (t[ii[2]] - t[ii[0]])
if t[ii[1]] != t[ii[3]]:
n1 = bspl_val((t, k - 1, i + 1), x)
val1 = (t[ii[3]] - x)*n1/(t[ii[3]] - t[ii[1]])
val1 = (t[ii[3]] - x) * n1 / (t[ii[3]] - t[ii[1]])

val = val0 + val1

Expand All @@ -56,6 +84,22 @@ def bspl_val(params: BsplParams, x: NDArray) -> NDArray:

@cache_bspl
def bspl_der(params: BsplParams, x: NDArray, order: int) -> NDArray:
"""Derivative of the bspline function.

Parameters
----------
params
Bspline function parameters as a tuple including, knots, degree and the
index of the spline basis.
x
Data points.

Returns
-------
describe
Derivative of the bspline function.

"""
# knots, degree, and index
t, k, i = params

Expand All @@ -72,10 +116,10 @@ def bspl_der(params: BsplParams, x: NDArray, order: int) -> NDArray:

if t[ii[0]] != t[ii[2]]:
n0 = bspl_der((t, k - 1, i), x, order - 1)
val0 = k*n0/(t[ii[2]] - t[ii[0]])
val0 = k * n0 / (t[ii[2]] - t[ii[0]])
if t[ii[1]] != t[ii[3]]:
n1 = bspl_der((t, k - 1, i + 1), x, order - 1)
val1 = k*n1/(t[ii[3]] - t[ii[1]])
val1 = k * n1 / (t[ii[3]] - t[ii[1]])

val = val0 - val1

Expand All @@ -84,6 +128,22 @@ def bspl_der(params: BsplParams, x: NDArray, order: int) -> NDArray:

@cache_bspl
def bspl_int(params: BsplParams, x: NDArray, order: int) -> NDArray:
"""Definite integral of the bspline function.

Parameters
----------
params
Bspline function parameters as a tuple including, knots, degree and the
index of the spline basis.
x
Data points.

Returns
-------
describe
Definite integral of the bspline function.

"""
# knots, degree, and index
t, k, i = params

Expand All @@ -101,21 +161,25 @@ def bspl_int(params: BsplParams, x: NDArray, order: int) -> NDArray:

if t[ii[0]] != t[ii[2]]:
val0 = (
(x - t[ii[0]])*bspl_int((t, k - 1, i), x, order) +
order*bspl_int((t, k - 1, i), x, order - 1)
)/(t[ii[2]] - t[ii[0]])
(x - t[ii[0]]) * bspl_int((t, k - 1, i), x, order)
+ order * bspl_int((t, k - 1, i), x, order - 1)
) / (t[ii[2]] - t[ii[0]])
if t[ii[1]] != t[ii[3]]:
val1 = (
(t[ii[3]] - x)*bspl_int((t, k - 1, i + 1), x, order) -
order*bspl_int((t, k - 1, i + 1), x, order - 1)
)/(t[ii[3]] - t[ii[1]])
(t[ii[3]] - x) * bspl_int((t, k - 1, i + 1), x, order)
- order * bspl_int((t, k - 1, i + 1), x, order - 1)
) / (t[ii[3]] - t[ii[1]])

val = val0 + val1

return val


def clear_bspl_cache() -> None:
"""Clear all cache of the value, derivative and definite integral for
bspline function.

"""
bspl_val.cache_clear()
bspl_der.cache_clear()
bspl_int.cache_clear()
Expand Down Expand Up @@ -149,6 +213,19 @@ def __init__(self, params: BsplParams) -> None:


def get_bspl_funs(knots: tuple[float, ...], degree: int) -> tuple[Bspl]:
return tuple(
Bspl((knots, degree, i)) for i in range(-degree, len(knots) - 1)
)
"""Create the bspline basis functions give knots and degree.

Parameters
----------
knots
Bspline knots.
degree
Bspline degree.

Returns
-------
describe
A full set of bspline functions.

"""
return tuple(Bspl((knots, degree, i)) for i in range(-degree, len(knots) - 1))
60 changes: 54 additions & 6 deletions src/xspline/indi.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,28 @@
from math import factorial

import numpy as np
from numpy.typing import NDArray

from xspline.typing import IndiParams
from xspline.typing import IndiParams, NDArray
from xspline.xfunction import BundleXFunction


def indi_val(params: IndiParams, x: NDArray) -> NDArray:
"""Indicator value function,

Parameters
----------
params
Indicator parameters as a tuple consists of lower and upper bound of
the interval corresponding to the indicator function.
x
Data points.

Returns
-------
describe
Indicator function value.

"""
# lower and upper bounds
lb, ub = params

Expand All @@ -22,21 +37,54 @@ def indi_val(params: IndiParams, x: NDArray) -> NDArray:


def indi_der(params: IndiParams, x: NDArray, order: int) -> NDArray:
"""Indicator derivative function. Since indicator function is a piecewise
constant function, its derivative will always be zero.

Parameters
----------
params
Indicator parameters as a tuple consists of lower and upper bound of
the interval corresponding to the indicator function.
x
Data points.

Returns
-------
describe
Indicator deviative value.

"""
return np.zeros(x.size, dtype=x.dtype)


def indi_int(params: IndiParams, x: NDArray, order: int) -> NDArray:
"""Indicator definite integral function. It is a piecewise polynomial
function.

Parameters
----------
params
Indicator parameters as a tuple consists of lower and upper bound of
the interval corresponding to the indicator function.
x
Data points.

Returns
-------
describe
Indicator definite integral value.

"""
# lower and upper bounds
lb, ub = params

val = np.zeros(x.size, dtype=x.dtype)
ind0 = (x >= lb[0]) & (x <= ub[0])
ind1 = x > ub[0]
val[ind0] = (x[ind0] - lb[0])**(-order)/factorial(-order)
val[ind0] = (x[ind0] - lb[0]) ** (-order) / factorial(-order)
for i in range(-order):
val[ind1] += (
((ub[0] - lb[0])**(-order - i)/factorial(-order - i)) *
((x[ind1] - ub[0])**i/factorial(i))
val[ind1] += ((ub[0] - lb[0]) ** (-order - i) / factorial(-order - i)) * (
(x[ind1] - ub[0]) ** i / factorial(i)
)
return val

Expand Down
89 changes: 86 additions & 3 deletions src/xspline/poly.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,70 @@
from math import factorial

import numpy as np
from numpy.typing import NDArray

from xspline.typing import PolyParams
from xspline.typing import PolyParams, NDArray
from xspline.xfunction import BundleXFunction, XFunction


def poly_val(params: PolyParams, x: NDArray) -> NDArray:
"""Polynomial value function.

Parameters
----------
params
Polynomial coefficients.
x
Data points.

Returns
-------
describe
Polynomial function values.

"""
return np.polyval(params, x)


def poly_der(params: PolyParams, x: NDArray, order: int) -> NDArray:
"""Polynomial derivative function.

Parameters
----------
params
Polynomial coefficients.
x
Data points.
order
Order of differentiation.

Returns
-------
describe
Polynomial derivative values.

"""
return np.polyval(np.polyder(params, order), x)


def poly_int(params: PolyParams, x: NDArray, order: int) -> NDArray:
"""Polynomial definite integral function.

Parameters
----------
params
Polynomial coefficients.
x
Data points.
order
Order of integration. Here we use negative integer.

Returns
-------
describe
Polynomial definite integral values.

"""

return np.polyval(np.polyint(params, -order), x)


Expand Down Expand Up @@ -46,16 +95,50 @@ def __init__(self, params: PolyParams) -> None:


def get_poly_params(fun: XFunction, x: float, degree: int) -> tuple[float, ...]:
"""Solve polynomial (taylor) coefficients provided the ``XFunction``.

Parameters
----------
fun
Provided ``XFunction`` to be approximated.
x
The point where we want to approximate ``XFunction`` by the polynomial.
degree
Degree of the approximation polynomial.

Returns
-------
describe
The approximation polynomial coefficients.

"""
if degree < 0:
return (0.0,)
rhs = np.array([fun(x, order=i) for i in range(degree, -1, -1)])
mat = np.zeros((degree + 1, degree + 1))
for i in range(degree + 1):
for j in range(i + 1):
mat[i, j] = factorial(degree - j) / factorial(i - j) * x**(i - j)
mat[i, j] = factorial(degree - j) / factorial(i - j) * x ** (i - j)
return tuple(np.linalg.solve(mat, rhs))


def get_poly_fun(fun: XFunction, x: float, degree: int) -> Poly:
"""Get the approximation polynomial function.

Parameters
----------
fun
Provided ``XFunction`` to be approximated.
x
The point where we want to approximate ``XFunction`` by the polynomial.
degree
Degree of the approximation polynomial.

Returns
-------
describe
Instance of the ``Poly`` class to approximate provided ``XFunction``.

"""
params = get_poly_params(fun, x, degree)
return Poly(params)
Loading
Loading