C++ reference¶
Include apxchol.h and link apxchol::core. Start with the
usage guide or CMake integration.
This page lists the existing public controls; the API policy
defines their compatibility guarantees.
Reusable solver¶
Use solver for both CPU and GPU operation. Its backend is selected during
construction and stays fixed. To force CPU use, set opts.backend to
solve_backend::cpu.
solve checks the returned solution against the original matrix and RHS.
Inspect converged; reaching the iteration limit is not an exception.
A warm start is an initial solution estimate supplied through x0.
-
class solver¶
Reusable solver owning one CPU or GPU backend, selected once at setup. Owns its input data; movable, noncopyable, and not safe for concurrent calls. Every solve verifies the returned residual against the original operator/RHS. Supplied factors use CPU in automatic mode; an explicit GPU request uploads them.
Public Functions
-
explicit solver(const Eigen::SparseMatrix<double> &A, const solve_options &opts = {}, checkpoint *cp = nullptr)¶
-
solver(const Eigen::SparseMatrix<double> &A, factorization F, const solve_options &opts = {}, checkpoint *cp = nullptr)¶
Adopt F without rebuilding or regularizing it. lump_max_mass still bounds operator validation; factor storage, dropping and solve options apply.
-
solve_result solve(const Eigen::VectorXd &b, double tol = -1.0, int max_iter = -1, const Eigen::VectorXd *x0 = nullptr) const¶
Solve Ax=b. Negative tol/max_iter use constructor defaults. x0 supplies an optional initial guess; nullptr starts from zero. Inspect converged in the result even when the iteration budget is exhausted.
-
void solve(const Eigen::VectorXd &b, solve_result &result, double tol = -1.0, int max_iter = -1, const Eigen::VectorXd *x0 = nullptr) const¶
Write into an existing result, preserving its setup timing records.
-
solve_result solve(const Eigen::VectorXd &b, Eigen::Ref<Eigen::VectorXd> x, double tol = -1.0, int max_iter = -1, const Eigen::VectorXd *x0 = nullptr) const¶
Write into caller storage; the returned result leaves x empty.
-
Eigen::VectorXd apply(const Eigen::VectorXd &r) const¶
Apply the preconditioner to finite scalar or matrix input.
-
template<class Input, class Output>
inline batch_solve_result solve(const Eigen::MatrixBase<Input> &B, Eigen::MatrixBase<Output> &X, double tol = -1, int max_iter = -1, const const_matrix_view *X0 = nullptr) const¶ Independent RHS columns, with bounded panel workspace. Output must not overlap the RHS or warm start. tol/max_iter apply to each column.
-
void apply(const_matrix_view R, matrix_view Z) const¶
-
const factorization &factor() const¶
Factor metadata; L’s row/value arrays require keep_factor_values=true. The returned reference is owned by this solver.
-
Eigen::Index rows() const¶
Operator dimension.
-
Eigen::Index operator_nnz() const¶
Stored entries in the original operator, after input canonicalization and before preconditioner lumping or dropping.
-
solve_backend backend() const¶
Selected route: cpu or gpu, never automatic.
-
factor_storage_type factor_storage() const¶
Installed triangular-solve storage: fp16 or fp32, never automatic.
-
explicit solver(const Eigen::SparseMatrix<double> &A, const solve_options &opts = {}, checkpoint *cp = nullptr)¶
Solve defaults¶
These values come directly from the native headers. Python and MATLAB/Octave use them when tolerance and iteration-budget arguments are omitted.
-
constexpr double apxchol::default_tol = 1e-8¶
-
constexpr int apxchol::default_max_iter = 200¶
Solve options¶
These defaults apply to each solve. A call may override the tolerance and iteration budget without rebuilding the factor.
-
struct solve_options¶
Public Members
-
double tol = default_tol¶
Default relative residual tolerance; must be finite and positive.
-
int max_iter = default_max_iter¶
Nonnegative default iteration budget; zero only checks the initial guess.
-
bool keep_factor_values = false¶
Retain FP32 host factor values for export or adoption by another solver. Costs an additional host copy; false keeps the permutation but releases row/value arrays. Python factorize() enables retention by default.
-
factor_options factor_opts = {}¶
Factor construction and triangular-solve storage controls.
-
solve_backend backend = solve_backend::automatic¶
Select a complete setup/solve route; execution errors never change it.
-
int num_threads = 0¶
CPU thread ceiling for setup and every solve/apply. Positive values override the calling OpenMP task’s setting; 0 inherits it. Small workloads may use fewer threads.
-
bool collect_timings = true¶
Record timing checkpoints. Final residual verification always runs.
-
double tol = default_tol¶
Results¶
Scalar solves return the solution in x, unless the caller supplied output
storage. Matrix solves write into the caller’s output matrix and return one
status record per RHS column.
-
struct solve_result¶
Public Members
-
Eigen::VectorXd x¶
-
Eigen::Index iterations = 0¶
-
double residual = 0.0¶
Relative residual checked against the original operator and RHS.
-
bool converged = false¶
Whether the checked residual is below the requested tolerance.
-
Eigen::Index lumped_offdiag = 0¶
Positive off-diagonal entries moved onto the preconditioner’s diagonal. The original operator is unchanged, including for residual verification.
-
checkpoint timings¶
-
solve_backend backend = solve_backend::cpu¶
-
Eigen::VectorXd x¶
-
struct batch_solve_result¶
Factor construction and storage¶
The controls below belong to solve_options::factor_opts or the opts
argument of factorize. Storage precision is separate from construction
precision and exported values; see the precision guide.
-
struct factor_options¶
Public Members
-
unsigned seed = 42¶
Seed for factor construction; see the precision guide for repeatability limits.
-
double regularization = 0¶
Nonnegative diagonal regularization, as a fraction of each input diagonal. Zero disables it; only the preconditioner changes.
-
double lump_max_mass = kDefaultLumpMassCeiling¶
Allowed positive off-diagonal mass fraction in [0, 1]. Zero rejects it. Accepted positive entries are moved to the preconditioner’s diagonal.
-
factor_storage_type factor_storage = factor_storage_type::automatic¶
Triangular-solve storage; construction arithmetic and exports are unchanged. automatic uses the backend default (CPU/Metal fp32, CUDA fp16).
-
double drop_tolerance = 1e-4¶
Relative off-diagonal drop threshold in [0, 1]; zero disables dropping.
-
bool verbose = false¶
Print setup and solve diagnostics.
-
partition_options partition = {}¶
Candidate selection controls for the chosen partitioner.
-
std::string is_select = "block_greedy"¶
Built-in partitioner name used by runtime dispatch.
-
clique_sampler sampler = clique_sampler::gks¶
Clique-sampling algorithm for factor construction.
-
unsigned seed = 42¶
-
enum class apxchol::factor_storage_type¶
Values:
-
enumerator automatic¶
-
enumerator fp16¶
-
enumerator fp32¶
-
enumerator automatic¶
Candidate selection¶
The partitioner chooses independent vertices for elimination. Its degree
controls live in factor_options::partition.
-
struct partition_options¶
Selection options for built-in partitioners, passed as opts.partition.
Public Members
-
double degree_quantile = degree_quantile_by_route¶
Lowest-degree fraction admitted as selection candidates, including ties. Use -1 for the backend default (CPU/Metal 0.2, CUDA 0.5), or a value in [0, 1). Zero uses degree_multiplier instead. Metal requires (0, 1) and rounds the cutoff to its degree-bucket boundary.
-
double degree_multiplier = 2.0¶
Positive degree cap multiplier when degree_quantile is zero: admit degrees at most degree_multiplier times the average degree.
-
bool degree_tiebreak = true¶
Prefer lower-degree candidates in conflicts. block_greedy breaks degree ties by index; priority_greedy uses its hashed priority to break ties.
-
double degree_quantile = degree_quantile_by_route¶
Advanced controls¶
These change scheduling, how factorization finishes the remaining graph, or sampling rules. Keep their defaults unless comparing a specific alternative. GPU construction supports a subset; see backend selection.
-
cpu_sptrsv_schedule apxchol::factor_options::cpu_schedule = cpu_sptrsv_schedule::automatic¶
CPU triangular-solve schedule; automatic chooses the installed schedule.
-
double apxchol::factor_options::min_is_fraction = 0.05¶
Base selection-yield threshold before switching to Baumann-Kyng rounds. Measured as selected regions divided by degree-eligible vertices; dense residuals may use a higher threshold. Zero disables yield-based handoff, but a round with no progress always hands off.
-
size_t apxchol::factor_options::omp_threshold = 2000¶
Work threshold for parallel selection and elimination. Smaller rounds may use fewer threads; changing this can change the constructed factor.
-
size_t apxchol::factor_options::parallel_residual_threshold = std::numeric_limits<size_t>::max()¶
Residual size at which Baumann-Kyng rounds switch to residual_peel. SIZE_MAX uses the partitioner’s default: 500 for block_greedy and priority_greedy. A small serial tail limits fill.
-
residual_peel_strategy apxchol::factor_options::residual_peel = residual_peel_strategy::natural¶
Serial pivot order: natural visits the supplied order; min_degree uses a lazy heap (not exact current minimum degree); bk_serial samples sqrt(active) vertices with replacement and picks the lowest live degree.
-
size_t apxchol::factor_options::exact_clique_max_degree = 0¶
Emit an exact Schur clique for degrees at most this value; zero disables it. Intended for small degrees because it adds d(d-1)/2 edges. GPU factor construction requires zero.
-
size_t apxchol::factor_options::exact_core_max_h = exact_core_by_route¶
Trace-cycle exact-clique limit for near-equal heavy neighbors; zero disables it. exact_core_by_route selects 4 on CPU or 0 on GPU. Other CPU samplers ignore it; GPU construction requires zero.
-
size_t apxchol::factor_options::double_cycle_min_h = 0¶
Trace-cycle rule: with at least this many near-equal heavy neighbors, emit two half-weight cycles unless the exact-core rule applies. Zero disables it; GPU construction requires zero. Expected pair weights are preserved.
Constructing and reusing a factor¶
factorize(A, opts) constructs a factor on CPU and retains its host arrays.
Custom partitioner and eliminator overloads are described in the
extension guide.
-
factorization apxchol::factorize(const Eigen::SparseMatrix<double> &L, const factor_options &opts = {}, checkpoint *cp = nullptr)¶
Matrix-level factorization using the built-in AoS graph and named partitioner.
-
struct factorization¶
Approximate Cholesky preconditioner: P^T L L^T P approximates the operator used for construction, including any lumping or regularization.
L stores FP32 lower-triangular columns in compressed sparse column (CSC)
form, with each diagonal first. perm[original_vertex] gives its elimination
position. Keep L, the permutation, operator kind and round metadata together
when handing a factor to another solver.
A solver can also retain a factor built on CUDA or Metal: enable
keep_factor_values before construction, then read solver.factor().
Pass a copy to solver(A, F, opts) to reuse it. Automatic adoption uses CPU;
set opts.backend = solve_backend::gpu to upload it to a GPU.
The original matrix A is still needed for PCG and residual checks.
For cross-process reuse, save the operator and factor together.
-
void apxchol::save_solver(const std::filesystem::path &path, const solver &owner)¶
Save the solver’s original operator and retained FP32 factor in a portable binary file. Creates a new file; an existing destination is an error. Factor retention must have been enabled at construction. No extra matrix is kept between saves.
-
solver apxchol::load_solver(const std::filesystem::path &path, const solve_options &options = {})¶
Restore a solver using the saved operator and factor. Backend, storage and solve options apply as with solver(A, F, options); automatic adoption uses CPU.
Eigen integration¶
apxchol::apx_cholesky is apxchol’s CPU preconditioner for Eigen solvers:
using SpMat = Eigen::SparseMatrix<double>;
Eigen::ConjugateGradient<SpMat, Eigen::Lower, apxchol::apx_cholesky> cg;
cg.compute(A);
Eigen::VectorXd x = cg.solve(b);
Eigen controls the outer iteration and its stopping test. Use this integration
when an Eigen solver is needed; use apxchol::solver for apxchol’s complete
CPU/GPU solve and final residual verification.
Preconditioner operation |
Purpose |
|---|---|
|
Set factor construction/storage options before setup |
|
Construct and prepare a CPU factor |
|
Prepare an existing host factor without reconstructing it |
|
Apply the prepared preconditioner, not a complete PCG solve |
|
Retain exportable values; call before |
|
Read the retained factor and metadata |
|
Query dimensions and Eigen setup status |
CPU-specific owner¶
cpu_solver remains available for code that needs its direct
preconditioner() accessor. It provides the same solve/apply operations as
solver, but always runs on CPU. Prefer
solver(A, opts) with opts.backend = solve_backend::cpu for ordinary use.
-
class cpu_solver¶
CPU-specific reusable solver, also used by the generic solver’s CPU route. Prefer solver with solve_backend::cpu unless direct preconditioner access is needed. Setup and solves stay on CPU, including in GPU-enabled builds. The optional checkpoint receives setup timings and is not retained.
Public Functions
-
explicit cpu_solver(const Eigen::SparseMatrix<double> &L, const solve_options &opts = {}, checkpoint *cp = nullptr)¶
-
cpu_solver(const Eigen::SparseMatrix<double> &L, factorization F, const solve_options &opts = {}, checkpoint *cp = nullptr)¶
Adopt an externally computed factorization (e.g. from a factorize() call with a custom eliminator or partitioner) instead of factorizing internally. L is still required — it is the PCG operator. Construction options (including regularization/lumping) are not reapplied; factor storage, dropping, scheduling and solve options still apply. L is interpreted through its lower triangle. The caller must ensure it is a valid operator compatible with F; use solver(L, F) for validation.
-
inline const apx_cholesky &preconditioner() const¶
-
explicit cpu_solver(const Eigen::SparseMatrix<double> &L, const solve_options &opts = {}, checkpoint *cp = nullptr)¶
One-shot solve and availability¶
-
solve_result apxchol::solve(const Eigen::SparseMatrix<double> &L, const Eigen::VectorXd &b, const solve_options &opts = {})¶
One-shot solve: factorize L, then solve Lx = b via PCG. Automatic selects GPU when the compiled backend is available and compatible, otherwise CPU. Explicit GPU selects device-owned CUDA or Metal setup and solve, according to the build. Unsupported inputs and execution failures are errors, never a CPU retry.
-
bool apxchol::backend_available(solve_backend backend) noexcept¶
CPU/automatic are always available without querying a device. GPU requires a usable device and compatible compiled kernels; options may still be unsupported.