Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Construction & Conversion

Sparse matrices can be built directly in CSR or CSC format, or assembled from unordered (row, col, value) triplets via CooMatrix and converted afterward. The three examples below construct a matrix in each of the three formats:

#![allow(unused)]
fn main() {
use rustebra::sparse::CooMatrix;

pub(crate) fn run() {
    println!("\n== CooMatrix ==");

    let eye = CooMatrix::new(3, 3, vec![0, 1, 2], vec![0, 1, 2], vec![1.0_f64, 1.0, 1.0])
        .expect("valid COO triplets");

    println!("3×3 identity:");
    println!(
        "  rows={}, cols={}, nnz={}",
        eye.rows(),
        eye.cols(),
        eye.nnz()
    );
    println!("  row_indices = {:?}", eye.row_indices());
    println!("  col_indices = {:?}", eye.col_indices());
    println!("  values      = {:?}", eye.values());

    // Duplicate (row, col) entries are legal — they are summed on conversion.
    let dup = CooMatrix::new(2, 2, vec![0, 0, 1], vec![0, 0, 1], vec![3.0_f64, 4.0, 5.0])
        .expect("valid COO with duplicate at (0,0)");
    println!(
        "with duplicate at (0,0): nnz={} (summed on coo_to_csr)",
        dup.nnz()
    );
}
}
#![allow(unused)]
fn main() {
use rustebra::sparse::CsrMatrix;

pub(crate) fn run() {
    println!("\n== CsrMatrix ==");

    // row_ptr has rows+1 entries; row_ptr[i]..row_ptr[i+1] spans row i.
    let eye = CsrMatrix::new(
        3,
        3,
        vec![0, 1, 2, 3],
        vec![0, 1, 2],
        vec![1.0_f64, 1.0, 1.0],
    )
    .expect("valid CSR arrays");

    println!("3×3 identity:");
    println!(
        "  rows={}, cols={}, nnz={}",
        eye.rows(),
        eye.cols(),
        eye.nnz()
    );
    println!("  row_ptr     = {:?}", eye.row_ptr());
    println!("  col_indices = {:?}", eye.col_indices());
    println!("  values      = {:?}", eye.values());
    println!("  row_range(1) = {:?}", eye.row_range(1));
}
}
#![allow(unused)]
fn main() {
use rustebra::sparse::CscMatrix;

pub(crate) fn run() {
    println!("\n== CscMatrix ==");

    // col_ptr has cols+1 entries; col_ptr[j]..col_ptr[j+1] spans column j.
    let eye = CscMatrix::new(
        3,
        3,
        vec![0, 1, 2, 3],
        vec![0, 1, 2],
        vec![1.0_f64, 1.0, 1.0],
    )
    .expect("valid CSC arrays");

    println!("3×3 identity:");
    println!(
        "  rows={}, cols={}, nnz={}",
        eye.rows(),
        eye.cols(),
        eye.nnz()
    );
    println!("  col_ptr     = {:?}", eye.col_ptr());
    println!("  row_indices = {:?}", eye.row_indices());
    println!("  values      = {:?}", eye.values());
    println!("  col_range(2) = {:?}", eye.col_range(2));
}
}

CooMatrix tolerates duplicate (row, col) triplets — they’re logically summed when the matrix is later used, e.g. by conversion to CSR. Converting between formats is a distinct step from construction; the example below covers all four conversion functions (coo_to_csr, csr_to_coo, csr_to_csc, csc_to_csr):

#![allow(unused)]
fn main() {
use rustebra::sparse::{
    CooMatrix, CscMatrix, CsrMatrix, SortedCsrMatrix, coo_to_csr, csc_to_csr, csr_to_coo,
    csr_to_csc,
};

pub(crate) fn run() {
    println!("\n== convert ==");

    // coo_to_csr: duplicate (row, col) entries are summed; columns sorted per row.
    let coo = CooMatrix::new(2, 2, vec![0, 0, 1], vec![0, 0, 1], vec![3.0_f64, 4.0, 5.0])
        .expect("valid COO");
    let csr: SortedCsrMatrix<f64> = coo_to_csr(coo).expect("dimensions fit within limits");
    println!("coo_to_csr (duplicate (0,0) summed: 3+4=7):");
    println!(
        "  row_ptr={:?}  col_indices={:?}  values={:?}",
        csr.row_ptr(),
        csr.col_indices(),
        csr.values()
    );

    // csr_to_coo: expands row_ptr into explicit row indices.
    let csr_eye = CsrMatrix::new(
        3,
        3,
        vec![0, 1, 2, 3],
        vec![0, 1, 2],
        vec![1.0_f64, 1.0, 1.0],
    )
    .expect("valid CSR");
    let coo_out = csr_to_coo(csr_eye).expect("dimensions fit within limits");
    println!(
        "\ncsr_to_coo (3×3 identity): row_indices={:?}",
        coo_out.row_indices()
    );

    // csr_to_csc: transposes storage layout, sorted by (col, row).
    let csr_rect = CsrMatrix::new(
        2,
        3,
        vec![0, 2, 4],
        vec![0, 2, 1, 2],
        vec![1.0_f64, 2.0, 3.0, 4.0],
    )
    .expect("valid 2×3 CSR");
    let csc_out = csr_to_csc(csr_rect).expect("dimensions fit within limits");
    println!("\ncsr_to_csc (2×3):");
    println!(
        "  col_ptr={:?}  row_indices={:?}  values={:?}",
        csc_out.col_ptr(),
        csc_out.row_indices(),
        csc_out.values()
    );

    // csc_to_csr: transposes back, sorted by (row, col).
    let csc_eye = CscMatrix::new(
        3,
        3,
        vec![0, 1, 2, 3],
        vec![0, 1, 2],
        vec![1.0_f64, 1.0, 1.0],
    )
    .expect("valid CSC");
    let csr_back = csc_to_csr(csc_eye).expect("dimensions fit within limits");
    println!(
        "\ncsc_to_csr (3×3 identity): row_ptr={:?}",
        csr_back.row_ptr()
    );
}
}

Gotchas

  • coo_to_csr sums duplicate (row, col) entries and sorts column indices within each row as a side effect, which is why it returns a SortedCsrMatrix rather than a plain CsrMatrix — you get the stronger guarantee “for free” from the conversion algorithm.
  • CsrMatrix::new/CscMatrix::new/CooMatrix::new all return Result rather than panicking on malformed input (mismatched array lengths, out-of-bounds indices, an invalid pointer array) — check the result rather than assuming construction always succeeds.