Skip to Content

Linear System Solvers

solve() is a unified entry point for and selects among HHL, QSVT, Schrödingerization, adiabatic, variational, and Chebyshev Krylov methods.

Minimal example

import numpy as np from unitarylab.library import solve A = np.array([[2.0, 1.0], [1.0, 3.0]]) b = np.array([1.0, 0.0]) result = solve(A, b, method="hhl", d=6, backend="torch", device="cpu") print(result.solution) print(result.scaling_factor)

Entry point and methods

solve(A, b, method="hhl", backend="torch", device="cpu", dtype=np.complex128, precondition=None, **kwargs)
Method and aliasesMatrix requirementsCommon method-specific parameters
hhlHermitiand=6, t=None, r=None, use_small_angle_approx=None
qsvt, qsvt_qlsaHermitianepsilon=0.001
schro, schro_trotter, schro_classicalSquare; further requirements depend on the branchSchrödingerization parameters
aqc, discrete_adiabaticHermitianTotal adiabatic time and number of discrete steps
vqlsAny square matrixcost_function, n_layers, maxiter, tol, seed, epsilon
cksHermitianepsilon=0.01

A must be an square matrix; b must have length , and must be a power of two. Matrix and vector entries must be finite. A zero vector, singular matrix, or matrix that violates a method’s assumptions can be rejected or fail to produce a valid solution.

Method defaults and branch selection

  • HHL defaults to d=6 and t=None; leaving r and use_small_angle_approx unset lets the solver choose them.
  • QSVT defaults to epsilon=0.001; CKS defaults to epsilon=0.01.
  • AQC defaults to T=None and p=1.4, with the solver estimating the total number of steps.
  • VQLS defaults to cost_function="global", n_layers=16, maxiter=50000, tol=1e-6, seed=None, and epsilon=None. It also supports n_restarts=1, optimizer="L-BFGS-B", and global_cost_stop=None. These differ from the Algorithms library’s VQLSAlgorithm.run() defaults of local_ht, 4 layers, 500 iterations, and seed=42.
  • Schrödingerization defaults to T=10.0, na=6, R=4.0, order=2, point=1, type="classical", and dt=None. The schro_trotter and schro_classical entry names are aliases for the same dispatch; the actual branch is selected by type, not the method name alone.

Preconditioning

precondition accepts:

ValueBehaviorGuidance
NoneNo preprocessingDefault
diagonal / jacobiSymmetric diagonal scalingPreserves Hermiticity
symmetric / icSymmetric incomplete CholeskyFor positive-definite matrices; preserves Hermiticity
iluIncomplete LU splittingCan break Hermiticity; use cautiously with HHL/QSVT/AQC

After preprocessing, .solution is restored to the coordinates of the original problem. The transformed problem is stored in .matrix and .rhs; original inputs are stored in .matrix_original and .rhs_original.

Return value

LinearSolverResult has these fields:

FieldDescription
solutionApproximate solution vector
matrix, rhsProblem actually passed to the solver
circuitAlgorithm circuit; may be None for a purely classical branch
scaling_factorFactor for recovering solution amplitude from a normalized quantum state
precondition_modePreprocessing information or None
matrix_original, rhs_originalOriginal inputs when preprocessing was used

Low-level HHLSolver, QSVTSolver, SCHROSolver, AQCSolver, VQLSSolver, and CKSSolver can be imported from unitarylab.library.linear_solver. They all return (circuit, solution, scaling_factor). Direct low-level calls do not include the preprocessing metadata from the high-level result object.

Usage recommendations

  • Use np.linalg.solve(A, b) to check a small-scale baseline and residual.
  • Method-specific parameters are forwarded through **kwargs; do not pass a method’s parameters to another method.
  • Increasing phase precision, circuit depth, or polynomial precision increases resource use and does not necessarily improve finite-precision results monotonically.
  • Set seed explicitly for reproducible randomized workflows such as VQLS.
Last updated on