| Crates.io | nalgebra_block_triangularization |
| lib.rs | nalgebra_block_triangularization |
| version | 0.1.0 |
| created_at | 2026-01-14 01:42:04.059767+00 |
| updated_at | 2026-01-14 01:42:04.059767+00 |
| description | Structural decomposition of sparse matrices into block triangular form using graph algorithms |
| homepage | |
| repository | https://github.com/bcolloran/nalgebra_block_triangularization |
| max_upload_size | |
| id | 2041958 |
| size | 164,451 |
Structural decomposition of sparse matrices into block triangular form using graph algorithms.
This was written to my spec, but entirely by LLM. It could contain errors, but my spec included a mandate for quite a lot of property-based testing. I've only looked through this quickly, but the proptests look good and cover a huge variety of cases, way more than I would have ever had the patience to write myself.
This is good enough for me, perhaps for you too :-)
But if you find any mistakes, please open an issue or PR!
This library computes row and column permutations that reveal the block triangular structure of a sparse matrix. Given a matrix M, it finds permutation matrices P and Q such that:
U = P M Q (upper block triangular)
or
L = P M Q (lower block triangular)
where each diagonal block corresponds to a strongly connected component (SCC) in the dependency graph induced by a maximum matching.
The implementation uses a well-established graph-theoretic approach:
nalgebra::PermutationSequence objectsAdd to your Cargo.toml:
[dependencies]
nalgebra = "0.32"
nalgebra_block_triangularization = "0.1"
use nalgebra::DMatrix;
use nalgebra_block_triangularization::upper_triangular_permutations;
// Create a sparse binary matrix (0/1 pattern)
let m = DMatrix::from_row_slice(8, 8, &[
1, 0, 1, 0, 0, 0, 0, 0,
1, 0, 1, 0, 0, 0, 0, 0,
1, 1, 0, 1, 1, 0, 0, 0,
1, 1, 0, 1, 1, 0, 0, 0,
1, 1, 0, 0, 0, 0, 0, 0,
1, 1, 1, 0, 0, 1, 1, 0,
1, 1, 1, 0, 0, 1, 1, 0,
1, 1, 0, 0, 0, 0, 1, 1,
]);
// Compute permutations
let (pr, pc) = upper_triangular_permutations(&m);
// Apply to get block upper-triangular form
let mut u = m.clone();
pr.permute_rows(&mut u);
pc.permute_columns(&mut u);
println!("Block upper-triangular form:\n{}", u);
For more detailed structural information:
use nalgebra_block_triangularization::upper_block_triangular_structure;
let structure = upper_block_triangular_structure(&m);
println!("Matching size: {}", structure.matching_size);
println!("Number of blocks: {}", structure.block_sizes.len());
println!("Block sizes: {:?}", structure.block_sizes);
println!("Row ordering: {:?}", structure.row_order);
println!("Column ordering: {:?}", structure.col_order);
// Access individual blocks
let blocks = structure.block_indices();
for (i, (row_indices, col_indices)) in blocks.iter().enumerate() {
println!("Block {}: rows {:?}, cols {:?}", i, row_indices, col_indices);
}
The library also supports lower block triangular form:
use nalgebra_block_triangularization::{lower_triangular_permutations, lower_block_triangular_structure};
let (pr, pc) = lower_triangular_permutations(&m);
let mut l = m.clone();
pr.permute_rows(&mut l);
pc.permute_columns(&mut l);
let structure = lower_block_triangular_structure(&m);
println!("Lower BTF structure: {:?}", structure);
The output provides:
The library is organized into focused modules:
adjacency: Graph construction from matrix sparsity patternmatching: Hopcroft-Karp maximum bipartite matchingscc: Tarjan's strongly connected components algorithmordering: Topological sorting with deterministic tie-breakingpermutation: Conversion to nalgebra permutation sequencesAll algorithms operate purely on the structural sparsity pattern (nonzero vs. zero), not on numerical values.
This project is licensed under the MIT License - see the LICENSE file for details.