gspx 0.1.0

Sparse graph signal processing and spectral graph wavelets in Rust
Documentation
# gspx

`gspx` is a Rust crate for sparse graph signal processing: exact spectral
filtering, dynamic topology updates, Chebyshev approximations, and spectral
graph modal analysis (SGMA).

It was designed around large sparse networks such as power systems, but the API works with any graph Laplacian.

License: `GPL-3.0-only`  
MSRV: Rust `1.85`

## Install

```toml
[dependencies]
gspx = "0.1"
```

## Start Here

`gspx` does not depend on packaged sample data. Most users start from one of
these three inputs:

1. An in-memory Laplacian you already have.
2. A local `.mat` Laplacian file.
3. A local `.ply` mesh file.

If your Laplacian is already in memory, the exact filtering path looks like
this:

```rust
use gspx::{StaticConvolver, impulse};
use sprs::TriMat;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut triplets = TriMat::<f64>::new((3, 3));
    triplets.add_triplet(0, 0, 1.0);
    triplets.add_triplet(0, 1, -1.0);
    triplets.add_triplet(1, 0, -1.0);
    triplets.add_triplet(1, 1, 2.0);
    triplets.add_triplet(1, 2, -1.0);
    triplets.add_triplet(2, 1, -1.0);
    triplets.add_triplet(2, 2, 1.0);

    let laplacian = triplets.to_csc();
    let signal = impulse(&laplacian, 0, 1)?;
    let scales = [0.25, 1.0, 4.0];

    let mut convolver = StaticConvolver::new(laplacian)?;
    let filtered = convolver.bandpass(signal.view(), &scales, 2)?;

    println!("computed {} scales", filtered.len());
    Ok(())
}
```

If you want to read local files directly, use the file loaders:

```rust,no_run
use gspx::{load_laplacian, load_ply_laplacian, load_ply_xyz};
use std::path::Path;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let delay_texas = load_laplacian(Path::new("resources/library/DELAY/TEXAS.mat"))?;
    let bunny_mesh = load_ply_laplacian(Path::new("resources/library/MESH/BUNNY.ply"))?;
    let bunny_xyz = load_ply_xyz(Path::new("resources/library/MESH/BUNNY.ply"))?;

    println!("Texas vertices: {}", delay_texas.rows());
    println!("Bunny vertices: {}", bunny_mesh.rows());
    println!("Bunny coordinate shape: {:?}", bunny_xyz.raw_dim());
    Ok(())
}
```

## Example Data

The larger Laplacians and meshes used by the examples live in this repository
under `resources/library`, but they are not packaged into the published crate.

Use `ExampleData::from_dir(...)` when you want the named example datasets from
that local directory structure:

```rust,no_run
use gspx::{Dataset, ExampleData, GraphKind};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let data = ExampleData::from_dir("resources/library")?;
    let texas = data.graph(Dataset::Texas, GraphKind::Delay)?;
    let coords = data.coords(Dataset::Texas)?;

    println!("Texas vertices: {}", texas.rows());
    println!("Texas coordinate shape: {:?}", coords.raw_dim());
    Ok(())
}
```

### Example Dataset Catalog

| Dataset | Graph kinds | Coordinates | Source |
|---|---|---|---|
| `East` | `Delay` | no | local `resources/library` |
| `EastWest` | `Delay`, `Impedance`, `Length` | yes | local `resources/library` |
| `Hawaii` | `Delay`, `Impedance`, `Length` | yes | local `resources/library` |
| `Neiso` | `Delay`, `Length` | no | local `resources/library` |
| `Texas` | `Delay`, `Impedance`, `Length` | yes | local `resources/library` |
| `Usa` | `Delay`, `Impedance`, `Length` | yes | local `resources/library` |
| `Wecc` | `Delay`, `Impedance`, `Length` | no | local `resources/library` |
| `Bunny` | `Mesh` | yes | local `resources/library` |
| `Horse` | `Mesh` | yes | local `resources/library` |
| `Lbrain` | `Mesh` | yes | local `resources/library` |
| `Rbrain` | `Mesh` | yes | local `resources/library` |

