// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2026 Rasmus Munk Larsen // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. // Tests for GpuSparseLU: GPU sparse LU via cuDSS. #define EIGEN_USE_GPU #include "main.h" #include #include using namespace Eigen; // ---- Helper: build a random sparse non-singular general matrix --------------- template SparseMatrix make_general(Index n, double density = 0.1) { using SpMat = SparseMatrix; using RealScalar = typename NumTraits::Real; SpMat R(n, n); R.reserve(VectorXi::Constant(n, static_cast(n * density) + 1)); for (Index j = 0; j < n; ++j) { for (Index i = 0; i < n; ++i) { if (i == j || (std::rand() / double(RAND_MAX)) < density) { R.insert(i, j) = Scalar(std::rand() / double(RAND_MAX) - 0.5); } } } // Add strong diagonal for non-singularity. for (Index i = 0; i < n; ++i) R.coeffRef(i, i) += Scalar(RealScalar(n)); R.makeCompressed(); return R; } // ---- Solve and check residual ----------------------------------------------- template void test_solve(Index n) { using SpMat = SparseMatrix; using Vec = Matrix; using RealScalar = typename NumTraits::Real; SpMat A = make_general(n); Vec b = Vec::Random(n); GpuSparseLU lu(A); VERIFY_IS_EQUAL(lu.info(), Success); Vec x = lu.solve(b); VERIFY_IS_EQUAL(x.rows(), n); Vec r = A * x - b; RealScalar tol = RealScalar(100) * RealScalar(n) * NumTraits::epsilon(); VERIFY(r.norm() / b.norm() < tol); } // ---- Multiple RHS ----------------------------------------------------------- template void test_multiple_rhs(Index n, Index nrhs) { using SpMat = SparseMatrix; using Mat = Matrix; using RealScalar = typename NumTraits::Real; SpMat A = make_general(n); Mat B = Mat::Random(n, nrhs); GpuSparseLU lu(A); VERIFY_IS_EQUAL(lu.info(), Success); Mat X = lu.solve(B); VERIFY_IS_EQUAL(X.rows(), n); VERIFY_IS_EQUAL(X.cols(), nrhs); Mat R = A * X - B; RealScalar tol = RealScalar(100) * RealScalar(n) * NumTraits::epsilon(); VERIFY(R.norm() / B.norm() < tol); } // ---- Refactorize ------------------------------------------------------------ template void test_refactorize(Index n) { using SpMat = SparseMatrix; using Vec = Matrix; using RealScalar = typename NumTraits::Real; SpMat A = make_general(n); Vec b = Vec::Random(n); GpuSparseLU lu; lu.analyzePattern(A); VERIFY_IS_EQUAL(lu.info(), Success); lu.factorize(A); VERIFY_IS_EQUAL(lu.info(), Success); Vec x1 = lu.solve(b); // Modify values, keep pattern. SpMat A2 = A; for (Index i = 0; i < n; ++i) A2.coeffRef(i, i) *= Scalar(RealScalar(2)); lu.factorize(A2); VERIFY_IS_EQUAL(lu.info(), Success); Vec x2 = lu.solve(b); RealScalar tol = RealScalar(100) * RealScalar(n) * NumTraits::epsilon(); VERIFY((A * x1 - b).norm() / b.norm() < tol); VERIFY((A2 * x2 - b).norm() / b.norm() < tol); VERIFY((x1 - x2).norm() > NumTraits::epsilon()); } // ---- Empty ------------------------------------------------------------------ void test_empty() { using SpMat = SparseMatrix; SpMat A(0, 0); A.makeCompressed(); GpuSparseLU lu(A); VERIFY_IS_EQUAL(lu.info(), Success); VERIFY_IS_EQUAL(lu.rows(), 0); VERIFY_IS_EQUAL(lu.cols(), 0); } // ---- Per-scalar driver ------------------------------------------------------ template void test_scalar() { CALL_SUBTEST(test_solve(64)); CALL_SUBTEST(test_solve(256)); CALL_SUBTEST(test_multiple_rhs(64, 4)); CALL_SUBTEST(test_refactorize(64)); } EIGEN_DECLARE_TEST(gpu_cudss_lu) { CALL_SUBTEST(test_scalar()); CALL_SUBTEST(test_scalar()); CALL_SUBTEST(test_scalar>()); CALL_SUBTEST(test_scalar>()); CALL_SUBTEST(test_empty()); }