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;
}