derivkit 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- derivkit/__init__.py +22 -0
- derivkit/calculus/__init__.py +17 -0
- derivkit/calculus/calculus_core.py +152 -0
- derivkit/calculus/gradient.py +97 -0
- derivkit/calculus/hessian.py +528 -0
- derivkit/calculus/hyper_hessian.py +296 -0
- derivkit/calculus/jacobian.py +156 -0
- derivkit/calculus_kit.py +128 -0
- derivkit/derivative_kit.py +315 -0
- derivkit/derivatives/__init__.py +6 -0
- derivkit/derivatives/adaptive/__init__.py +5 -0
- derivkit/derivatives/adaptive/adaptive_fit.py +238 -0
- derivkit/derivatives/adaptive/batch_eval.py +179 -0
- derivkit/derivatives/adaptive/diagnostics.py +325 -0
- derivkit/derivatives/adaptive/grid.py +333 -0
- derivkit/derivatives/adaptive/polyfit_utils.py +513 -0
- derivkit/derivatives/adaptive/spacing.py +66 -0
- derivkit/derivatives/adaptive/transforms.py +245 -0
- derivkit/derivatives/autodiff/__init__.py +1 -0
- derivkit/derivatives/autodiff/jax_autodiff.py +95 -0
- derivkit/derivatives/autodiff/jax_core.py +217 -0
- derivkit/derivatives/autodiff/jax_utils.py +146 -0
- derivkit/derivatives/finite/__init__.py +5 -0
- derivkit/derivatives/finite/batch_eval.py +91 -0
- derivkit/derivatives/finite/core.py +84 -0
- derivkit/derivatives/finite/extrapolators.py +511 -0
- derivkit/derivatives/finite/finite_difference.py +247 -0
- derivkit/derivatives/finite/stencil.py +206 -0
- derivkit/derivatives/fornberg.py +245 -0
- derivkit/derivatives/local_polynomial_derivative/__init__.py +1 -0
- derivkit/derivatives/local_polynomial_derivative/diagnostics.py +90 -0
- derivkit/derivatives/local_polynomial_derivative/fit.py +199 -0
- derivkit/derivatives/local_polynomial_derivative/local_poly_config.py +95 -0
- derivkit/derivatives/local_polynomial_derivative/local_polynomial_derivative.py +205 -0
- derivkit/derivatives/local_polynomial_derivative/sampling.py +72 -0
- derivkit/derivatives/tabulated_model/__init__.py +1 -0
- derivkit/derivatives/tabulated_model/one_d.py +247 -0
- derivkit/forecast_kit.py +783 -0
- derivkit/forecasting/__init__.py +1 -0
- derivkit/forecasting/dali.py +78 -0
- derivkit/forecasting/expansions.py +486 -0
- derivkit/forecasting/fisher.py +298 -0
- derivkit/forecasting/fisher_gaussian.py +171 -0
- derivkit/forecasting/fisher_xy.py +357 -0
- derivkit/forecasting/forecast_core.py +313 -0
- derivkit/forecasting/getdist_dali_samples.py +429 -0
- derivkit/forecasting/getdist_fisher_samples.py +235 -0
- derivkit/forecasting/laplace.py +259 -0
- derivkit/forecasting/priors_core.py +860 -0
- derivkit/forecasting/sampling_utils.py +388 -0
- derivkit/likelihood_kit.py +114 -0
- derivkit/likelihoods/__init__.py +1 -0
- derivkit/likelihoods/gaussian.py +136 -0
- derivkit/likelihoods/poisson.py +176 -0
- derivkit/utils/__init__.py +13 -0
- derivkit/utils/concurrency.py +213 -0
- derivkit/utils/extrapolation.py +254 -0
- derivkit/utils/linalg.py +513 -0
- derivkit/utils/logger.py +26 -0
- derivkit/utils/numerics.py +262 -0
- derivkit/utils/sandbox.py +74 -0
- derivkit/utils/types.py +15 -0
- derivkit/utils/validate.py +811 -0
- derivkit-1.0.0.dist-info/METADATA +50 -0
- derivkit-1.0.0.dist-info/RECORD +68 -0
- derivkit-1.0.0.dist-info/WHEEL +5 -0
- derivkit-1.0.0.dist-info/licenses/LICENSE +21 -0
- derivkit-1.0.0.dist-info/top_level.txt +1 -0
derivkit/__init__.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Provides all derivkit methods."""
|
|
2
|
+
|
|
3
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
4
|
+
|
|
5
|
+
from derivkit.calculus_kit import CalculusKit
|
|
6
|
+
from derivkit.derivative_kit import DerivativeKit
|
|
7
|
+
from derivkit.forecast_kit import ForecastKit
|
|
8
|
+
from derivkit.likelihood_kit import LikelihoodKit
|
|
9
|
+
|
|
10
|
+
try:
|
|
11
|
+
__version__ = version("derivkit")
|
|
12
|
+
except PackageNotFoundError:
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
DerivativeKit.__module__ = "derivkit.derivative_kit"
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"DerivativeKit",
|
|
19
|
+
"ForecastKit",
|
|
20
|
+
"CalculusKit",
|
|
21
|
+
"LikelihoodKit"
|
|
22
|
+
]
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""Calculus utilities.
|
|
2
|
+
|
|
3
|
+
Provides constructors for gradient, Jacobian, and Hessian computations.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from derivkit.calculus.gradient import build_gradient
|
|
7
|
+
from derivkit.calculus.hessian import build_hessian, build_hessian_diag
|
|
8
|
+
from derivkit.calculus.hyper_hessian import build_hyper_hessian
|
|
9
|
+
from derivkit.calculus.jacobian import build_jacobian
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"build_gradient",
|
|
13
|
+
"build_jacobian",
|
|
14
|
+
"build_hessian",
|
|
15
|
+
"build_hessian_diag",
|
|
16
|
+
"build_hyper_hessian",
|
|
17
|
+
]
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"""Core utilities for calculus-based derivative computations.
|
|
2
|
+
|
|
3
|
+
This module provides shared helper functions for building derivative
|
|
4
|
+
objects (gradients, Jacobians, Hessians, higher-order tensors) of scalar-
|
|
5
|
+
and tensor-valued functions using DerivativeKit.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from collections.abc import Callable
|
|
11
|
+
from functools import partial
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
import numpy as np
|
|
15
|
+
from numpy.typing import ArrayLike, NDArray
|
|
16
|
+
|
|
17
|
+
from derivkit.utils.concurrency import (
|
|
18
|
+
parallel_execute,
|
|
19
|
+
)
|
|
20
|
+
from derivkit.utils.validate import ensure_finite
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
"component_scalar_eval",
|
|
24
|
+
"dispatch_tensor_output",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def component_scalar_eval(
|
|
29
|
+
theta_vec: NDArray[np.float64],
|
|
30
|
+
*,
|
|
31
|
+
function: Callable[[ArrayLike], float | np.ndarray],
|
|
32
|
+
idx: int,
|
|
33
|
+
) -> float:
|
|
34
|
+
"""Evaluates a single element of the model output ``function(theta_vec)`` as a scalar.
|
|
35
|
+
|
|
36
|
+
This helper is used internally when building derivatives of models that
|
|
37
|
+
return multiple outputs (e.g. vectors or arrays). Derivative routines
|
|
38
|
+
operate on scalar-valued functions, so one output component is selected
|
|
39
|
+
and treated as a scalar function of the parameters.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
theta_vec: 1D parameter vector.
|
|
43
|
+
function: Original function.
|
|
44
|
+
idx: Index of the output component to differentiate, where the output is first
|
|
45
|
+
flattened with NumPy C-order (i.e. ``np.ravel(y, order="C")``).
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
Scalar value of the specified output component.
|
|
49
|
+
|
|
50
|
+
Raises:
|
|
51
|
+
IndexError: If ``idx`` is out of bounds for the model output.
|
|
52
|
+
"""
|
|
53
|
+
theta_vec = np.asarray(theta_vec, dtype=np.float64)
|
|
54
|
+
val = np.asarray(function(theta_vec))
|
|
55
|
+
|
|
56
|
+
flat = np.ravel(val, order="C")
|
|
57
|
+
i = int(idx)
|
|
58
|
+
|
|
59
|
+
if i < 0 or i >= flat.size:
|
|
60
|
+
raise IndexError(
|
|
61
|
+
f"Output index {i} out of bounds for model output of size {flat.size}."
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
return float(flat[i])
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def dispatch_tensor_output(
|
|
68
|
+
function: Callable[[ArrayLike], float | np.ndarray],
|
|
69
|
+
theta: NDArray[np.float64],
|
|
70
|
+
*,
|
|
71
|
+
method: str | None,
|
|
72
|
+
outer_workers: int,
|
|
73
|
+
inner_workers: int | None,
|
|
74
|
+
dk_kwargs: dict[str, Any],
|
|
75
|
+
build_component: Callable[
|
|
76
|
+
[
|
|
77
|
+
int, NDArray[np.float64],
|
|
78
|
+
str | None,
|
|
79
|
+
int | None,
|
|
80
|
+
dict[str, Any],
|
|
81
|
+
Callable[[ArrayLike],
|
|
82
|
+
float | np.ndarray]
|
|
83
|
+
],
|
|
84
|
+
NDArray[np.float64],
|
|
85
|
+
],
|
|
86
|
+
) -> NDArray[np.float64]:
|
|
87
|
+
"""Computes per-output-component derivative objects for tensor-valued outputs and reshapes back.
|
|
88
|
+
|
|
89
|
+
This helper is intended for functions whose output has one or more dimensions
|
|
90
|
+
(i.e. ``function(theta)`` returns an array). Scalar-valued functions should be
|
|
91
|
+
handled by the scalar derivative routines (e.g. gradient, hessian, or derivative)
|
|
92
|
+
and must not be routed through this dispatcher.
|
|
93
|
+
|
|
94
|
+
The function uses the following strategy:
|
|
95
|
+
|
|
96
|
+
1. Evaluate ``y0 = function(theta)``
|
|
97
|
+
2. Flatten tensor output into m scalar components
|
|
98
|
+
3. For each component ``idx``, compute a scalar-output derivative object
|
|
99
|
+
4. Stack and reshape to ``(*out_shape, *derivative_object_shape)``
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
function: Original function.
|
|
103
|
+
theta: 1D parameter vector.
|
|
104
|
+
method: Derivative method name or alias.
|
|
105
|
+
outer_workers: Parallelism across output components.
|
|
106
|
+
inner_workers: Parallelism forwarded to DerivativeKit inside each component calculation.
|
|
107
|
+
dk_kwargs: Keyword args forwarded to DerivativeKit.differentiate (already stripped of ``inner_workers``).
|
|
108
|
+
build_component: Per-component builder with signature:
|
|
109
|
+
(idx, theta, method, inner_workers, dk_kwargs, function) -> ndarray
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
Array with shape ``(*out_shape, *derivative_object_shape)``.
|
|
113
|
+
|
|
114
|
+
Raises:
|
|
115
|
+
FloatingPointError: If non-finite values are encountered.
|
|
116
|
+
ValueError: If ``function(theta)`` is scalar (use scalar path in caller).
|
|
117
|
+
"""
|
|
118
|
+
theta = np.asarray(theta, dtype=np.float64)
|
|
119
|
+
y0 = np.asarray(function(theta))
|
|
120
|
+
ensure_finite(y0, msg="Non-finite values in model output at theta0.")
|
|
121
|
+
|
|
122
|
+
if y0.ndim == 0:
|
|
123
|
+
raise ValueError(
|
|
124
|
+
"dispatch_tensor_output requires an array-valued model output (ndim >= 1), "
|
|
125
|
+
f"but function(theta) returned a scalar (dtype={y0.dtype}). "
|
|
126
|
+
"Use the scalar-output derivative path (e.g. derivative/gradient/hessian) instead."
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
out_shape = y0.shape
|
|
130
|
+
m = int(y0.size)
|
|
131
|
+
|
|
132
|
+
worker = partial(
|
|
133
|
+
build_component,
|
|
134
|
+
theta=theta,
|
|
135
|
+
method=method,
|
|
136
|
+
inner_workers=inner_workers,
|
|
137
|
+
dk_kwargs=dk_kwargs,
|
|
138
|
+
function=function,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
vals = parallel_execute(
|
|
142
|
+
worker,
|
|
143
|
+
arg_tuples=[(i,) for i in range(m)],
|
|
144
|
+
outer_workers=outer_workers,
|
|
145
|
+
inner_workers=inner_workers,
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
arr = np.stack([np.asarray(v, dtype=np.float64) for v in vals], axis=0)
|
|
149
|
+
arr = arr.reshape(out_shape + arr.shape[1:])
|
|
150
|
+
|
|
151
|
+
ensure_finite(arr, msg="Non-finite values encountered in tensor-output derivative object.")
|
|
152
|
+
return arr
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""Contains functions used to construct the gradient of scalar-valued functions."""
|
|
2
|
+
|
|
3
|
+
from collections.abc import Callable
|
|
4
|
+
from functools import partial
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
|
|
8
|
+
from derivkit.derivative_kit import DerivativeKit
|
|
9
|
+
from derivkit.utils.concurrency import (
|
|
10
|
+
parallel_execute,
|
|
11
|
+
resolve_inner_from_outer,
|
|
12
|
+
)
|
|
13
|
+
from derivkit.utils.sandbox import get_partial_function
|
|
14
|
+
from derivkit.utils.validate import check_scalar_valued
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def build_gradient(function: Callable,
|
|
18
|
+
theta0: np.ndarray,
|
|
19
|
+
method: str | None = None,
|
|
20
|
+
n_workers=1,
|
|
21
|
+
**dk_kwargs: dict
|
|
22
|
+
) -> np.ndarray:
|
|
23
|
+
"""Returns the gradient of a scalar-valued function.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
function: The function to be differentiated.
|
|
27
|
+
theta0: The parameter vector at which the gradient is evaluated.
|
|
28
|
+
method: Method name or alias (e.g., ``"adaptive"``, ``"finite"``).
|
|
29
|
+
If ``None``, the :class:`derivkit.derivative_kit.DerivativeKit`
|
|
30
|
+
default (``"adaptive"``) is used.
|
|
31
|
+
n_workers: Number of workers used by
|
|
32
|
+
:meth:`derivkit.derivative_kit.DerivativeKit.differentiate`.
|
|
33
|
+
This setting does not parallelize across parameters. Default is ``1``.
|
|
34
|
+
dk_kwargs: Additional keyword arguments passed to
|
|
35
|
+
:meth:`derivkit.derivative_kit.DerivativeKit.differentiate`.
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
A 1D array representing the gradient.
|
|
39
|
+
|
|
40
|
+
Raises:
|
|
41
|
+
TypeError: If ``function`` does not return a scalar value.
|
|
42
|
+
"""
|
|
43
|
+
theta0 = np.asarray(theta0, dtype=float).reshape(-1)
|
|
44
|
+
if theta0.size == 0:
|
|
45
|
+
raise ValueError("theta0 must be a non-empty 1D array.")
|
|
46
|
+
|
|
47
|
+
check_scalar_valued(function, theta0, 0, n_workers)
|
|
48
|
+
|
|
49
|
+
inner = resolve_inner_from_outer(n_workers)
|
|
50
|
+
|
|
51
|
+
# Bind shared kwargs once; tasks only carry (function, theta0, i)
|
|
52
|
+
worker = partial(
|
|
53
|
+
_grad_component,
|
|
54
|
+
method=method,
|
|
55
|
+
n_workers=inner,
|
|
56
|
+
dk_kwargs=dk_kwargs,
|
|
57
|
+
)
|
|
58
|
+
tasks = [(function, theta0, i) for i in range(theta0.size)]
|
|
59
|
+
|
|
60
|
+
vals = parallel_execute(worker, tasks, outer_workers=n_workers, inner_workers=inner)
|
|
61
|
+
grad = np.asarray(vals, dtype=float)
|
|
62
|
+
if not np.isfinite(grad).all():
|
|
63
|
+
raise FloatingPointError("Non-finite values encountered in build_gradient.")
|
|
64
|
+
return grad
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _grad_component(
|
|
68
|
+
function: Callable,
|
|
69
|
+
theta0: np.ndarray,
|
|
70
|
+
i:int,
|
|
71
|
+
method: str | None = None,
|
|
72
|
+
n_workers: int = 1,
|
|
73
|
+
dk_kwargs: dict | None = None,
|
|
74
|
+
) -> float:
|
|
75
|
+
"""Returns one entry of the gradient for a scalar-valued function.
|
|
76
|
+
|
|
77
|
+
Used inside :func:`derivkit.calculus.gradient.build_gradient` to find how
|
|
78
|
+
the function changes with respect to a single parameter while keeping the
|
|
79
|
+
others fixed.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
function: A function that returns a single value.
|
|
83
|
+
theta0: The parameter values where the derivative is evaluated.
|
|
84
|
+
i: The index of the parameter being varied.
|
|
85
|
+
method: Method name or alias (e.g., ``"adaptive"``, ``"finite"``).
|
|
86
|
+
If ``None``, the :class:`derivkit.derivative_kit.DerivativeKit`
|
|
87
|
+
default (``"adaptive"``) is used.
|
|
88
|
+
n_workers: Number of workers used for the internal derivative step. Default is ``1``.
|
|
89
|
+
dk_kwargs: Additional keyword arguments passed to
|
|
90
|
+
:meth:`derivkit.derivative_kit.DerivativeKit.differentiate`.
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
A single number showing how the function changes with that parameter.
|
|
94
|
+
"""
|
|
95
|
+
partial_vec = get_partial_function(function, i, theta0)
|
|
96
|
+
kit = DerivativeKit(partial_vec, float(theta0[i]))
|
|
97
|
+
return kit.differentiate(order=1, method=method, n_workers=n_workers, **dk_kwargs)
|