Add explicit no sparse linear algebra library available option.
- Previously we had no defined default value for
sparse_linear_algebra_library_type in Solver::Options if Ceres
was compiled with no sparse library available. Thus in that case,
the default value (dependent upon the compiler) would indicate that
one was available.
- Now we have an explicit option that means no sparse library is
available, which is now the default value in Solver::Options in this
case.
- Add a warning in CMake when the user disables all sparse libraries.
- Fix typos in trust_region_preprocessor_test:
(SUITE/CX)_SPARSE -> (SUITE/CX)SPARSE that induced failures when
no sparse libraries were available.
Change-Id: I869c399a12d42bfc44220cbb25ce6d6dd80236bd
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9c0ed8c..6fe1e32 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -370,6 +370,16 @@
CXSPARSE_LIBRARY)
ENDIF (CXSPARSE)
+# Ensure that the user understands they have disabled all sparse libraries.
+IF (NOT SUITESPARSE AND NOT CXSPARSE AND NOT EIGENSPARSE)
+ MESSAGE(" ===============================================================")
+ MESSAGE(" Compiling without any sparse library: SuiteSparse, CXSparse ")
+ MESSAGE(" & Eigen (Sparse) are all disabled or unavailable. No sparse ")
+ MESSAGE(" linear solvers (SPARSE_NORMAL_CHOLESKY & SPARSE_SCHUR)")
+ MESSAGE(" will be available when Ceres is used.")
+ MESSAGE(" ===============================================================")
+ENDIF(NOT SUITESPARSE AND NOT CXSPARSE AND NOT EIGENSPARSE)
+
# GFlags.
IF (GFLAGS)
HANDLE_LEGACY_INCLUDE_DEPENDENCY_HINT(GFLAGS_INCLUDE GFLAGS_INCLUDE_DIR_HINTS)
diff --git a/docs/source/nnls_solving.rst b/docs/source/nnls_solving.rst
index a283f98..067e3b1 100644
--- a/docs/source/nnls_solving.rst
+++ b/docs/source/nnls_solving.rst
@@ -1237,13 +1237,16 @@
.. member:: SparseLinearAlgebraLibrary Solver::Options::sparse_linear_algebra_library_type
- Default:``SUITE_SPARSE``
+ Default: The highest available according to: ``SUITE_SPARSE`` >
+ ``CX_SPARSE`` > ``EIGEN_SPARSE`` > ``NO_SPARSE``
Ceres supports the use of three sparse linear algebra libraries,
``SuiteSparse``, which is enabled by setting this parameter to
``SUITE_SPARSE``, ``CXSparse``, which can be selected by setting
- this parameter to ```CX_SPARSE`` and ``Eigen`` which is enabled by
- setting this parameter to ``EIGEN_SPARSE``.
+ this parameter to ``CX_SPARSE`` and ``Eigen`` which is enabled by
+ setting this parameter to ``EIGEN_SPARSE``. Lastly, ``NO_SPARSE``
+ means that no sparse linear solver should be used; note that this is
+ irrespective of whether Ceres was compiled with support for one.
``SuiteSparse`` is a sophisticated and complex sparse linear
algebra library and should be used in general.
diff --git a/include/ceres/solver.h b/include/ceres/solver.h
index 791630d..b2fa3ae 100644
--- a/include/ceres/solver.h
+++ b/include/ceres/solver.h
@@ -104,7 +104,8 @@
// Choose a default sparse linear algebra library in the order:
//
- // SUITE_SPARSE > CX_SPARSE > EIGEN_SPARSE
+ // SUITE_SPARSE > CX_SPARSE > EIGEN_SPARSE > NO_SPARSE
+ sparse_linear_algebra_library_type = NO_SPARSE;
#if !defined(CERES_NO_SUITESPARSE)
sparse_linear_algebra_library_type = SUITE_SPARSE;
#else
diff --git a/include/ceres/types.h b/include/ceres/types.h
index a07c893..8915188 100644
--- a/include/ceres/types.h
+++ b/include/ceres/types.h
@@ -157,7 +157,12 @@
// Eigen's sparse linear algebra routines. In particular Ceres uses
// the Simplicial LDLT routines.
- EIGEN_SPARSE
+ EIGEN_SPARSE,
+
+ // No sparse linear solver should be used. This does not necessarily
+ // imply that Ceres was built without any sparse library, although that
+ // is the likely use case, merely that one should not be used.
+ NO_SPARSE
};
enum DenseLinearAlgebraLibraryType {
diff --git a/internal/ceres/solver.cc b/internal/ceres/solver.cc
index de170c3..738828b 100644
--- a/internal/ceres/solver.cc
+++ b/internal/ceres/solver.cc
@@ -228,6 +228,20 @@
}
#endif
+ if (options.sparse_linear_algebra_library_type == NO_SPARSE) {
+ if (options.linear_solver_type == SPARSE_NORMAL_CHOLESKY) {
+ *error = "Can't use SPARSE_NORMAL_CHOLESKY as "
+ "sparse_linear_algebra_library_type is NO_SPARSE.";
+ return false;
+ }
+
+ if (options.linear_solver_type == SPARSE_SCHUR) {
+ *error = "Can't use SPARSE_SCHUR as "
+ "sparse_linear_algebra_library_type is NO_SPARSE.";
+ return false;
+ }
+ }
+
if (options.trust_region_strategy_type == DOGLEG) {
if (options.linear_solver_type == ITERATIVE_SCHUR ||
options.linear_solver_type == CGNR) {
diff --git a/internal/ceres/solver_test.cc b/internal/ceres/solver_test.cc
index cd82f55..4069578 100644
--- a/internal/ceres/solver_test.cc
+++ b/internal/ceres/solver_test.cc
@@ -293,6 +293,42 @@
}
#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;
diff --git a/internal/ceres/trust_region_preprocessor_test.cc b/internal/ceres/trust_region_preprocessor_test.cc
index a6189ad..b895a72 100644
--- a/internal/ceres/trust_region_preprocessor_test.cc
+++ b/internal/ceres/trust_region_preprocessor_test.cc
@@ -201,16 +201,16 @@
}
#if defined(CERES_USE_EIGEN_SPARSE) || \
- !defined(CERES_NO_SUITE_SPARSE) || \
- !defined(CERES_NO_CX_SPARSE)
+ !defined(CERES_NO_SUITESPARSE) || \
+ !defined(CERES_NO_CXSPARSE)
TEST_F(LinearSolverAndEvaluatorCreationTest, SparseNormalCholesky) {
PreprocessForGivenLinearSolverAndVerify(SPARSE_NORMAL_CHOLESKY);
}
#endif
#if defined(CERES_USE_EIGEN_SPARSE) || \
- !defined(CERES_NO_SUITE_SPARSE) || \
- !defined(CERES_NO_CX_SPARSE)
+ !defined(CERES_NO_SUITESPARSE) || \
+ !defined(CERES_NO_CXSPARSE)
TEST_F(LinearSolverAndEvaluatorCreationTest, SparseSchur) {
PreprocessForGivenLinearSolverAndVerify(SPARSE_SCHUR);
}
diff --git a/internal/ceres/types.cc b/internal/ceres/types.cc
index 4710261..52bd67d 100644
--- a/internal/ceres/types.cc
+++ b/internal/ceres/types.cc
@@ -97,6 +97,7 @@
CASESTR(SUITE_SPARSE);
CASESTR(CX_SPARSE);
CASESTR(EIGEN_SPARSE);
+ CASESTR(NO_SPARSE);
default:
return "UNKNOWN";
}
@@ -109,6 +110,7 @@
STRENUM(SUITE_SPARSE);
STRENUM(CX_SPARSE);
STRENUM(EIGEN_SPARSE);
+ STRENUM(NO_SPARSE);
return false;
}