d780ed81d7
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.
53 lines
1.9 KiB
ReStructuredText
53 lines
1.9 KiB
ReStructuredText
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>;
|