gspx 0.1.1

Sparse graph signal processing and spectral graph wavelets in Rust
Documentation

gspx

gspx is a Rust crate for sparse graph signal processing. It provides fast implementations of graph convolution using rational kernel fitting (and alternatively using the slower Chebyshev method). Supports dynamic graphs for applications with a changing network topology.

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

License: GPL-3.0-only
MSRV: Rust 1.85

Install

[dependencies]
gspx = "0.1"

What It Provides

  • Exact lowpass, bandpass, and highpass filtering on sparse Laplacians
  • Reusable dynamic filtering after low-rank branch updates
  • Chebyshev polynomial approximations for faster approximate filtering
  • Rational kernel fitting through vector fitting
  • SGMA for joint spatial-temporal analysis

Quick Start

If you already have a Laplacian in memory, you can start filtering immediately:

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(())
}

Loading Local Files

If your graph data is already stored on disk, use the direct file loaders:

use gspx::{load_laplacian, load_ply_laplacian, load_ply_xyz, load_signal};
use std::path::Path;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let laplacian = load_laplacian(Path::new("/path/to/graph.mat"))?;
    let signal = load_signal(Path::new("/path/to/signals.mat"))?;
    let mesh_graph = load_ply_laplacian(Path::new("/path/to/mesh.ply"))?;
    let mesh_xyz = load_ply_xyz(Path::new("/path/to/mesh.ply"))?;

    println!("graph vertices: {}", laplacian.rows());
    println!("signal shape: {:?}", signal.raw_dim());
    println!("mesh vertices: {}", mesh_graph.rows());
    println!("mesh coordinate shape: {:?}", mesh_xyz.raw_dim());
    Ok(())
}

Main APIs

Exact and Dynamic Filtering

  • StaticConvolver for fixed graphs
  • DynamicConvolver for graphs that receive branch updates through add_branch
  • lowpass(...), bandpass(...), and highpass(...) for analytical filters

Approximate Filtering

  • ChebyModel to fit Chebyshev kernels
  • ChebyConvolver to apply them efficiently on sparse graphs

Custom Rational Kernels

  • VfModel to fit rational kernels from sampled spectral responses
  • VfKernel to store poles, residues, and direct terms

SGMA

  • Sgma for spectral graph modal analysis
  • spectrum(...), spectrum_complex(...), find_peaks(...), find_modes(...)

Helpers

  • impulse(&laplacian, vertex_index, n_channels)
  • impulse_1d(&laplacian, vertex_index)
  • estimate_spectral_bound(&laplacian)

Signal Shape Conventions

Filtering APIs accept either:

  • 1D signals with shape (n_vertices,)
  • 2D signal matrices with shape (n_vertices, n_signals)

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

Repository Examples

The repository includes runnable examples under examples/.

If you cloned this repository, the larger example Laplacians and meshes used by some examples live under resources/library. They are not packaged into the published crate.

ExampleData is a convenience wrapper for that local directory layout, or for your own directory if you mirror the same subfolders:

use gspx::{Dataset, ExampleData, GraphKind, KernelPreset};

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)?;
    let kernel = data.vf_kernel(KernelPreset::ModifiedMorlet)?;

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

Common example commands from a cloned checkout:

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

Plotting and benchmark-report examples also live in examples/, but they are primarily for repository use rather than typical crate consumption.

Platform Notes

  • gspx currently targets Linux and Windows
  • Sparse shifted solves use SuiteSparse-backed LDL factorization via sprs-ldl
  • The published crate does not include repository example datasets

Citation

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

@inproceedings{lowery-gspx-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.

Links