|
| 1 | +# CXSparse.jl |
| 2 | + |
| 3 | +Julia wrapper around the [CXSparse](https://github.com/DrTimothyAldenDavis/SuiteSparse/tree/dev/CXSparse) library from SuiteSparse — the lightweight, textbook-style sparse direct solvers from Tim Davis's *Direct Methods for Sparse Linear Systems* (CSparse), extended to support `ComplexF64` values and both 32- and 64-bit indices. |
| 4 | + |
| 5 | +CXSparse is the QR / LU counterpart to **KLU's design philosophy**: a small symbolic phase, very little per-call overhead, well-suited to small-to-medium sparse problems (n up to a few thousand). It complements the multifrontal solvers (UMFPACK, SPQR, CHOLMOD) which pay a heavier symbolic tax in exchange for BLAS-3 speedups on larger fronts. |
| 6 | + |
| 7 | +This package wraps the `cs_qr` and `cs_lu` factorizations from `CXSparse_jll` and exposes a Julian API. |
| 8 | + |
| 9 | +## Status |
| 10 | + |
| 11 | +- [x] `cs_qr` for `SparseMatrixCSC{Float64, Int32 | Int64}` and `SparseMatrixCSC{ComplexF64, Int32 | Int64}` |
| 12 | +- [x] `cs_lu` for the same four element/index combinations |
| 13 | +- [x] `LinearAlgebra.ldiv!` and `\` for both factorizations |
| 14 | +- [x] Finalizer-managed C-side memory (no manual `cs_*_sfree` calls required) |
| 15 | +- [ ] `cs_cholsol` for symmetric positive definite — not yet wrapped |
| 16 | + |
| 17 | +## Quick start |
| 18 | + |
| 19 | +```julia |
| 20 | +using CXSparse, SparseArrays |
| 21 | + |
| 22 | +A = sparse([2.0 1.0 0.0; |
| 23 | + 1.0 3.0 1.0; |
| 24 | + 0.0 1.0 2.0]) |
| 25 | +b = [1.0, 2.0, 3.0] |
| 26 | + |
| 27 | +# QR factorization (works for square or overdetermined m ≥ n): |
| 28 | +F = cs_qr(A) |
| 29 | +x = F \ b |
| 30 | +# or in-place: |
| 31 | +x_pre = zeros(3) |
| 32 | +ldiv!(x_pre, F, b) |
| 33 | + |
| 34 | +# LU factorization (square only): |
| 35 | +G = cs_lu(A) |
| 36 | +y = G \ b |
| 37 | +``` |
| 38 | + |
| 39 | +## Supported element/index combinations |
| 40 | + |
| 41 | +| element type | index type | CXSparse name | |
| 42 | +|----------------|------------|---------------| |
| 43 | +| `Float64` | `Int32` | `cs_di_*` | |
| 44 | +| `Float64` | `Int64` | `cs_dl_*` | |
| 45 | +| `ComplexF64` | `Int32` | `cs_ci_*` | |
| 46 | +| `ComplexF64` | `Int64` | `cs_cl_*` | |
| 47 | + |
| 48 | +CXSparse does **not** ship `Float32` variants — `cs_si_*` / `cs_sl_*` don't exist upstream. |
| 49 | + |
| 50 | +## When to use this vs SPQR / UMFPACK |
| 51 | + |
| 52 | +CXSparse `cs_qr` and `cs_lu` are textbook implementations: simple, low symbolic-phase overhead, no BLAS-3. They sit alongside KLU in the "small/medium fast path" niche: |
| 53 | + |
| 54 | +| | KLU | UMFPACK | SPQR | CXSparse `cs_qr` / `cs_lu` | |
| 55 | +|---|---|---|---|---| |
| 56 | +| factorization | LU | LU | QR | LU / QR | |
| 57 | +| algorithm | BTF + Gilbert–Peierls partial-pivot LU | multifrontal BLAS-3 LU | multifrontal BLAS-3 QR | textbook Householder QR / Gilbert–Peierls LU | |
| 58 | +| sweet spot | n ≲ few thousand | n ≳ 1k | n ≳ 1k, least-squares | n ≲ few thousand | |
| 59 | +| pivoting | partial | row + column | sparsity-only (rank-revealing if `tol ≥ 0`) | partial (LU), sparsity-only (QR) | |
| 60 | +| BLAS-3 | no | yes | yes | no | |
| 61 | + |
| 62 | +On 199×199 sparse matrices we observed `cs_qr` running in ~325 µs vs SPQR's ~570 µs (1.7× faster). For rank-deficient inputs, however, `cs_qr` is **not rank-revealing** — `x` may contain non-finite entries from the back-solve dividing through near-zero `R` diagonals. If you need a clean solution on rank-deficient systems, fall back to `qr(A)` (SPQR) or LAPACK's column-pivoted QR on `Matrix(A)`. |
| 63 | + |
| 64 | +## Internals |
| 65 | + |
| 66 | +CXSparse uses 0-based indexing. The wrapper allocates 0-based `colptr` / `rowval` buffers when constructing the `cs_*_sparse` view; `nzval` is shared with the user's `SparseMatrixCSC` directly (CXSparse doesn't mutate it during factorization of a CSC matrix). |
| 67 | + |
| 68 | +Symbolic and numeric C-side structs (`cs_*_symbolic`, `cs_*_numeric`) are owned by the Julia factorization object and freed by a finalizer. The struct internals are accessed via raw pointer offsets matching the layout in `cs.h`; we never mirror the symbolic/numeric structs in full. |
| 69 | + |
| 70 | +## License |
| 71 | + |
| 72 | +The wrapper is MIT-licensed. CXSparse itself is dual-licensed (LGPL-2.1+ / GPL-2.0+) — see the upstream [SuiteSparse repository](https://github.com/DrTimothyAldenDavis/SuiteSparse). |
0 commit comments