Performance Tips

Practical guidance for picking a backend, method, and precision once you are past the quick start. The reasoning behind the direct-vs-iterative trade-off is in Backends and Capability Matrix; the measured numbers are in Benchmarks.

Choosing a backend and method

  • float64 converges more reliably with the iterative solvers; float32 can stall on ill-conditioned PDE matrices.

  • For SPD matrices, cholesky is roughly twice as fast as lu – let matrix_type="auto" detect symmetry / positive-definiteness and pick it.

  • On CPU, scipy+lu is the default and gives machine precision.

  • On NVIDIA for problems under ~2M DOF, cudss+cholesky is the fastest direct solver.

  • For larger problems, pytorch+cg is the memory-efficient choice and the one that reached 169M DOF on a single GPU.

  • Beyond a single GPU, DSparseTensor partitions the matrix across devices.

  • For a portable GPU direct solve – including AMD ROCm, where cuDSS is not available – use strumpack (multifrontal LU on CPU/CUDA/ROCm).

Reusing work across solves

  • For repeated solves with the same matrix, factor once with A.lu() and reuse the LUFactorization for each right-hand side.

  • To apply one set of defaults across many solves, wrap them in a SolverConfig scope (see the Configuring solves section of Introduction) rather than repeating kwargs.

  • An iterative solve refines toward a tolerance, so a good x0 (e.g. the previous step’s solution in a time loop) cuts the iteration count.

Accuracy vs. speed

  • The iterative default atol ~ 1e-6 is a stopping point, not a ceiling – tighten atol toward 1e-12 when you need more digits, at the cost of iterations. See Direct vs iterative.

  • A good preconditioner ("amg" for PDE problems) can cut the iteration count 10-100x on ill-conditioned systems.