release(v1.1.0): additive CPU-only generic numerical primitives
Adds 9 new top-level / sub-modules to the Rust API only (no Python
bindings yet), with at least one analytic unit test per module.
New Rust modules:
- optimal_control::matrix_riccati (RK4 backward solver)
- timeseries_utils::nonsync_covariance (Hayashi-Yoshida)
- timeseries_utils::wavelet (Haar / Daubechies DWT and MODWT)
- risk_measures (VaR, CVaR, projected sub-gradient CVaR minimisation)
- graph::laplacian + graph::spectral_clustering (Jacobi + k-means++)
- topology (Vietoris-Rips persistent homology, bottleneck distance)
- volterra (Caputo Adams, Markovian lift, second-kind Volterra,
Fourier inversion of characteristic functions)
- signatures (truncated tensor signature, log-sig, random reservoir,
Salvi-Cass-Lyons signature kernel, shuffle product)
All previously stable APIs untouched; abi3-py38 ABI preserved.
New module tests: 29/29 passing. Pre-existing 5 unrelated failures
unchanged.
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
Graph Laplacians and Spectral Clustering
|
||||
========================================
|
||||
|
||||
The module :code:`graph` provides graph Laplacian operators and a
|
||||
spectral clustering algorithm built on a Jacobi diagonaliser.
|
||||
|
||||
Laplacians
|
||||
----------
|
||||
|
||||
For a weighted undirected graph with adjacency matrix :math:`W \in \mathbb{R}^{n\times n}_{\ge 0}`
|
||||
and degree matrix :math:`D = \mathrm{diag}(W \mathbf{1})`:
|
||||
|
||||
- **Combinatorial**: :math:`L = D - W`.
|
||||
- **Symmetric normalised**: :math:`L_{\mathrm{sym}} = I - D^{-1/2} W D^{-1/2}`.
|
||||
- **Random-walk normalised**: :math:`L_{\mathrm{rw}} = I - D^{-1} W`.
|
||||
|
||||
Each operator is positive semidefinite and the multiplicity of the
|
||||
zero eigenvalue equals the number of connected components.
|
||||
|
||||
Spectral Clustering
|
||||
-------------------
|
||||
|
||||
Given :math:`W` and a target number of clusters :math:`k`:
|
||||
|
||||
1. Build :math:`L_{\mathrm{sym}}` (or another Laplacian).
|
||||
2. Diagonalise via cyclic Jacobi rotations to obtain the eigenpairs
|
||||
:math:`(\lambda_i, u_i)`.
|
||||
3. Stack the :math:`k` eigenvectors associated with the smallest
|
||||
eigenvalues as columns of :math:`U \in \mathbb{R}^{n \times k}`.
|
||||
4. Normalise rows of :math:`U` and run Lloyd's algorithm with
|
||||
k-means++ initialisation on the rows.
|
||||
|
||||
The Fiedler eigenvalue :math:`\lambda_2` is reported separately as a
|
||||
proxy for the spectral gap.
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
.. code-block:: rust
|
||||
|
||||
pub enum LaplacianKind { Combinatorial, SymmetricNormalised, RandomWalk }
|
||||
pub fn combinatorial_laplacian(w: ArrayView2<f64>) -> Result<Array2<f64>>;
|
||||
pub fn normalised_laplacian(w: ArrayView2<f64>) -> Result<Array2<f64>>;
|
||||
pub fn random_walk_laplacian(w: ArrayView2<f64>) -> Result<Array2<f64>>;
|
||||
|
||||
pub struct SpectralClusterResult {
|
||||
pub labels: Vec<usize>,
|
||||
pub eigenvalues: Vec<f64>,
|
||||
pub fiedler_value: f64,
|
||||
}
|
||||
pub fn spectral_cluster(w: ArrayView2<f64>, k: usize, n_kmeans_iter: usize, seed: u64)
|
||||
-> Result<SpectralClusterResult>;
|
||||
@@ -0,0 +1,60 @@
|
||||
Matrix Riccati Solver
|
||||
=====================
|
||||
|
||||
The module :code:`optimal_control::matrix_riccati` integrates backward in time
|
||||
the matrix Riccati differential equation
|
||||
|
||||
.. math::
|
||||
|
||||
\frac{dA(t)}{dt} = -2\,A(t)\,M\,A(t) + Q,
|
||||
\qquad A(T) = A_T,
|
||||
|
||||
together with the affine and constant components
|
||||
|
||||
.. math::
|
||||
|
||||
\frac{dB(t)}{dt} = -2\,A(t)\,M\,B(t),
|
||||
\qquad B(T) = B_T,
|
||||
|
||||
.. math::
|
||||
|
||||
\frac{dC(t)}{dt} = -B(t)^\top\,M\,B(t),
|
||||
\qquad C(T) = C_T.
|
||||
|
||||
Discretisation
|
||||
--------------
|
||||
|
||||
The grid :math:`\{t_n = T - n\,\Delta t\}_{n=0}^{N}` with
|
||||
:math:`\Delta t = T / N` is traversed backward and a classical RK4 step is
|
||||
applied to the joint vector field :math:`(A, B, C)`. Each macro step is
|
||||
optionally subdivided into :math:`s` sub-steps for stability on stiff
|
||||
problems.
|
||||
|
||||
Validation
|
||||
----------
|
||||
|
||||
In the scalar case :math:`A, M, Q \in \mathbb{R}` with :math:`A(T) = 0`,
|
||||
|
||||
.. math::
|
||||
|
||||
A(t) \;=\; -\sqrt{\frac{Q}{2M}}\;\tanh\!\Big(\sqrt{2QM}\,(T - t)\Big),
|
||||
|
||||
a closed form used by the unit test :code:`scalar_riccati_matches_analytic`
|
||||
to certify :math:`L^\infty` convergence below :math:`10^{-5}` on
|
||||
:math:`[0, T]`.
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
.. code-block:: rust
|
||||
|
||||
pub fn solve_matrix_riccati(
|
||||
m_matrix: ArrayView2<f64>,
|
||||
q: ArrayView2<f64>,
|
||||
n: ArrayView2<f64>,
|
||||
a_terminal: ArrayView2<f64>,
|
||||
b_terminal: ArrayView1<f64>,
|
||||
c_terminal: f64,
|
||||
t_horizon: f64,
|
||||
config: RiccatiConfig,
|
||||
) -> Result<RiccatiResult>;
|
||||
@@ -0,0 +1,48 @@
|
||||
Asynchronous Covariance (Hayashi--Yoshida)
|
||||
==========================================
|
||||
|
||||
The module :code:`timeseries_utils::nonsync_covariance` implements the
|
||||
Hayashi--Yoshida estimator of the integrated covariance between two
|
||||
asynchronously sampled processes :math:`X` and :math:`Y` observed at
|
||||
distinct, non-overlapping observation grids
|
||||
:math:`\{t^X_i\}` and :math:`\{t^Y_j\}`.
|
||||
|
||||
Estimator
|
||||
---------
|
||||
|
||||
Let :math:`I_i = (t^X_{i-1}, t^X_i]` and :math:`J_j = (t^Y_{j-1}, t^Y_j]`.
|
||||
The Hayashi--Yoshida estimator is
|
||||
|
||||
.. math::
|
||||
|
||||
\widehat{\langle X, Y\rangle}_{[0,T]}
|
||||
\;=\;
|
||||
\sum_{i, j}\,
|
||||
\big(X_{t^X_i} - X_{t^X_{i-1}}\big)\,
|
||||
\big(Y_{t^Y_j} - Y_{t^Y_{j-1}}\big)\,
|
||||
\mathbf{1}\!\big[I_i \cap J_j \neq \emptyset\big].
|
||||
|
||||
It is consistent under non-synchronicity and avoids the *Epps effect*
|
||||
that plagues naive grid interpolation.
|
||||
|
||||
Implementation
|
||||
--------------
|
||||
|
||||
* A two-pointer scan in :math:`O(n_X + n_Y)` collects all overlapping
|
||||
pairs.
|
||||
* For matrices of size :math:`d \times d` with large per-asset sample
|
||||
counts, off-diagonal entries are computed in parallel with Rayon.
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
.. code-block:: rust
|
||||
|
||||
pub fn hayashi_yoshida_covariance(
|
||||
t1: &[f64], v1: &[f64],
|
||||
t2: &[f64], v2: &[f64],
|
||||
) -> Result<f64>;
|
||||
|
||||
pub fn hayashi_yoshida_matrix(
|
||||
series: &[(Vec<f64>, Vec<f64>)],
|
||||
) -> Result<Vec<Vec<f64>>>;
|
||||
@@ -0,0 +1,73 @@
|
||||
Risk Measures: VaR and CVaR
|
||||
============================
|
||||
|
||||
The module :code:`risk_measures` provides Value-at-Risk and Conditional
|
||||
Value-at-Risk estimators together with a convex CVaR minimisation
|
||||
solver over the unit simplex.
|
||||
|
||||
Definitions
|
||||
-----------
|
||||
|
||||
For a real random variable :math:`L` (a *loss*), the Value-at-Risk at
|
||||
confidence level :math:`\alpha \in (0, 1)` is the lower :math:`\alpha`-
|
||||
quantile
|
||||
|
||||
.. math::
|
||||
|
||||
\mathrm{VaR}_\alpha(L)
|
||||
\;=\;
|
||||
\inf\!\big\{ \ell \in \mathbb{R} : \mathbb{P}(L \le \ell) \ge \alpha \big\}.
|
||||
|
||||
The Conditional Value-at-Risk (also called Average Value-at-Risk) is
|
||||
|
||||
.. math::
|
||||
|
||||
\mathrm{CVaR}_\alpha(L)
|
||||
\;=\;
|
||||
\frac{1}{1-\alpha}\,
|
||||
\int_\alpha^1 \mathrm{VaR}_u(L)\,du.
|
||||
|
||||
For a sample :math:`L_1, \dots, L_n` of i.i.d. losses sorted in increasing
|
||||
order, the empirical CVaR at level :math:`\alpha` is
|
||||
|
||||
.. math::
|
||||
|
||||
\widehat{\mathrm{CVaR}}_\alpha
|
||||
\;=\;
|
||||
\frac{1}{n - k}\, \sum_{i = k+1}^{n} L_{(i)},
|
||||
\qquad k = \lfloor \alpha\, n \rfloor.
|
||||
|
||||
Convex minimisation
|
||||
-------------------
|
||||
|
||||
Rockafellar--Uryasev (2000) showed that
|
||||
|
||||
.. math::
|
||||
|
||||
\mathrm{CVaR}_\alpha(L)
|
||||
\;=\;
|
||||
\min_{\zeta \in \mathbb{R}}\;
|
||||
\zeta + \frac{1}{1 - \alpha}\,\mathbb{E}\!\big[(L - \zeta)_+\big].
|
||||
|
||||
Given samples of a vector :math:`r^{(s)} \in \mathbb{R}^d`,
|
||||
:code:`minimize_cvar` solves
|
||||
|
||||
.. math::
|
||||
|
||||
\min_{w \in \Delta_d,\;\zeta \in \mathbb{R}}\;
|
||||
\zeta + \frac{1}{(1 - \alpha)\, S}\, \sum_{s=1}^S
|
||||
\big(\zeta - \langle r^{(s)}, w\rangle\big)_+,
|
||||
|
||||
over the unit simplex :math:`\Delta_d`, by a projected sub-gradient
|
||||
method using the Held--Wolfe--Crowder simplex projection.
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
.. code-block:: rust
|
||||
|
||||
pub fn historical_var(losses: &[f64], alpha: f64) -> Result<f64>;
|
||||
pub fn parametric_var(mu: f64, sigma: f64, alpha: f64) -> Result<f64>;
|
||||
pub fn cvar_value(losses: &[f64], alpha: f64) -> Result<f64>;
|
||||
pub fn minimize_cvar(returns: ArrayView2<f64>, cfg: &CVaRConfig)
|
||||
-> Result<CVaRResult>;
|
||||
@@ -0,0 +1,119 @@
|
||||
Path Signatures
|
||||
===============
|
||||
|
||||
The module :code:`signatures` provides truncated tensor signatures
|
||||
(Lyons 1998), log-signatures, random reservoir projections, and the
|
||||
Salvi--Cass--Lyons signature kernel.
|
||||
|
||||
Truncated Signature
|
||||
-------------------
|
||||
|
||||
For a continuous path :math:`X : [0, T] \to \mathbb{R}^d` of bounded
|
||||
variation, the *signature* is the formal series
|
||||
|
||||
.. math::
|
||||
|
||||
S(X)_{0,T}
|
||||
\;=\;
|
||||
1 + \sum_{k \ge 1} \sum_{i_1, \dots, i_k}
|
||||
S^{i_1, \dots, i_k}_{0, T}\,
|
||||
e_{i_1} \otimes \dots \otimes e_{i_k},
|
||||
|
||||
with iterated Stieltjes integrals
|
||||
|
||||
.. math::
|
||||
|
||||
S^{i_1, \dots, i_k}_{0, T}
|
||||
\;=\;
|
||||
\int_{0 < u_1 < \dots < u_k < T}
|
||||
dX^{i_1}_{u_1}\, \dots\, dX^{i_k}_{u_k}.
|
||||
|
||||
For piecewise-linear input with increments :math:`\Delta_n`, the
|
||||
truncated signature obeys the multiplicative recursion
|
||||
|
||||
.. math::
|
||||
|
||||
S^{(M)}_{0, t_n}
|
||||
\;=\;
|
||||
S^{(M)}_{0, t_{n-1}}\,\otimes_M\,\exp_M(\Delta_n),
|
||||
|
||||
where :math:`\exp_M(\Delta) = \sum_{k=0}^M \Delta^{\otimes k} / k!`.
|
||||
|
||||
Log-Signature
|
||||
-------------
|
||||
|
||||
The truncated tensor logarithm
|
||||
|
||||
.. math::
|
||||
|
||||
\log(S)
|
||||
\;=\;
|
||||
\sum_{n \ge 1} \frac{(-1)^{n+1}}{n}\,(S - 1)^{\otimes n}
|
||||
|
||||
lives in the truncated free Lie algebra and provides a more
|
||||
parsimonious representation.
|
||||
|
||||
Random Signature
|
||||
----------------
|
||||
|
||||
Following Cuchiero--Schmocker--Teichmann (2023), one drives a random
|
||||
reservoir on :math:`\mathbb{R}^N`,
|
||||
|
||||
.. math::
|
||||
|
||||
dZ_t = A_0 Z_t\, dt + \sum_{i=1}^d A_i Z_t\, dX^i_t,
|
||||
|
||||
with random matrices :math:`A_i \in \mathbb{R}^{N \times N}` whose
|
||||
entries are i.i.d. Gaussian with variance :math:`1/N`. The map
|
||||
:math:`X \mapsto Z_T` is a finite-dimensional random projection of
|
||||
:math:`S(X)`.
|
||||
|
||||
Signature Kernel (Salvi--Cass--Lyons)
|
||||
-------------------------------------
|
||||
|
||||
The signature inner product
|
||||
|
||||
.. math::
|
||||
|
||||
K(s, t) \;=\; \langle S(X)_{0, s},\; S(Y)_{0, t}\rangle
|
||||
|
||||
solves the linear hyperbolic PDE
|
||||
|
||||
.. math::
|
||||
|
||||
\frac{\partial^2 K}{\partial s\,\partial t}
|
||||
\;=\;
|
||||
\langle \dot X_s, \dot Y_t \rangle\, K(s, t),
|
||||
\qquad
|
||||
K(s, 0) = K(0, t) = 1.
|
||||
|
||||
It is integrated on a uniform grid via the Goursat scheme
|
||||
|
||||
.. math::
|
||||
|
||||
K_{i+1, j+1}
|
||||
= K_{i+1, j} + K_{i, j+1} - K_{i, j}
|
||||
+ \langle \Delta x_i, \Delta y_j\rangle\,
|
||||
\tfrac{1}{2}(K_{i+1, j} + K_{i, j+1}).
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
.. code-block:: rust
|
||||
|
||||
pub struct TruncatedSignature {
|
||||
pub channels: usize,
|
||||
pub level: usize,
|
||||
pub tensors: Vec<Vec<f64>>,
|
||||
}
|
||||
pub fn path_signature(path: &[Vec<f64>], level: usize) -> Result<TruncatedSignature>;
|
||||
pub fn log_signature(sig: &TruncatedSignature) -> Result<TruncatedLogSignature>;
|
||||
|
||||
pub struct RandomSignatureConfig {
|
||||
pub reservoir_dim: usize, pub seed: u64, pub variance: f64,
|
||||
}
|
||||
pub fn random_signature(path: &[Vec<f64>], cfg: &RandomSignatureConfig)
|
||||
-> Result<RandomSignatureResult>;
|
||||
|
||||
pub fn signature_kernel(x: &[Vec<f64>], y: &[Vec<f64>])
|
||||
-> Result<SignatureKernelResult>;
|
||||
@@ -0,0 +1,67 @@
|
||||
Topological Data Analysis
|
||||
=========================
|
||||
|
||||
The module :code:`topology` implements Vietoris--Rips persistent
|
||||
homology and the bottleneck distance between persistence diagrams.
|
||||
|
||||
Vietoris--Rips Filtration
|
||||
-------------------------
|
||||
|
||||
For a finite point cloud :math:`X = \{x_1, \dots, x_n\} \subset \mathbb{R}^d`
|
||||
and scale :math:`\varepsilon \ge 0`, the Vietoris--Rips complex is
|
||||
|
||||
.. math::
|
||||
|
||||
\mathrm{VR}_\varepsilon(X)
|
||||
\;=\;
|
||||
\big\{ \sigma \subseteq X : \mathrm{diam}(\sigma) \le \varepsilon \big\}.
|
||||
|
||||
Increasing :math:`\varepsilon` yields a filtration; the persistent
|
||||
homology of this filtration produces, for each homological degree
|
||||
:math:`k`, a multiset of birth/death pairs
|
||||
|
||||
.. math::
|
||||
|
||||
D_k(X) = \big\{ (b_i, d_i) : 0 \le b_i < d_i \le \infty \big\}.
|
||||
|
||||
Persistence Algorithm
|
||||
---------------------
|
||||
|
||||
The boundary matrix :math:`\partial` is built over :math:`\mathbb{Z}/2`
|
||||
and reduced left-to-right: for each column :math:`j` we cancel its
|
||||
lowest entry by adding any earlier column with the same low. Pairs
|
||||
:math:`(\mathrm{low}(j), j)` give birth/death pairs.
|
||||
|
||||
Bottleneck Distance
|
||||
-------------------
|
||||
|
||||
For two diagrams :math:`D` and :math:`D'`,
|
||||
|
||||
.. math::
|
||||
|
||||
d_B(D, D')
|
||||
\;=\;
|
||||
\inf_{\eta : D \to D'}\;
|
||||
\sup_{x \in D}\, \|x - \eta(x)\|_\infty,
|
||||
|
||||
where matchings may pair points with the diagonal
|
||||
:math:`\Delta = \{(t, t) : t \ge 0\}` at cost :math:`(d - b)/2`.
|
||||
|
||||
The implementation binary-searches the threshold :math:`\varepsilon`
|
||||
and certifies a perfect matching by Hopcroft--Karp on the bipartite
|
||||
graph of admissible edges.
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
.. code-block:: rust
|
||||
|
||||
pub struct PersistencePair { pub dim: usize, pub birth: f64, pub death: f64 }
|
||||
pub struct PersistenceDiagram { pub pairs: Vec<PersistencePair> }
|
||||
|
||||
pub fn vietoris_rips_filtration(points: &[Vec<f64>], max_dim: usize, max_eps: f64)
|
||||
-> Result<Vec<Simplex>>;
|
||||
pub fn persistent_homology(points: &[Vec<f64>], max_dim: usize, max_eps: f64)
|
||||
-> Result<PersistenceDiagram>;
|
||||
pub fn bottleneck_distance(d1: &[PersistencePair], d2: &[PersistencePair])
|
||||
-> Result<f64>;
|
||||
@@ -0,0 +1,122 @@
|
||||
Volterra and Fractional Solvers
|
||||
================================
|
||||
|
||||
The module :code:`volterra` collects four CPU-only generic numerical
|
||||
primitives for Volterra integral equations and related transforms.
|
||||
|
||||
Fractional Caputo Adams Solver
|
||||
------------------------------
|
||||
|
||||
For :math:`\alpha \in (0, 1)`, solve
|
||||
|
||||
.. math::
|
||||
|
||||
D^\alpha h(t) = F(t, h(t)),
|
||||
\qquad h(0) = h_0,
|
||||
|
||||
with the Diethelm--Ford--Freed (2002) fractional Adams predictor--
|
||||
corrector. Predictor:
|
||||
|
||||
.. math::
|
||||
|
||||
h^P_{n+1}
|
||||
= h_0
|
||||
+ \frac{\Delta t^\alpha}{\alpha\,\Gamma(\alpha)}
|
||||
\sum_{k=0}^{n}
|
||||
\big[(n+1-k)^\alpha - (n-k)^\alpha\big]\, F(t_k, h_k).
|
||||
|
||||
Corrector:
|
||||
|
||||
.. math::
|
||||
|
||||
h_{n+1}
|
||||
= h_0
|
||||
+ \frac{\Delta t^\alpha}{\Gamma(\alpha + 2)}
|
||||
\Big[ F(t_{n+1}, h^P_{n+1}) + \sum_{k=0}^{n} a_{n+1, k}\, F(t_k, h_k) \Big],
|
||||
|
||||
with
|
||||
|
||||
.. math::
|
||||
|
||||
a_{n+1, 0} = n^{\alpha + 1} - (n - \alpha)\,(n+1)^\alpha,
|
||||
|
||||
a_{n+1, k} = (n - k + 2)^{\alpha + 1} + (n - k)^{\alpha + 1}
|
||||
- 2\,(n - k + 1)^{\alpha + 1},
|
||||
\qquad 1 \le k \le n.
|
||||
|
||||
Markovian Lift
|
||||
--------------
|
||||
|
||||
A convolution kernel :math:`K(t)` admitting
|
||||
|
||||
.. math::
|
||||
|
||||
K(t) = \int_0^\infty e^{-\gamma t}\, \nu(d\gamma)
|
||||
|
||||
is approximated by
|
||||
|
||||
.. math::
|
||||
|
||||
K(t) \;\approx\; \sum_{j=1}^N c_j\, e^{-\gamma_j t},
|
||||
\qquad c_j \ge 0,
|
||||
|
||||
with rates :math:`\gamma_j` on a geometric grid and weights fitted by
|
||||
non-negative least squares.
|
||||
|
||||
Generic Volterra Equation
|
||||
-------------------------
|
||||
|
||||
For
|
||||
|
||||
.. math::
|
||||
|
||||
y(t) = g(t) + \int_0^t K(t - s, y(s))\, ds,
|
||||
|
||||
the trapezoidal product-integration scheme reads
|
||||
|
||||
.. math::
|
||||
|
||||
y_n = g_n + \Delta t\,\Big[
|
||||
\tfrac{1}{2} K(t_n, y_0)
|
||||
+ \sum_{k=1}^{n-1} K(t_n - t_k, y_k)
|
||||
+ \tfrac{1}{2} K(0, y_n) \Big],
|
||||
|
||||
solved implicitly by fixed-point iteration on :math:`y_n`.
|
||||
|
||||
Fourier Inversion
|
||||
-----------------
|
||||
|
||||
Recover a density from a characteristic function :math:`\varphi(u)` via
|
||||
|
||||
.. math::
|
||||
|
||||
f(x) \;\approx\;
|
||||
\frac{\Delta u}{\pi}\,
|
||||
\sum_{k=0}^{N_u - 1}
|
||||
w_k \big[\,\Re \varphi(u_k)\,\cos(u_k x)
|
||||
+ \Im \varphi(u_k)\,\sin(u_k x)\,\big],
|
||||
|
||||
with trapezoidal weights :math:`w_k`.
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
.. code-block:: rust
|
||||
|
||||
pub fn solve_fractional_ode<F: Fn(f64, f64) -> f64>(
|
||||
h0: f64, alpha: f64, t_horizon: f64, n_steps: usize, rhs: F,
|
||||
) -> Result<FractionalOdeResult>;
|
||||
|
||||
pub fn geometric_grid_lift<K: Fn(f64) -> f64>(
|
||||
kernel: K, t_samples: &[f64],
|
||||
n_factors: usize, gamma_min: f64, gamma_max: f64, nnls_iter: usize,
|
||||
) -> Result<MarkovianLift>;
|
||||
|
||||
pub fn solve_volterra<G, K>(
|
||||
g: G, kernel: K, t_horizon: f64, n_steps: usize,
|
||||
fixed_point_iter: usize, fixed_point_tol: f64,
|
||||
) -> Result<VolterraResult>;
|
||||
|
||||
pub fn fourier_invert<P: Fn(f64) -> (f64, f64)>(
|
||||
phi: P, x_grid: &[f64], u_max: f64, n_u: usize,
|
||||
) -> Result<DensityResult>;
|
||||
@@ -0,0 +1,51 @@
|
||||
Discrete and Maximum-Overlap Wavelet Transforms
|
||||
================================================
|
||||
|
||||
The module :code:`timeseries_utils::wavelet` provides Haar and Daubechies
|
||||
wavelet transforms with periodic boundary handling.
|
||||
|
||||
Filter banks
|
||||
------------
|
||||
|
||||
For an orthogonal scaling filter :math:`\{h_k\}_{k=0}^{L-1}` the quadrature
|
||||
mirror filter (QMF) is
|
||||
|
||||
.. math::
|
||||
|
||||
g_k = (-1)^k\, h_{L - 1 - k},
|
||||
|
||||
so that :math:`\sum_k h_k = \sqrt{2}` and :math:`\sum_k g_k = 0`.
|
||||
|
||||
DWT (one level, periodic)
|
||||
-------------------------
|
||||
|
||||
For an input vector :math:`x \in \mathbb{R}^N` with :math:`N` even,
|
||||
|
||||
.. math::
|
||||
|
||||
a_n = \sum_{k=0}^{L-1} h_k\, x_{(2n + k)\bmod N},
|
||||
\qquad
|
||||
d_n = \sum_{k=0}^{L-1} g_k\, x_{(2n + k)\bmod N},
|
||||
\qquad n = 0, \dots, N/2 - 1.
|
||||
|
||||
Successive levels apply the same filter to the previous approximation
|
||||
:math:`a^{(j)}`.
|
||||
|
||||
MODWT (Maximum Overlap)
|
||||
-----------------------
|
||||
|
||||
The MODWT does not downsample: at level :math:`j`, the filter is dilated
|
||||
by inserting :math:`2^{j-1} - 1` zeros between successive taps and applied
|
||||
in a periodic convolution. The result is shift-invariant.
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
.. code-block:: rust
|
||||
|
||||
pub enum WaveletFamily { Haar, Daubechies(u8) }
|
||||
pub fn scaling_filter(family: WaveletFamily) -> Result<Vec<f64>>;
|
||||
pub fn qmf(h: &[f64]) -> Vec<f64>;
|
||||
pub fn dwt_step(x: &[f64], h: &[f64], g: &[f64]) -> (Vec<f64>, Vec<f64>);
|
||||
pub fn dwt(x: &[f64], family: WaveletFamily, levels: usize) -> Result<Vec<Vec<f64>>>;
|
||||
pub fn modwt_step(x: &[f64], h: &[f64], g: &[f64], level: usize) -> (Vec<f64>, Vec<f64>);
|
||||
Reference in New Issue
Block a user