## Main Workflows

### Exact Filters

`StaticConvolver` and `DynamicConvolver` expose the analytical filter family:

- `lowpass(...)`
- `bandpass(...)`
- `highpass(...)`

Use `StaticConvolver` when the graph is fixed. Use `DynamicConvolver` when you
need online branch updates with `add_branch(i, j, weight)` and want to reuse
precomputed pole state.

### Custom Kernels

`VfModel` fits rational kernels from sampled spectral responses, then
`StaticConvolver` or `DynamicConvolver` applies the resulting `VfKernel`.

For polynomial approximations, use `ChebyModel` and `ChebyConvolver`.

### SGMA

`Sgma` handles the spatial-temporal analysis path:

- `spectrum(...)` and `spectrum_complex(...)`
- `find_peaks(...)`
- `find_modes(...)`
- `analyze_many(...)`

## Signal Shape Conventions

Filtering APIs accept either:

- 1D signals: `(n_vertices,)`
- 2D signal matrices: `(n_vertices, n_signals)`

For SGMA, the signal matrix is `(n_vertices, n_times)` and the time vector
length must match `n_times`.

Helpers:

- `impulse(&laplacian, vertex_index, n_channels)`
- `impulse_1d(&laplacian, vertex_index)`
- `estimate_spectral_bound(&laplacian)`

## Examples

Cargo examples live in `examples/`.

| Group | Examples |
|---|---|
| Basics | `basic_static_filters`, `basic_dynamic_topology`, `basic_chebyshev`, `basic_vf_fit`, `basic_sgma`, `basic_resource`, `basic_local_files` |
| Plotting | `plot_path_filters`, `plot_sgma_heatmap`, `plot_sgma_modes`, `plot_geo_filters`, `plot_mesh_bunny_filters`, `plot_mesh_bunny_scales` |
| Reporting | `benchmark_report` |

Common starting points:

```bash
cargo run --example basic_static_filters
cargo run --example basic_dynamic_topology
cargo run --example basic_chebyshev
cargo run --example basic_vf_fit
cargo run --example basic_sgma
cargo run --example basic_resource
cargo run --example basic_local_files
```

- `basic_resource` shows loading a named dataset from a local `resources/library` directory.
- `basic_local_files` shows direct MAT and PLY loading from local file paths.

Benchmark workflow:

```bash
cargo bench --bench perf_core
cargo run --example benchmark_report
```

## Platform Notes

- `gspx` targets Linux and Windows for the `0.1` release.
- Sparse shifted solves use SuiteSparse-backed LDL factorization through `sprs-ldl`.
- The packaged crate includes source, tests, examples, and docs only; example data stays in the repo.

## Citation

If you use `gspx` for research, cite the associated HICSS paper.

```bibtex
@inproceedings{lowery-sgwt-2026,
  title={Using Spectral Graph Wavelets to Analyze Large Power System Oscillation Modes},
  author={Lowery, Luke and Baek, Jongoh and Birchfield, Adam},
  year={2026}
}
```

The same citation metadata is also available in [`CITATION.cff`](./CITATION.cff).

## Links

`gspx` was first prototyped in the Python `sgwt` project; that repository is
still the main background reference for the datasets and research context.

- Python `sgwt`: <https://github.com/lukelowry/sgwt>
- Python docs: <https://sgwt.readthedocs.io/>
- Julia implementation: <https://github.com/lukelowry/SpectralGraphWavelet.jl>
- SuiteSparse: <https://github.com/DrTimothyAldenDavis/SuiteSparse>
- Synthetic grid cases: <https://electricgrids.engr.tamu.edu/electric-grid-test-cases/>
- Author page: <https://lukelowry.github.io/>
- Google Scholar: <https://scholar.google.com/citations?user=CTynuRMAAAAJ&hl=en>