Refactor options checking for linear solvers The code that verifies that the linear solver is configuration specified by the user has grown into a rat's nest. This CL attempts to bring some order to this madness. Fixes https://github.com/ceres-solver/ceres-solver/issues/852 Change-Id: I3f34c0e27da13a6412117dee43ef2d9ec3835b64
diff --git a/internal/ceres/solver.cc b/internal/ceres/solver.cc index 8ad0862..b07d4f0 100644 --- a/internal/ceres/solver.cc +++ b/internal/ceres/solver.cc
@@ -118,37 +118,242 @@ internal::EigenSparse::IsNestedDissectionAvailable())); } -bool MixedPrecisionOptionIsValid(const Solver::Options& options, - string* error) { - if (!options.use_mixed_precision_solves) { - return true; +bool IsIterativeSolver(LinearSolverType type) { + return (type == CGNR || type == ITERATIVE_SCHUR); +} + +bool OptionsAreValidForDenseSolver(const Solver::Options& options, + string* error) { + const char* library_name = DenseLinearAlgebraLibraryTypeToString( + options.dense_linear_algebra_library_type); + const char* solver_name = + LinearSolverTypeToString(options.linear_solver_type); + constexpr char kFormat[] = + "Can't use %s with dense_linear_algebra_library_type = %s " + "because support not enabled when Ceres was built."; + + if (!IsDenseLinearAlgebraLibraryTypeAvailable( + options.dense_linear_algebra_library_type)) { + *error = StringPrintf(kFormat, solver_name, library_name); + return false; + } + return true; +} + +bool OptionsAreValidForSparseCholeskyBasedSolver(const Solver::Options& options, + string* error) { + const char* library_name = SparseLinearAlgebraLibraryTypeToString( + options.sparse_linear_algebra_library_type); + // Sparse factorization based solvers and some preconditioners require a + // sparse Cholesky factorization. + const char* solver_name = + IsIterativeSolver(options.linear_solver_type) + ? PreconditionerTypeToString(options.preconditioner_type) + : LinearSolverTypeToString(options.linear_solver_type); + + constexpr char kNoSparseFormat[] = + "Can't use %s with sparse_linear_algebra_library_type = %s."; + constexpr char kNoLibraryFormat[] = + "Can't use %s sparse_linear_algebra_library_type = %s, because support " + "was not enabled when Ceres Solver was built."; + constexpr char kNoNesdisFormat[] = + "NESDIS is not available with sparse_linear_algebra_library_type = %s."; + constexpr char kMixedFormat[] = + "use_mixed_precision_solves with %s is not supported with " + "sparse_linear_algebra_library_type = %s"; + constexpr char kDynamicSparsityFormat[] = + "dynamic sparsity is not supported with " + "sparse_linear_algebra_library_type = %s"; + + if (options.sparse_linear_algebra_library_type == NO_SPARSE) { + *error = StringPrintf(kNoSparseFormat, solver_name, library_name); + return false; } - // All dense linear algebra backends support mixed precision solves now with - // Cholesky factorization. - if ((options.linear_solver_type == DENSE_NORMAL_CHOLESKY || - options.linear_solver_type == DENSE_SCHUR)) { - return true; + if (!IsSparseLinearAlgebraLibraryTypeAvailable( + options.sparse_linear_algebra_library_type)) { + *error = StringPrintf(kNoLibraryFormat, solver_name, library_name); + return false; } - if ((options.linear_solver_type == SPARSE_NORMAL_CHOLESKY || - options.linear_solver_type == SPARSE_SCHUR)) { - if (options.sparse_linear_algebra_library_type == EIGEN_SPARSE || - options.sparse_linear_algebra_library_type == ACCELERATE_SPARSE) { - // Mixed precision with any Eigen or Accelerate Cholesky variant: okay. - return true; + if (options.linear_solver_ordering_type == ceres::NESDIS && + !IsNestedDissectionAvailable( + options.sparse_linear_algebra_library_type)) { + *error = StringPrintf(kNoNesdisFormat, library_name); + return false; + } + + if (options.use_mixed_precision_solves && + options.sparse_linear_algebra_library_type == SUITE_SPARSE) { + *error = StringPrintf(kMixedFormat, solver_name, library_name); + return false; + } + + if (options.dynamic_sparsity && + options.sparse_linear_algebra_library_type == ACCELERATE_SPARSE) { + *error = StringPrintf(kDynamicSparsityFormat, library_name); + return false; + } + + return true; +} + +bool OptionsAreValidForDenseNormalCholesky(const Solver::Options& options, + string* error) { + CHECK_EQ(options.linear_solver_type, DENSE_NORMAL_CHOLESKY); + return OptionsAreValidForDenseSolver(options, error); +} + +bool OptionsAreValidForDenseQr(const Solver::Options& options, string* error) { + CHECK_EQ(options.linear_solver_type, DENSE_QR); + + if (!OptionsAreValidForDenseSolver(options, error)) { + return false; + } + + if (options.use_mixed_precision_solves) { + *error = "Can't use use_mixed_precision_solves with DENSE_QR."; + return false; + } + + return true; +} + +bool OptionsAreValidForSparseNormalCholesky(const Solver::Options& options, + string* error) { + CHECK_EQ(options.linear_solver_type, SPARSE_NORMAL_CHOLESKY); + return OptionsAreValidForSparseCholeskyBasedSolver(options, error); +} + +bool OptionsAreValidForDenseSchur(const Solver::Options& options, + string* error) { + CHECK_EQ(options.linear_solver_type, DENSE_SCHUR); + + if (options.dynamic_sparsity) { + *error = "dynamic sparsity is only supported with SPARSE_NORMAL_CHOLESKY"; + return false; + } + + if (!OptionsAreValidForDenseSolver(options, error)) { + return false; + } + + return true; +} + +bool OptionsAreValidForSparseSchur(const Solver::Options& options, + string* error) { + CHECK_EQ(options.linear_solver_type, SPARSE_SCHUR); + if (options.dynamic_sparsity) { + *error = "Dynamic sparsity is only supported with SPARSE_NORMAL_CHOLESKY."; + return false; + } + return OptionsAreValidForSparseCholeskyBasedSolver(options, error); +} + +bool OptionsAreValidForIterativeSchur(const Solver::Options& options, + string* error) { + CHECK_EQ(options.linear_solver_type, ITERATIVE_SCHUR); + if (options.dynamic_sparsity) { + *error = "Dynamic sparsity is only supported with SPARSE_NORMAL_CHOLESKY."; + return false; + } + + if (options.use_explicit_schur_complement && + options.preconditioner_type != SCHUR_JACOBI) { + *error = + "use_explicit_schur_complement only supports " + "SCHUR_JACOBI as the preconditioner."; + return false; + } + + if (options.use_mixed_precision_solves) { + *error = "Can't use use_mixed_precision_solves with ITERATIVE_SCHUR"; + return false; + } + + if (options.dynamic_sparsity) { + *error = "Dynamic sparsity is only supported with SPARSE_NORMAL_CHOLESKY."; + return false; + } + + if (options.preconditioner_type == SUBSET) { + *error = "Can't use SUBSET preconditioner with ITERATIVE_SCHUR"; + return false; + } + + // CLUSTER_JACOBI and CLUSTER_TRIDIAGONAL require sparse Cholesky + // factorization. + if (options.preconditioner_type == CLUSTER_JACOBI || + options.preconditioner_type == CLUSTER_TRIDIAGONAL) { + return OptionsAreValidForSparseCholeskyBasedSolver(options, error); + } + + return true; +} + +bool OptionsAreValidForCgnr(const Solver::Options& options, string* error) { + CHECK_EQ(options.linear_solver_type, CGNR); + + if (options.preconditioner_type != IDENTITY && + options.preconditioner_type != JACOBI && + options.preconditioner_type != SUBSET) { + *error = + StringPrintf("Can't use CGNR with preconditioner_type = %s.", + PreconditionerTypeToString(options.preconditioner_type)); + return false; + } + + if (options.use_mixed_precision_solves) { + *error = "use_mixed_precision_solves cannot be used with CGNR"; + return false; + } + + if (options.dynamic_sparsity) { + *error = "Dynamic sparsity is only supported with SPARSE_NORMAL_CHOLESKY."; + return false; + } + + if (options.preconditioner_type == SUBSET) { + if (options.residual_blocks_for_subset_preconditioner.empty()) { + *error = + "When using SUBSET preconditioner, " + "residual_blocks_for_subset_preconditioner cannot be empty"; + return false; } - if (options.sparse_linear_algebra_library_type == SUITE_SPARSE) { - *error = StringPrintf( - "use_mixed_precision_solves with %s is not supported with " - "SUITE_SPARSE as the sparse_linear_algebra_library_type.", - LinearSolverTypeToString(options.linear_solver_type)); + + // SUBSET preconditioner requires sparse Cholesky factorization. + if (!OptionsAreValidForSparseCholeskyBasedSolver(options, error)) { return false; } } - *error = StringPrintf("use_mixed_precision_solves with %s is not supported.", - LinearSolverTypeToString(options.linear_solver_type)); + return true; +} + +bool OptionsAreValidForLinearSolver(const Solver::Options& options, + string* error) { + switch (options.linear_solver_type) { + case DENSE_NORMAL_CHOLESKY: + return OptionsAreValidForDenseNormalCholesky(options, error); + case DENSE_QR: + return OptionsAreValidForDenseQr(options, error); + case SPARSE_NORMAL_CHOLESKY: + return OptionsAreValidForSparseNormalCholesky(options, error); + case DENSE_SCHUR: + return OptionsAreValidForDenseSchur(options, error); + case SPARSE_SCHUR: + return OptionsAreValidForSparseSchur(options, error); + case ITERATIVE_SCHUR: + return OptionsAreValidForIterativeSchur(options, error); + case CGNR: + return OptionsAreValidForCgnr(options, error); + default: + LOG(FATAL) << "Congratulations you have found a bug. Please report " + "this to the " + "Ceres Solver developers. Unknown linear solver type: " + << LinearSolverTypeToString(options.linear_solver_type); + } return false; } @@ -177,106 +382,19 @@ OPTION_GT(max_consecutive_nonmonotonic_steps, 0); } - if (options.linear_solver_type == ITERATIVE_SCHUR && - options.use_explicit_schur_complement && - options.preconditioner_type != SCHUR_JACOBI) { + if ((options.trust_region_strategy_type == DOGLEG) && + IsIterativeSolver(options.linear_solver_type)) { *error = - "use_explicit_schur_complement only supports " - "SCHUR_JACOBI as the preconditioner."; + "DOGLEG only supports exact factorization based linear " + "solvers. If you want to use an iterative solver please " + "use LEVENBERG_MARQUARDT as the trust_region_strategy_type"; return false; } - if (!IsDenseLinearAlgebraLibraryTypeAvailable( - options.dense_linear_algebra_library_type) && - (options.linear_solver_type == DENSE_NORMAL_CHOLESKY || - options.linear_solver_type == DENSE_QR || - options.linear_solver_type == DENSE_SCHUR)) { - *error = StringPrintf( - "Can't use %s with " - "Solver::Options::dense_linear_algebra_library_type = %s " - "because %s was not enabled when Ceres was built.", - LinearSolverTypeToString(options.linear_solver_type), - DenseLinearAlgebraLibraryTypeToString( - options.dense_linear_algebra_library_type), - DenseLinearAlgebraLibraryTypeToString( - options.dense_linear_algebra_library_type)); + if (!OptionsAreValidForLinearSolver(options, error)) { return false; } - { - const char* sparse_linear_algebra_library_name = - SparseLinearAlgebraLibraryTypeToString( - options.sparse_linear_algebra_library_type); - const char* name = nullptr; - if (options.linear_solver_type == SPARSE_NORMAL_CHOLESKY || - options.linear_solver_type == SPARSE_SCHUR) { - name = LinearSolverTypeToString(options.linear_solver_type); - } else if ((options.linear_solver_type == ITERATIVE_SCHUR && - (options.preconditioner_type == CLUSTER_JACOBI || - options.preconditioner_type == CLUSTER_TRIDIAGONAL)) || - (options.linear_solver_type == CGNR && - options.preconditioner_type == SUBSET)) { - name = PreconditionerTypeToString(options.preconditioner_type); - } - - if (name) { - if (options.sparse_linear_algebra_library_type == NO_SPARSE) { - *error = StringPrintf( - "Can't use %s with " - "Solver::Options::sparse_linear_algebra_library_type = %s.", - name, - sparse_linear_algebra_library_name); - return false; - } - - if (!IsSparseLinearAlgebraLibraryTypeAvailable( - options.sparse_linear_algebra_library_type)) { - *error = StringPrintf( - "Can't use %s with " - "Solver::Options::sparse_linear_algebra_library_type = %s, " - "because support was not enabled when Ceres Solver was built.", - name, - sparse_linear_algebra_library_name); - return false; - } - - if (options.linear_solver_ordering_type == ceres::NESDIS && - !IsNestedDissectionAvailable( - options.sparse_linear_algebra_library_type)) { - if (options.sparse_linear_algebra_library_type == SUITE_SPARSE) { - *error = StringPrintf( - "Can't use NESDIS with SUITE_SPARSE because SuiteSparse was " - "compiled without support for Metis."); - } else if (options.sparse_linear_algebra_library_type == EIGEN_SPARSE) { - *error = StringPrintf( - "Can't use NESDIS with EIGEN_SPARSE because Ceres was " - "compiled without support for Metis."); - } else { - *error = StringPrintf( - "Can't use NESDIS with " - "Solver::Options::sparse_linear_algebra_library_type = %s.", - sparse_linear_algebra_library_name); - } - return false; - } - } - } - - if (!MixedPrecisionOptionIsValid(options, error)) { - return false; - } - - if (options.trust_region_strategy_type == DOGLEG) { - if (options.linear_solver_type == ITERATIVE_SCHUR || - options.linear_solver_type == CGNR) { - *error = - "DOGLEG only supports exact factorization based linear " - "solvers. If you want to use an iterative solver please " - "use LEVENBERG_MARQUARDT as the trust_region_strategy_type"; - return false; - } - } - if (!options.trust_region_minimizer_iterations_to_dump.empty() && options.trust_region_problem_dump_format_type != CONSOLE && options.trust_region_problem_dump_directory.empty()) { @@ -284,31 +402,6 @@ return false; } - if (options.dynamic_sparsity) { - if (options.linear_solver_type != SPARSE_NORMAL_CHOLESKY) { - *error = - "Dynamic sparsity is only supported with SPARSE_NORMAL_CHOLESKY."; - return false; - } - if (options.sparse_linear_algebra_library_type == ACCELERATE_SPARSE) { - *error = - "ACCELERATE_SPARSE is not currently supported with dynamic " - "sparsity."; - return false; - } - } - - if (options.linear_solver_type == CGNR && - options.preconditioner_type == SUBSET && - options.residual_blocks_for_subset_preconditioner.empty()) { - *error = - "When using SUBSET preconditioner, " - "Solver::Options::residual_blocks_for_subset_preconditioner cannot " - "be " - "empty"; - return false; - } - return true; } @@ -785,8 +878,7 @@ LinearSolverTypeToString(linear_solver_type_given), LinearSolverTypeToString(linear_solver_type_used)); - if (linear_solver_type_given == CGNR || - linear_solver_type_given == ITERATIVE_SCHUR) { + if (IsIterativeSolver(linear_solver_type_given)) { StringAppendF(&report, "Preconditioner %25s%25s\n", PreconditionerTypeToString(preconditioner_type_given),
diff --git a/internal/ceres/solver_test.cc b/internal/ceres/solver_test.cc index 5abd723..1b61b18 100644 --- a/internal/ceres/solver_test.cc +++ b/internal/ceres/solver_test.cc
@@ -312,160 +312,6 @@ EXPECT_EQ(summary.final_cost, 1.0 / 2.0); } -#if defined(CERES_NO_SUITESPARSE) -TEST(Solver, SparseNormalCholeskyNoSuiteSparse) { - Solver::Options options; - options.sparse_linear_algebra_library_type = SUITE_SPARSE; - options.linear_solver_type = SPARSE_NORMAL_CHOLESKY; - string message; - EXPECT_FALSE(options.IsValid(&message)); -} - -TEST(Solver, SparseSchurNoSuiteSparse) { - Solver::Options options; - options.sparse_linear_algebra_library_type = SUITE_SPARSE; - options.linear_solver_type = SPARSE_SCHUR; - string message; - EXPECT_FALSE(options.IsValid(&message)); -} -#endif - -#if defined(CERES_NO_CXSPARSE) -TEST(Solver, SparseNormalCholeskyNoCXSparse) { - Solver::Options options; - options.sparse_linear_algebra_library_type = CX_SPARSE; - options.linear_solver_type = SPARSE_NORMAL_CHOLESKY; - string message; - EXPECT_FALSE(options.IsValid(&message)); -} - -TEST(Solver, SparseSchurNoCXSparse) { - Solver::Options options; - options.sparse_linear_algebra_library_type = CX_SPARSE; - options.linear_solver_type = SPARSE_SCHUR; - string message; - EXPECT_FALSE(options.IsValid(&message)); -} -#endif - -#if defined(CERES_NO_ACCELERATE_SPARSE) -TEST(Solver, SparseNormalCholeskyNoAccelerateSparse) { - Solver::Options options; - options.sparse_linear_algebra_library_type = ACCELERATE_SPARSE; - options.linear_solver_type = SPARSE_NORMAL_CHOLESKY; - string message; - EXPECT_FALSE(options.IsValid(&message)); -} - -TEST(Solver, SparseSchurNoAccelerateSparse) { - Solver::Options options; - options.sparse_linear_algebra_library_type = ACCELERATE_SPARSE; - options.linear_solver_type = SPARSE_SCHUR; - string message; - EXPECT_FALSE(options.IsValid(&message)); -} -#else -TEST(Solver, DynamicSparseNormalCholeskyUnsupportedWithAccelerateSparse) { - Solver::Options options; - options.sparse_linear_algebra_library_type = ACCELERATE_SPARSE; - options.linear_solver_type = SPARSE_NORMAL_CHOLESKY; - options.dynamic_sparsity = true; - string message; - EXPECT_FALSE(options.IsValid(&message)); -} -#endif - -#if !defined(CERES_USE_EIGEN_SPARSE) -TEST(Solver, SparseNormalCholeskyNoEigenSparse) { - Solver::Options options; - options.sparse_linear_algebra_library_type = EIGEN_SPARSE; - options.linear_solver_type = SPARSE_NORMAL_CHOLESKY; - string message; - EXPECT_FALSE(options.IsValid(&message)); -} - -TEST(Solver, SparseSchurNoEigenSparse) { - Solver::Options options; - options.sparse_linear_algebra_library_type = EIGEN_SPARSE; - options.linear_solver_type = SPARSE_SCHUR; - string message; - EXPECT_FALSE(options.IsValid(&message)); -} -#endif - -TEST(Solver, SparseNormalCholeskyNoSparseLibrary) { - Solver::Options options; - options.sparse_linear_algebra_library_type = NO_SPARSE; - options.linear_solver_type = SPARSE_NORMAL_CHOLESKY; - string message; - EXPECT_FALSE(options.IsValid(&message)); -} - -TEST(Solver, SparseSchurNoSparseLibrary) { - Solver::Options options; - options.sparse_linear_algebra_library_type = NO_SPARSE; - options.linear_solver_type = SPARSE_SCHUR; - string message; - EXPECT_FALSE(options.IsValid(&message)); -} - -TEST(Solver, IterativeSchurWithClusterJacobiPerconditionerNoSparseLibrary) { - Solver::Options options; - options.sparse_linear_algebra_library_type = NO_SPARSE; - options.linear_solver_type = ITERATIVE_SCHUR; - // Requires SuiteSparse. - options.preconditioner_type = CLUSTER_JACOBI; - string message; - EXPECT_FALSE(options.IsValid(&message)); -} - -TEST(Solver, - IterativeSchurWithClusterTridiagonalPerconditionerNoSparseLibrary) { - Solver::Options options; - options.sparse_linear_algebra_library_type = NO_SPARSE; - options.linear_solver_type = ITERATIVE_SCHUR; - // Requires SuiteSparse. - options.preconditioner_type = CLUSTER_TRIDIAGONAL; - string message; - EXPECT_FALSE(options.IsValid(&message)); -} - -TEST(Solver, IterativeLinearSolverForDogleg) { - Solver::Options options; - options.trust_region_strategy_type = DOGLEG; - string message; - options.linear_solver_type = ITERATIVE_SCHUR; - EXPECT_FALSE(options.IsValid(&message)); - - options.linear_solver_type = CGNR; - EXPECT_FALSE(options.IsValid(&message)); -} - -TEST(Solver, LinearSolverTypeNormalOperation) { - Solver::Options options; - options.linear_solver_type = DENSE_QR; - - string message; - EXPECT_TRUE(options.IsValid(&message)); - - options.linear_solver_type = DENSE_NORMAL_CHOLESKY; - EXPECT_TRUE(options.IsValid(&message)); - - options.linear_solver_type = DENSE_SCHUR; - EXPECT_TRUE(options.IsValid(&message)); - - options.linear_solver_type = SPARSE_SCHUR; -#if defined(CERES_NO_SUITESPARSE) && defined(CERES_NO_CXSPARSE) && \ - !defined(CERES_USE_EIGEN_SPARSE) - EXPECT_FALSE(options.IsValid(&message)); -#else - EXPECT_TRUE(options.IsValid(&message)); -#endif - - options.linear_solver_type = ITERATIVE_SCHUR; - EXPECT_TRUE(options.IsValid(&message)); -} - template <int kNumResiduals, int... Ns> class DummyCostFunction : public SizedCostFunction<kNumResiduals, Ns...> { public: @@ -529,4 +375,793 @@ EXPECT_EQ(y, 1.0); } +TEST(Solver, DenseNormalCholeskyOptions) { + std::string message; + Solver::Options options; + options.linear_solver_type = DENSE_NORMAL_CHOLESKY; + EXPECT_TRUE(options.IsValid(&message)); + + options.dense_linear_algebra_library_type = EIGEN; + options.use_mixed_precision_solves = false; + EXPECT_TRUE(options.IsValid(&message)); + + options.use_mixed_precision_solves = true; + EXPECT_TRUE(options.IsValid(&message)); + + if (IsDenseLinearAlgebraLibraryTypeAvailable(LAPACK)) { + options.use_mixed_precision_solves = false; + options.dense_linear_algebra_library_type = LAPACK; + + EXPECT_TRUE(options.IsValid(&message)); + options.use_mixed_precision_solves = true; + EXPECT_TRUE(options.IsValid(&message)); + } else { + options.use_mixed_precision_solves = false; + options.dense_linear_algebra_library_type = LAPACK; + EXPECT_FALSE(options.IsValid(&message)); + } +} + +TEST(Solver, DenseQrOptions) { + std::string message; + Solver::Options options; + options.linear_solver_type = DENSE_QR; + + options.use_mixed_precision_solves = false; + options.dense_linear_algebra_library_type = EIGEN; + EXPECT_TRUE(options.IsValid(&message)); + + options.use_mixed_precision_solves = true; + EXPECT_FALSE(options.IsValid(&message)); + + if (IsDenseLinearAlgebraLibraryTypeAvailable(LAPACK)) { + options.use_mixed_precision_solves = false; + options.dense_linear_algebra_library_type = LAPACK; + EXPECT_TRUE(options.IsValid(&message)); + options.use_mixed_precision_solves = true; + EXPECT_FALSE(options.IsValid(&message)); + } else { + options.use_mixed_precision_solves = false; + options.dense_linear_algebra_library_type = LAPACK; + EXPECT_FALSE(options.IsValid(&message)); + } +} + +TEST(Solver, SparseNormalCholeskyOptionsNoSparse) { + std::string message; + Solver::Options options; + options.linear_solver_type = SPARSE_NORMAL_CHOLESKY; + options.sparse_linear_algebra_library_type = NO_SPARSE; + EXPECT_FALSE(options.IsValid(&message)); +} + +TEST(Solver, SparseNormalCholeskyOptionsEigenSparse) { + std::string message; + Solver::Options options; + options.linear_solver_type = SPARSE_NORMAL_CHOLESKY; + options.sparse_linear_algebra_library_type = EIGEN_SPARSE; + options.linear_solver_ordering_type = AMD; + + options.use_mixed_precision_solves = false; + options.dynamic_sparsity = false; + if (IsSparseLinearAlgebraLibraryTypeAvailable(EIGEN_SPARSE)) { + EXPECT_TRUE(options.IsValid(&message)); + } else { + EXPECT_FALSE(options.IsValid(&message)); + } + + if (IsSparseLinearAlgebraLibraryTypeAvailable(EIGEN_SPARSE)) { + options.use_mixed_precision_solves = true; + options.dynamic_sparsity = false; + EXPECT_TRUE(options.IsValid(&message)); + + options.use_mixed_precision_solves = false; + options.dynamic_sparsity = true; + EXPECT_TRUE(options.IsValid(&message)); + + options.use_mixed_precision_solves = true; + options.dynamic_sparsity = true; + EXPECT_TRUE(options.IsValid(&message)); + } + +#ifndef CERES_NO_EIGEN_METIS + options.linear_solver_ordering_type = NESDIS; + if (IsSparseLinearAlgebraLibraryTypeAvailable(EIGEN_SPARSE)) { + options.use_mixed_precision_solves = false; + options.dynamic_sparsity = false; + EXPECT_TRUE(options.IsValid(&message)); + + options.use_mixed_precision_solves = true; + options.dynamic_sparsity = false; + EXPECT_TRUE(options.IsValid(&message)); + + options.use_mixed_precision_solves = false; + options.dynamic_sparsity = true; + EXPECT_TRUE(options.IsValid(&message)); + + options.use_mixed_precision_solves = true; + options.dynamic_sparsity = true; + EXPECT_TRUE(options.IsValid(&message)); + } +#else + options.linear_solver_ordering_type = NESDIS; + options.use_mixed_precision_solves = false; + options.dynamic_sparsity = false; + EXPECT_FALSE(options.IsValid(&message)); +#endif +} + +TEST(Solver, SparseNormalCholeskyOptionsSuiteSparse) { + std::string message; + Solver::Options options; + options.linear_solver_type = SPARSE_NORMAL_CHOLESKY; + options.sparse_linear_algebra_library_type = SUITE_SPARSE; + options.linear_solver_ordering_type = AMD; + + options.use_mixed_precision_solves = false; + options.dynamic_sparsity = false; + if (IsSparseLinearAlgebraLibraryTypeAvailable( + options.sparse_linear_algebra_library_type)) { + EXPECT_TRUE(options.IsValid(&message)); + } else { + EXPECT_FALSE(options.IsValid(&message)); + } + + if (IsSparseLinearAlgebraLibraryTypeAvailable( + options.sparse_linear_algebra_library_type)) { + options.use_mixed_precision_solves = true; + options.dynamic_sparsity = false; + EXPECT_FALSE(options.IsValid(&message)); + + options.use_mixed_precision_solves = false; + options.dynamic_sparsity = true; + EXPECT_TRUE(options.IsValid(&message)); + + options.use_mixed_precision_solves = true; + options.dynamic_sparsity = true; + EXPECT_FALSE(options.IsValid(&message)); + } + +#ifndef CERES_NO_CHOLMOD_PARTITION + options.linear_solver_ordering_type = NESDIS; + if (IsSparseLinearAlgebraLibraryTypeAvailable( + options.sparse_linear_algebra_library_type)) { + options.use_mixed_precision_solves = false; + options.dynamic_sparsity = false; + EXPECT_TRUE(options.IsValid(&message)); + + options.use_mixed_precision_solves = true; + options.dynamic_sparsity = false; + EXPECT_FALSE(options.IsValid(&message)); + + options.use_mixed_precision_solves = false; + options.dynamic_sparsity = true; + EXPECT_TRUE(options.IsValid(&message)); + + options.use_mixed_precision_solves = true; + options.dynamic_sparsity = true; + EXPECT_FALSE(options.IsValid(&message)); + } +#else + options.linear_solver_ordering_type = NESDIS; + options.use_mixed_precision_solves = false; + options.dynamic_sparsity = false; + EXPECT_FALSE(options.IsValid(&message)); +#endif +} + +TEST(Solver, SparseNormalCholeskyOptionsAccelerateSparse) { + std::string message; + Solver::Options options; + options.linear_solver_type = SPARSE_NORMAL_CHOLESKY; + options.sparse_linear_algebra_library_type = ACCELERATE_SPARSE; + options.linear_solver_ordering_type = AMD; + + options.use_mixed_precision_solves = false; + options.dynamic_sparsity = false; + if (IsSparseLinearAlgebraLibraryTypeAvailable( + options.sparse_linear_algebra_library_type)) { + EXPECT_TRUE(options.IsValid(&message)); + } else { + EXPECT_FALSE(options.IsValid(&message)); + } + + if (IsSparseLinearAlgebraLibraryTypeAvailable( + options.sparse_linear_algebra_library_type)) { + options.use_mixed_precision_solves = true; + options.dynamic_sparsity = false; + EXPECT_TRUE(options.IsValid(&message)); + + options.use_mixed_precision_solves = false; + options.dynamic_sparsity = true; + EXPECT_FALSE(options.IsValid(&message)); + + options.use_mixed_precision_solves = true; + options.dynamic_sparsity = true; + EXPECT_FALSE(options.IsValid(&message)); + } + + options.linear_solver_ordering_type = NESDIS; + if (IsSparseLinearAlgebraLibraryTypeAvailable( + options.sparse_linear_algebra_library_type)) { + options.use_mixed_precision_solves = false; + options.dynamic_sparsity = false; + EXPECT_TRUE(options.IsValid(&message)); + + options.use_mixed_precision_solves = true; + options.dynamic_sparsity = false; + EXPECT_TRUE(options.IsValid(&message)); + + options.use_mixed_precision_solves = false; + options.dynamic_sparsity = true; + EXPECT_FALSE(options.IsValid(&message)); + + options.use_mixed_precision_solves = true; + options.dynamic_sparsity = true; + EXPECT_FALSE(options.IsValid(&message)); + } +} + +TEST(Solver, DenseSchurOptions) { + std::string message; + Solver::Options options; + options.linear_solver_type = DENSE_SCHUR; + options.dense_linear_algebra_library_type = EIGEN; + + options.use_mixed_precision_solves = false; + options.dynamic_sparsity = false; + EXPECT_TRUE(options.IsValid(&message)); + + options.use_mixed_precision_solves = true; + options.dynamic_sparsity = false; + EXPECT_TRUE(options.IsValid(&message)); + + options.use_mixed_precision_solves = true; + options.dynamic_sparsity = true; + EXPECT_FALSE(options.IsValid(&message)); + + options.use_mixed_precision_solves = false; + options.dynamic_sparsity = true; + EXPECT_FALSE(options.IsValid(&message)); + + options.dense_linear_algebra_library_type = LAPACK; + if (IsDenseLinearAlgebraLibraryTypeAvailable( + options.dense_linear_algebra_library_type)) { + options.use_mixed_precision_solves = false; + options.dynamic_sparsity = false; + EXPECT_TRUE(options.IsValid(&message)); + + options.use_mixed_precision_solves = true; + options.dynamic_sparsity = false; + EXPECT_TRUE(options.IsValid(&message)); + + options.use_mixed_precision_solves = true; + options.dynamic_sparsity = true; + EXPECT_FALSE(options.IsValid(&message)); + + options.use_mixed_precision_solves = false; + options.dynamic_sparsity = true; + EXPECT_FALSE(options.IsValid(&message)); + } +} + +TEST(Solver, SparseSchurOptionsNoSparse) { + std::string message; + Solver::Options options; + options.linear_solver_type = SPARSE_SCHUR; + options.sparse_linear_algebra_library_type = NO_SPARSE; + EXPECT_FALSE(options.IsValid(&message)); +} + +TEST(Solver, SparseSchurOptionsEigenSparse) { + std::string message; + Solver::Options options; + options.linear_solver_type = SPARSE_SCHUR; + options.sparse_linear_algebra_library_type = EIGEN_SPARSE; + options.linear_solver_ordering_type = AMD; + + options.use_mixed_precision_solves = false; + options.dynamic_sparsity = false; + if (IsSparseLinearAlgebraLibraryTypeAvailable(EIGEN_SPARSE)) { + EXPECT_TRUE(options.IsValid(&message)); + } else { + EXPECT_FALSE(options.IsValid(&message)); + } + + if (IsSparseLinearAlgebraLibraryTypeAvailable(EIGEN_SPARSE)) { + options.use_mixed_precision_solves = true; + options.dynamic_sparsity = false; + EXPECT_TRUE(options.IsValid(&message)); + + options.use_mixed_precision_solves = false; + options.dynamic_sparsity = true; + EXPECT_FALSE(options.IsValid(&message)); + + options.use_mixed_precision_solves = true; + options.dynamic_sparsity = true; + EXPECT_FALSE(options.IsValid(&message)); + } + +#ifndef CERES_NO_EIGEN_METIS + options.linear_solver_ordering_type = NESDIS; + if (IsSparseLinearAlgebraLibraryTypeAvailable(EIGEN_SPARSE)) { + options.use_mixed_precision_solves = false; + options.dynamic_sparsity = false; + EXPECT_TRUE(options.IsValid(&message)); + + options.use_mixed_precision_solves = true; + options.dynamic_sparsity = false; + EXPECT_TRUE(options.IsValid(&message)); + + options.use_mixed_precision_solves = false; + options.dynamic_sparsity = true; + EXPECT_FALSE(options.IsValid(&message)); + + options.use_mixed_precision_solves = true; + options.dynamic_sparsity = true; + EXPECT_FALSE(options.IsValid(&message)); + } +#else + options.linear_solver_ordering_type = NESDIS; + options.use_mixed_precision_solves = false; + options.dynamic_sparsity = false; + EXPECT_FALSE(options.IsValid(&message)); +#endif +} + +TEST(Solver, SparseSchurOptionsSuiteSparse) { + std::string message; + Solver::Options options; + options.linear_solver_type = SPARSE_SCHUR; + options.sparse_linear_algebra_library_type = SUITE_SPARSE; + options.linear_solver_ordering_type = AMD; + + options.use_mixed_precision_solves = false; + options.dynamic_sparsity = false; + if (IsSparseLinearAlgebraLibraryTypeAvailable( + options.sparse_linear_algebra_library_type)) { + EXPECT_TRUE(options.IsValid(&message)); + } else { + EXPECT_FALSE(options.IsValid(&message)); + } + + if (IsSparseLinearAlgebraLibraryTypeAvailable( + options.sparse_linear_algebra_library_type)) { + options.use_mixed_precision_solves = true; + options.dynamic_sparsity = false; + EXPECT_FALSE(options.IsValid(&message)); + + options.use_mixed_precision_solves = false; + options.dynamic_sparsity = true; + EXPECT_FALSE(options.IsValid(&message)); + + options.use_mixed_precision_solves = true; + options.dynamic_sparsity = true; + EXPECT_FALSE(options.IsValid(&message)); + } + +#ifndef CERES_NO_CHOLMOD_PARTITION + options.linear_solver_ordering_type = NESDIS; + if (IsSparseLinearAlgebraLibraryTypeAvailable( + options.sparse_linear_algebra_library_type)) { + options.use_mixed_precision_solves = false; + options.dynamic_sparsity = false; + EXPECT_TRUE(options.IsValid(&message)); + + options.use_mixed_precision_solves = true; + options.dynamic_sparsity = false; + EXPECT_FALSE(options.IsValid(&message)); + + options.use_mixed_precision_solves = false; + options.dynamic_sparsity = true; + EXPECT_FALSE(options.IsValid(&message)); + + options.use_mixed_precision_solves = true; + options.dynamic_sparsity = true; + EXPECT_FALSE(options.IsValid(&message)); + } +#else + options.linear_solver_ordering_type = NESDIS; + options.use_mixed_precision_solves = false; + options.dynamic_sparsity = false; + EXPECT_FALSE(options.IsValid(&message)); +#endif +} + +TEST(Solver, SparseSchurOptionsAccelerateSparse) { + std::string message; + Solver::Options options; + options.linear_solver_type = SPARSE_SCHUR; + options.sparse_linear_algebra_library_type = ACCELERATE_SPARSE; + options.linear_solver_ordering_type = AMD; + + options.use_mixed_precision_solves = false; + options.dynamic_sparsity = false; + if (IsSparseLinearAlgebraLibraryTypeAvailable( + options.sparse_linear_algebra_library_type)) { + EXPECT_TRUE(options.IsValid(&message)); + } else { + EXPECT_FALSE(options.IsValid(&message)); + } + + if (IsSparseLinearAlgebraLibraryTypeAvailable( + options.sparse_linear_algebra_library_type)) { + options.use_mixed_precision_solves = true; + options.dynamic_sparsity = false; + EXPECT_TRUE(options.IsValid(&message)); + + options.use_mixed_precision_solves = false; + options.dynamic_sparsity = true; + EXPECT_FALSE(options.IsValid(&message)); + + options.use_mixed_precision_solves = true; + options.dynamic_sparsity = true; + EXPECT_FALSE(options.IsValid(&message)); + } + + options.linear_solver_ordering_type = NESDIS; + if (IsSparseLinearAlgebraLibraryTypeAvailable( + options.sparse_linear_algebra_library_type)) { + options.use_mixed_precision_solves = false; + options.dynamic_sparsity = false; + EXPECT_TRUE(options.IsValid(&message)); + + options.use_mixed_precision_solves = true; + options.dynamic_sparsity = false; + EXPECT_TRUE(options.IsValid(&message)); + + options.use_mixed_precision_solves = false; + options.dynamic_sparsity = true; + EXPECT_FALSE(options.IsValid(&message)); + + options.use_mixed_precision_solves = true; + options.dynamic_sparsity = true; + EXPECT_FALSE(options.IsValid(&message)); + } +} + +TEST(Solver, CgnrOptionsIdentityPreconditioner) { + std::string message; + Solver::Options options; + options.linear_solver_type = CGNR; + options.preconditioner_type = IDENTITY; + options.sparse_linear_algebra_library_type = NO_SPARSE; + + options.dynamic_sparsity = false; + options.use_mixed_precision_solves = false; + EXPECT_TRUE(options.IsValid(&message)); + + options.dynamic_sparsity = true; + options.use_mixed_precision_solves = false; + EXPECT_FALSE(options.IsValid(&message)); + + options.dynamic_sparsity = false; + options.use_mixed_precision_solves = true; + EXPECT_FALSE(options.IsValid(&message)); + + options.sparse_linear_algebra_library_type = EIGEN_SPARSE; + if (IsSparseLinearAlgebraLibraryTypeAvailable( + options.sparse_linear_algebra_library_type)) { + options.dynamic_sparsity = false; + options.use_mixed_precision_solves = false; + EXPECT_TRUE(options.IsValid(&message)); + + options.dynamic_sparsity = true; + options.use_mixed_precision_solves = false; + EXPECT_FALSE(options.IsValid(&message)); + + options.dynamic_sparsity = false; + options.use_mixed_precision_solves = true; + EXPECT_FALSE(options.IsValid(&message)); + } + + options.sparse_linear_algebra_library_type = SUITE_SPARSE; + if (IsSparseLinearAlgebraLibraryTypeAvailable( + options.sparse_linear_algebra_library_type)) { + options.dynamic_sparsity = false; + options.use_mixed_precision_solves = false; + EXPECT_TRUE(options.IsValid(&message)); + + options.dynamic_sparsity = true; + options.use_mixed_precision_solves = false; + EXPECT_FALSE(options.IsValid(&message)); + + options.dynamic_sparsity = false; + options.use_mixed_precision_solves = true; + EXPECT_FALSE(options.IsValid(&message)); + } + + options.sparse_linear_algebra_library_type = ACCELERATE_SPARSE; + if (IsSparseLinearAlgebraLibraryTypeAvailable( + options.sparse_linear_algebra_library_type)) { + options.dynamic_sparsity = false; + options.use_mixed_precision_solves = false; + EXPECT_TRUE(options.IsValid(&message)); + + options.dynamic_sparsity = true; + options.use_mixed_precision_solves = false; + EXPECT_FALSE(options.IsValid(&message)); + + options.dynamic_sparsity = false; + options.use_mixed_precision_solves = true; + EXPECT_FALSE(options.IsValid(&message)); + } +} + +TEST(Solver, CgnrOptionsJacobiPreconditioner) { + std::string message; + Solver::Options options; + options.linear_solver_type = CGNR; + options.preconditioner_type = JACOBI; + options.sparse_linear_algebra_library_type = NO_SPARSE; + + options.dynamic_sparsity = false; + options.use_mixed_precision_solves = false; + EXPECT_TRUE(options.IsValid(&message)); + + options.dynamic_sparsity = true; + options.use_mixed_precision_solves = false; + EXPECT_FALSE(options.IsValid(&message)); + + options.dynamic_sparsity = false; + options.use_mixed_precision_solves = true; + EXPECT_FALSE(options.IsValid(&message)); + + options.sparse_linear_algebra_library_type = EIGEN_SPARSE; + + options.dynamic_sparsity = false; + options.use_mixed_precision_solves = false; + EXPECT_TRUE(options.IsValid(&message)); + + options.dynamic_sparsity = true; + options.use_mixed_precision_solves = false; + EXPECT_FALSE(options.IsValid(&message)); + + options.dynamic_sparsity = false; + options.use_mixed_precision_solves = true; + EXPECT_FALSE(options.IsValid(&message)); + + options.sparse_linear_algebra_library_type = SUITE_SPARSE; + + options.dynamic_sparsity = false; + options.use_mixed_precision_solves = false; + EXPECT_TRUE(options.IsValid(&message)); + + options.dynamic_sparsity = true; + options.use_mixed_precision_solves = false; + EXPECT_FALSE(options.IsValid(&message)); + + options.dynamic_sparsity = false; + options.use_mixed_precision_solves = true; + EXPECT_FALSE(options.IsValid(&message)); + + options.sparse_linear_algebra_library_type = ACCELERATE_SPARSE; + + options.dynamic_sparsity = false; + options.use_mixed_precision_solves = false; + EXPECT_TRUE(options.IsValid(&message)); + + options.dynamic_sparsity = true; + options.use_mixed_precision_solves = false; + EXPECT_FALSE(options.IsValid(&message)); + + options.dynamic_sparsity = false; + options.use_mixed_precision_solves = true; + EXPECT_FALSE(options.IsValid(&message)); +} + +TEST(Solver, CgnrOptionsSubsetPreconditioner) { + std::string message; + Solver::Options options; + options.linear_solver_type = CGNR; + options.preconditioner_type = SUBSET; + + options.sparse_linear_algebra_library_type = NO_SPARSE; + EXPECT_FALSE(options.IsValid(&message)); + options.residual_blocks_for_subset_preconditioner.insert(nullptr); + EXPECT_FALSE(options.IsValid(&message)); + + options.dynamic_sparsity = false; + options.use_mixed_precision_solves = false; + EXPECT_FALSE(options.IsValid(&message)); + + options.dynamic_sparsity = true; + options.use_mixed_precision_solves = false; + EXPECT_FALSE(options.IsValid(&message)); + + options.dynamic_sparsity = false; + options.use_mixed_precision_solves = true; + EXPECT_FALSE(options.IsValid(&message)); + + options.sparse_linear_algebra_library_type = EIGEN_SPARSE; + + options.dynamic_sparsity = false; + options.use_mixed_precision_solves = false; + EXPECT_TRUE(options.IsValid(&message)); + + options.dynamic_sparsity = true; + options.use_mixed_precision_solves = false; + EXPECT_FALSE(options.IsValid(&message)); + + options.dynamic_sparsity = false; + options.use_mixed_precision_solves = true; + EXPECT_FALSE(options.IsValid(&message)); + + options.sparse_linear_algebra_library_type = SUITE_SPARSE; + + options.dynamic_sparsity = false; + options.use_mixed_precision_solves = false; + EXPECT_TRUE(options.IsValid(&message)); + + options.dynamic_sparsity = true; + options.use_mixed_precision_solves = false; + EXPECT_FALSE(options.IsValid(&message)); + + options.dynamic_sparsity = false; + options.use_mixed_precision_solves = true; + EXPECT_FALSE(options.IsValid(&message)); + + options.sparse_linear_algebra_library_type = ACCELERATE_SPARSE; + + options.dynamic_sparsity = false; + options.use_mixed_precision_solves = false; + EXPECT_TRUE(options.IsValid(&message)); + + options.dynamic_sparsity = true; + options.use_mixed_precision_solves = false; + EXPECT_FALSE(options.IsValid(&message)); + + options.dynamic_sparsity = false; + options.use_mixed_precision_solves = true; + EXPECT_FALSE(options.IsValid(&message)); +} + +TEST(Solver, CgnrOptionsSchurPreconditioners) { + std::string message; + Solver::Options options; + options.linear_solver_type = CGNR; + options.preconditioner_type = SCHUR_JACOBI; + EXPECT_FALSE(options.IsValid(&message)); + options.preconditioner_type = CLUSTER_JACOBI; + EXPECT_FALSE(options.IsValid(&message)); + options.preconditioner_type = CLUSTER_TRIDIAGONAL; + EXPECT_FALSE(options.IsValid(&message)); +} + +TEST(Solver, IterativeSchurOptionsNoSparse) { + std::string message; + Solver::Options options; + options.linear_solver_type = ITERATIVE_SCHUR; + options.sparse_linear_algebra_library_type = NO_SPARSE; + options.preconditioner_type = IDENTITY; + EXPECT_TRUE(options.IsValid(&message)); + options.preconditioner_type = JACOBI; + EXPECT_TRUE(options.IsValid(&message)); + options.preconditioner_type = SCHUR_JACOBI; + EXPECT_TRUE(options.IsValid(&message)); + options.preconditioner_type = CLUSTER_JACOBI; + EXPECT_FALSE(options.IsValid(&message)); + options.preconditioner_type = CLUSTER_TRIDIAGONAL; + EXPECT_FALSE(options.IsValid(&message)); + options.preconditioner_type = SUBSET; + EXPECT_FALSE(options.IsValid(&message)); + + options.use_explicit_schur_complement = true; + options.preconditioner_type = IDENTITY; + EXPECT_FALSE(options.IsValid(&message)); + options.preconditioner_type = JACOBI; + EXPECT_FALSE(options.IsValid(&message)); + options.preconditioner_type = SCHUR_JACOBI; + EXPECT_TRUE(options.IsValid(&message)); + options.preconditioner_type = CLUSTER_JACOBI; + EXPECT_FALSE(options.IsValid(&message)); + options.preconditioner_type = CLUSTER_TRIDIAGONAL; + EXPECT_FALSE(options.IsValid(&message)); +} + +TEST(Solver, IterativeSchurOptionsEigenSparse) { + std::string message; + Solver::Options options; + options.linear_solver_type = ITERATIVE_SCHUR; + options.sparse_linear_algebra_library_type = EIGEN_SPARSE; + options.preconditioner_type = IDENTITY; + EXPECT_TRUE(options.IsValid(&message)); + options.preconditioner_type = JACOBI; + EXPECT_TRUE(options.IsValid(&message)); + options.preconditioner_type = SCHUR_JACOBI; + EXPECT_TRUE(options.IsValid(&message)); + options.preconditioner_type = CLUSTER_JACOBI; + EXPECT_EQ(options.IsValid(&message), + IsSparseLinearAlgebraLibraryTypeAvailable( + options.sparse_linear_algebra_library_type)); + options.preconditioner_type = CLUSTER_TRIDIAGONAL; + EXPECT_EQ(options.IsValid(&message), + IsSparseLinearAlgebraLibraryTypeAvailable( + options.sparse_linear_algebra_library_type)); + options.preconditioner_type = SUBSET; + EXPECT_FALSE(options.IsValid(&message)); + + options.use_explicit_schur_complement = true; + options.preconditioner_type = IDENTITY; + EXPECT_FALSE(options.IsValid(&message)); + options.preconditioner_type = JACOBI; + EXPECT_FALSE(options.IsValid(&message)); + options.preconditioner_type = SCHUR_JACOBI; + EXPECT_TRUE(options.IsValid(&message)); + options.preconditioner_type = CLUSTER_JACOBI; + EXPECT_FALSE(options.IsValid(&message)); + options.preconditioner_type = CLUSTER_TRIDIAGONAL; + EXPECT_FALSE(options.IsValid(&message)); +} + +TEST(Solver, IterativeSchurOptionsSuiteSparse) { + std::string message; + Solver::Options options; + options.linear_solver_type = ITERATIVE_SCHUR; + options.sparse_linear_algebra_library_type = SUITE_SPARSE; + options.preconditioner_type = IDENTITY; + EXPECT_TRUE(options.IsValid(&message)); + options.preconditioner_type = JACOBI; + EXPECT_TRUE(options.IsValid(&message)); + options.preconditioner_type = SCHUR_JACOBI; + EXPECT_TRUE(options.IsValid(&message)); + options.preconditioner_type = CLUSTER_JACOBI; + EXPECT_EQ(options.IsValid(&message), + IsSparseLinearAlgebraLibraryTypeAvailable( + options.sparse_linear_algebra_library_type)); + options.preconditioner_type = CLUSTER_TRIDIAGONAL; + EXPECT_EQ(options.IsValid(&message), + IsSparseLinearAlgebraLibraryTypeAvailable( + options.sparse_linear_algebra_library_type)); + options.preconditioner_type = SUBSET; + EXPECT_FALSE(options.IsValid(&message)); + + options.use_explicit_schur_complement = true; + options.preconditioner_type = IDENTITY; + EXPECT_FALSE(options.IsValid(&message)); + options.preconditioner_type = JACOBI; + EXPECT_FALSE(options.IsValid(&message)); + options.preconditioner_type = SCHUR_JACOBI; + EXPECT_TRUE(options.IsValid(&message)); + options.preconditioner_type = CLUSTER_JACOBI; + EXPECT_FALSE(options.IsValid(&message)); + options.preconditioner_type = CLUSTER_TRIDIAGONAL; + EXPECT_FALSE(options.IsValid(&message)); +} + +TEST(Solver, IterativeSchurOptionsAccelerateSparse) { + std::string message; + Solver::Options options; + options.linear_solver_type = ITERATIVE_SCHUR; + options.sparse_linear_algebra_library_type = ACCELERATE_SPARSE; + options.preconditioner_type = IDENTITY; + EXPECT_TRUE(options.IsValid(&message)); + options.preconditioner_type = JACOBI; + EXPECT_TRUE(options.IsValid(&message)); + options.preconditioner_type = SCHUR_JACOBI; + EXPECT_TRUE(options.IsValid(&message)); + options.preconditioner_type = CLUSTER_JACOBI; + EXPECT_EQ(options.IsValid(&message), + IsSparseLinearAlgebraLibraryTypeAvailable( + options.sparse_linear_algebra_library_type)); + options.preconditioner_type = CLUSTER_TRIDIAGONAL; + EXPECT_EQ(options.IsValid(&message), + IsSparseLinearAlgebraLibraryTypeAvailable( + options.sparse_linear_algebra_library_type)); + options.preconditioner_type = SUBSET; + EXPECT_FALSE(options.IsValid(&message)); + + options.use_explicit_schur_complement = true; + options.preconditioner_type = IDENTITY; + EXPECT_FALSE(options.IsValid(&message)); + options.preconditioner_type = JACOBI; + EXPECT_FALSE(options.IsValid(&message)); + options.preconditioner_type = SCHUR_JACOBI; + EXPECT_TRUE(options.IsValid(&message)); + options.preconditioner_type = CLUSTER_JACOBI; + EXPECT_FALSE(options.IsValid(&message)); + options.preconditioner_type = CLUSTER_TRIDIAGONAL; + EXPECT_FALSE(options.IsValid(&message)); +} + } // namespace ceres::internal
diff --git a/internal/ceres/types.cc b/internal/ceres/types.cc index 5d1bcea..c0e3355 100644 --- a/internal/ceres/types.cc +++ b/internal/ceres/types.cc
@@ -418,6 +418,10 @@ #endif } + if (type == NO_SPARSE) { + return true; + } + LOG(WARNING) << "Unknown sparse linear algebra library " << type; return false; }