Skip to content

feat(binar): add sparse ↔ dense BitMatrix conversion#47

Open
jmbr wants to merge 4 commits into
mainfrom
sparse-matrix-conversion
Open

feat(binar): add sparse ↔ dense BitMatrix conversion#47
jmbr wants to merge 4 commits into
mainfrom
sparse-matrix-conversion

Conversation

@jmbr
Copy link
Copy Markdown
Member

@jmbr jmbr commented Mar 25, 2026

Summary

Add methods for converting between dense BitMatrix and sparse
column/row representations via IndexSet, and expose them in the
Python bindings.

Motivation

BitMatrix has no way to construct a matrix from sparse column or row
descriptions, or to decompose one into its column/row supports.
Consumers that work with sparse GF(2) matrices (e.g., syndrome
indicators, check matrices) must set bits one at a time.

Changes

Rust API (AlignedBitMatrix + BitMatrix):

  • from_sparse_columns(&[IndexSet], row_count, column_count) -> Result<Self, SparseConversionError>
  • from_sparse_rows(&[IndexSet], row_count, column_count) -> Result<Self, SparseConversionError>
  • sparse_columns(&self) -> Vec<IndexSet>
  • sparse_rows(&self) -> Vec<IndexSet>

Both constructors take an explicit (row_count, column_count) shape
(matching the scipy.sparse convention), allowing trailing zero
rows/columns. Invalid inputs return SparseConversionError.

Python API (BitMatrix):

  • from_sparse_columns(columns, row_count, column_count)
  • from_sparse_rows(rows, row_count, column_count)
  • sparse_columns() -> list[list[int]]
  • sparse_rows() -> list[list[int]]

Invalid inputs raise ValueError.

Testing

  • Proptest round-trips for both sparse_columns and sparse_rows
  • Trailing zero rows/columns
  • Error cases: too many entries, index out of bounds
  • Edge cases: empty matrix, identity matrix
  • cargo clippy-all clean, cargo fmt clean, mypy.stubtest clean

@jmbr jmbr force-pushed the sparse-matrix-conversion branch from d8dab5f to 7d82cbd Compare March 25, 2026 18:17
@jmbr jmbr requested a review from apaetz March 25, 2026 20:40
@jmbr jmbr marked this pull request as draft March 25, 2026 21:16
@jmbr jmbr marked this pull request as ready for review March 25, 2026 22:05
Juan M. Bello-Rivas and others added 4 commits March 25, 2026 15:10
Add four methods to BitMatrix for converting between dense matrix
storage and sparse column/row representations via IndexSet:

- from_sparse_columns(&[IndexSet], row_count) -> Self
- from_sparse_rows(&[IndexSet], column_count) -> Self
- sparse_columns(&self) -> Vec<IndexSet>
- sparse_rows(&self) -> Vec<IndexSet>

Implementations are on AlignedBitMatrix with BitMatrix delegating.
Includes proptest round-trip tests and edge-case coverage.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add PyO3 wrappers and .pyi stubs for:
- BitMatrix.from_sparse_columns(columns, row_count)
- BitMatrix.from_sparse_rows(rows, column_count)
- BitMatrix.sparse_columns() -> list[list[int]]
- BitMatrix.sparse_rows() -> list[list[int]]

Python uses list[list[int]] rather than Vec<IndexSet> since IndexSet
is not exposed to Python.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Both from_sparse_rows and from_sparse_columns now take (row_count,
column_count) instead of inferring one dimension from the data length.
This allows constructing matrices with trailing zero rows or columns,
matching the scipy.sparse convention of an explicit shape parameter.

Invalid inputs (too many entries or out-of-bounds indices) return
SparseConversionError instead of panicking. The Python bindings
translate this to ValueError.
@jmbr jmbr force-pushed the sparse-matrix-conversion branch from a9d4eed to 2134817 Compare March 25, 2026 22:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant