sanic: Solving Ax = b Nimbly in C++

sanic provides direct and iterative solvers for linear systems in R, powered by the Eigen C++ library. It supports dense and sparse systems, reusable LU factorizations, eigenvalue and singular value decompositions, and Arnoldi and Lanczos projections.

Installation

Install the released version from CRAN or the development version from GitHub:

install.packages("sanic")
# remotes::install_github("nk027/sanic")
install.packages("sanic", repos = c('https://nk027.r-universe.dev', 'https://cloud.r-project.org'))

Usage

Use solve2() to select a direct solver automatically: QR for rectangular input, a Cholesky attempt for symmetric input (with LU fallback), and LU otherwise.

library(sanic)

A <- matrix(c(4, 1, 1, 3), nrow = 2)
b1 <- c(1, 2)
b2 <- c(3, 4)

x <- solve2(A, b1)
x
#            [,1]
# [1,] 0.09090909
# [2,] 0.63636364

For repeated LU solves with the same matrix, compute the factorization once:

f <- factorize_lu(A)
x1 <- solve(f, b1)
x2 <- solve(f, b2)
cbind(x1, x2)

Factors are session-local and must be recreated from the original matrix after saving/loading or when moving to another R process.

Call solve_lu(), solve_qr(), or solve_chol() directly to choose a method explicitly. For iterative solves, use solve_cg() and select the method explicitly. The default is BiCGSTAB; for classic conjugate gradient use:

x_cg <- solve_cg(sparsify(A), b1, type = "CG", tol = 1e-10)
max(abs(A %*% x_cg - b1))

Classic CG requires a symmetric positive definite matrix. Iterative methods offer preconditioners and convergence controls.

Use eigen2() for eigenvalue decompositions and svd2() for singular value decompositions of dense matrices. For large sparse matrices, arnoldi() and lanczos() construct smaller Krylov projections. Set iter below the matrix dimension to build a smaller projection.

Linear system solvers

The pivoting options below refer to dense methods; sparse methods use their own pivoting and ordering schemes. For Cholesky, positive definite input is a safe starting point for both LLT and LDLT.

Solver Function Notes Sparse support Reference
LU decomposition solve_lu() Partial or full pivoting Yes 1, 2, 3
Householder QR solve_qr() Column, full, or no pivoting; rectangular least squares Yes 1, 2, 3, 4
Cholesky decomposition solve_chol() LDLT by default; LLT with pivot = 0 Yes 1, 2, 3, 4
Iterative Krylov methods solve_cg() BiCGSTAB (default); LSCG for least squares; CG for symmetric positive definite systems; preconditioners available Only¹ 1, 2, 3

¹ Sparse matrices are used internally; dense inputs are converted.

Spectral methods

Method Function Notes Sparse support Reference
Eigenvalue decomposition eigen2() General square and symmetric matrices No 1, 2
Singular value decomposition svd2() Divide-and-conquer SVD for large problems; Jacobi SVD for small problems No 1, 2
Arnoldi iteration arnoldi() Hessenberg projection; uses Lanczos for symmetric matrices Only¹ 1
Lanczos algorithm lanczos() Tridiagonal projection for symmetric matrices Only¹ 1

¹ Sparse matrices are used internally; dense inputs are converted.

Citation

To cite sanic, please use:

Kuschnig, N. (2026). sanic: Solving Ax = b Nimbly in C++ (R package version 0.0.2). https://CRAN.R-project.org/package=sanic

BibTeX:

@Manual{sanic,
  title  = {{sanic}: Solving {A}x = b Nimbly in {C++}},
  author = {Nikolas Kuschnig},
  year   = {2026},
  note   = {R package version 0.0.2},
  url    = {https://CRAN.R-project.org/package=sanic}
}

License

See LICENSE for package licensing and third-party attribution, including the MPL-2.0 header adapted from Eigen and Spectra.