Refactor Covariance::Options::algorithm_type.
THIS IS AN API BREAKING CHANGE.
Decouple the algorithm from the sparse linear algebra
library being used to perform the computation.
Before this change
Covariance::AlgorithmType had values
DENSE_SVD
EIGEN_SPARSE_QR
SUITE_SPARSE_QR
This has been replaced by two enums now.
Covariance::Options::sparse_linear_algebra_library_type
which can take values EIGEN_SPARSE, SUITE_SPARSE or CX_SPARSE.
The last one is currently not supported.
And Covariance::Options::algorithm_type takes values
DENSE_SVD
SPARSE_QR
This sets the stage for future extensions of the covariance
computation algorithm.
Also as part of this change, the covariance computation chapter
has been made a top level chapter on its own instead of being
buried deep inside the Solving Non-linear Least Squares problem.
Change-Id: Ibfbf60902d8d17694d9ff585047a5a57d329ab22
diff --git a/docs/source/index.rst b/docs/source/index.rst
index ae3be3d..d72368f 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -27,6 +27,7 @@
derivatives
nnls_modeling
nnls_solving
+ nnls_covariance
gradient_solver
faqs
users
diff --git a/docs/source/nnls_solving.rst b/docs/source/nnls_solving.rst
index 5863ff0..fed0b3e 100644
--- a/docs/source/nnls_solving.rst
+++ b/docs/source/nnls_solving.rst
@@ -2255,365 +2255,3 @@
If the type of the line search direction is `LBFGS`, then this
indicates the rank of the Hessian approximation.
-
-Covariance Estimation
-=====================
-
-Background
-----------
-
-One way to assess the quality of the solution returned by a
-non-linear least squares solve is to analyze the covariance of the
-solution.
-
-Let us consider the non-linear regression problem
-
-.. math:: y = f(x) + N(0, I)
-
-i.e., the observation :math:`y` is a random non-linear function of the
-independent variable :math:`x` with mean :math:`f(x)` and identity
-covariance. Then the maximum likelihood estimate of :math:`x` given
-observations :math:`y` is the solution to the non-linear least squares
-problem:
-
-.. math:: x^* = \arg \min_x \|f(x)\|^2
-
-And the covariance of :math:`x^*` is given by
-
-.. math:: C(x^*) = \left(J'(x^*)J(x^*)\right)^{-1}
-
-Here :math:`J(x^*)` is the Jacobian of :math:`f` at :math:`x^*`. The
-above formula assumes that :math:`J(x^*)` has full column rank.
-
-If :math:`J(x^*)` is rank deficient, then the covariance matrix :math:`C(x^*)`
-is also rank deficient and is given by the Moore-Penrose pseudo inverse.
-
-.. math:: C(x^*) = \left(J'(x^*)J(x^*)\right)^{\dagger}
-
-Note that in the above, we assumed that the covariance matrix for
-:math:`y` was identity. This is an important assumption. If this is
-not the case and we have
-
-.. math:: y = f(x) + N(0, S)
-
-Where :math:`S` is a positive semi-definite matrix denoting the
-covariance of :math:`y`, then the maximum likelihood problem to be
-solved is
-
-.. math:: x^* = \arg \min_x f'(x) S^{-1} f(x)
-
-and the corresponding covariance estimate of :math:`x^*` is given by
-
-.. math:: C(x^*) = \left(J'(x^*) S^{-1} J(x^*)\right)^{-1}
-
-So, if it is the case that the observations being fitted to have a
-covariance matrix not equal to identity, then it is the user's
-responsibility that the corresponding cost functions are correctly
-scaled, e.g. in the above case the cost function for this problem
-should evaluate :math:`S^{-1/2} f(x)` instead of just :math:`f(x)`,
-where :math:`S^{-1/2}` is the inverse square root of the covariance
-matrix :math:`S`.
-
-Gauge Invariance
-----------------
-
-In structure from motion (3D reconstruction) problems, the
-reconstruction is ambiguous upto a similarity transform. This is
-known as a *Gauge Ambiguity*. Handling Gauges correctly requires the
-use of SVD or custom inversion algorithms. For small problems the
-user can use the dense algorithm. For more details see the work of
-Kanatani & Morris [KanataniMorris]_.
-
-
-:class:`Covariance`
--------------------
-
-:class:`Covariance` allows the user to evaluate the covariance for a
-non-linear least squares problem and provides random access to its
-blocks. The computation assumes that the cost functions compute
-residuals such that their covariance is identity.
-
-Since the computation of the covariance matrix requires computing the
-inverse of a potentially large matrix, this can involve a rather large
-amount of time and memory. However, it is usually the case that the
-user is only interested in a small part of the covariance
-matrix. Quite often just the block diagonal. :class:`Covariance`
-allows the user to specify the parts of the covariance matrix that she
-is interested in and then uses this information to only compute and
-store those parts of the covariance matrix.
-
-Rank of the Jacobian
---------------------
-
-As we noted above, if the Jacobian is rank deficient, then the inverse
-of :math:`J'J` is not defined and instead a pseudo inverse needs to be
-computed.
-
-The rank deficiency in :math:`J` can be *structural* -- columns
-which are always known to be zero or *numerical* -- depending on the
-exact values in the Jacobian.
-
-Structural rank deficiency occurs when the problem contains parameter
-blocks that are constant. This class correctly handles structural rank
-deficiency like that.
-
-Numerical rank deficiency, where the rank of the matrix cannot be
-predicted by its sparsity structure and requires looking at its
-numerical values is more complicated. Here again there are two
-cases.
-
- a. The rank deficiency arises from overparameterization. e.g., a
- four dimensional quaternion used to parameterize :math:`SO(3)`,
- which is a three dimensional manifold. In cases like this, the
- user should use an appropriate
- :class:`LocalParameterization`. Not only will this lead to better
- numerical behaviour of the Solver, it will also expose the rank
- deficiency to the :class:`Covariance` object so that it can
- handle it correctly.
-
- b. More general numerical rank deficiency in the Jacobian requires
- the computation of the so called Singular Value Decomposition
- (SVD) of :math:`J'J`. We do not know how to do this for large
- sparse matrices efficiently. For small and moderate sized
- problems this is done using dense linear algebra.
-
-
-:class:`Covariance::Options`
-
-.. class:: Covariance::Options
-
-.. member:: int Covariance::Options::num_threads
-
- Default: ``1``
-
- Number of threads to be used for evaluating the Jacobian and
- estimation of covariance.
-
-.. member:: CovarianceAlgorithmType Covariance::Options::algorithm_type
-
- Default: ``SUITE_SPARSE_QR`` if ``SuiteSparseQR`` is installed and
- ``EIGEN_SPARSE_QR`` otherwise.
-
- Ceres supports three different algorithms for covariance
- estimation, which represent different tradeoffs in speed, accuracy
- and reliability.
-
- 1. ``DENSE_SVD`` uses ``Eigen``'s ``JacobiSVD`` to perform the
- computations. It computes the singular value decomposition
-
- .. math:: U S V^\top = J
-
- and then uses it to compute the pseudo inverse of J'J as
-
- .. math:: (J'J)^{\dagger} = V S^{\dagger} V^\top
-
- It is an accurate but slow method and should only be used for
- small to moderate sized problems. It can handle full-rank as
- well as rank deficient Jacobians.
-
- 2. ``EIGEN_SPARSE_QR`` uses the sparse QR factorization algorithm
- in ``Eigen`` to compute the decomposition
-
- .. math::
-
- QR &= J\\
- \left(J^\top J\right)^{-1} &= \left(R^\top R\right)^{-1}
-
- It is a moderately fast algorithm for sparse matrices.
-
- 3. ``SUITE_SPARSE_QR`` uses the sparse QR factorization algorithm
- in ``SuiteSparse``. It uses dense linear algebra and is multi
- threaded, so for large sparse sparse matrices it is
- significantly faster than ``EIGEN_SPARSE_QR``.
-
- Neither ``EIGEN_SPARSE_QR`` nor ``SUITE_SPARSE_QR`` are capable of
- computing the covariance if the Jacobian is rank deficient.
-
-.. member:: int Covariance::Options::min_reciprocal_condition_number
-
- Default: :math:`10^{-14}`
-
- If the Jacobian matrix is near singular, then inverting :math:`J'J`
- will result in unreliable results, e.g, if
-
- .. math::
-
- J = \begin{bmatrix}
- 1.0& 1.0 \\
- 1.0& 1.0000001
- \end{bmatrix}
-
- which is essentially a rank deficient matrix, we have
-
- .. math::
-
- (J'J)^{-1} = \begin{bmatrix}
- 2.0471e+14& -2.0471e+14 \\
- -2.0471e+14 2.0471e+14
- \end{bmatrix}
-
-
- This is not a useful result. Therefore, by default
- :func:`Covariance::Compute` will return ``false`` if a rank
- deficient Jacobian is encountered. How rank deficiency is detected
- depends on the algorithm being used.
-
- 1. ``DENSE_SVD``
-
- .. math:: \frac{\sigma_{\text{min}}}{\sigma_{\text{max}}} < \sqrt{\text{min_reciprocal_condition_number}}
-
- where :math:`\sigma_{\text{min}}` and
- :math:`\sigma_{\text{max}}` are the minimum and maxiumum
- singular values of :math:`J` respectively.
-
- 2. ``EIGEN_SPARSE_QR`` and ``SUITE_SPARSE_QR``
-
- .. math:: \operatorname{rank}(J) < \operatorname{num\_col}(J)
-
- Here :\math:`\operatorname{rank}(J)` is the estimate of the
- rank of `J` returned by the sparse QR factorization
- algorithm. It is a fairly reliable indication of rank
- deficiency.
-
-.. member:: int Covariance::Options::null_space_rank
-
- When using ``DENSE_SVD``, the user has more control in dealing
- with singular and near singular covariance matrices.
-
- As mentioned above, when the covariance matrix is near singular,
- instead of computing the inverse of :math:`J'J`, the Moore-Penrose
- pseudoinverse of :math:`J'J` should be computed.
-
- If :math:`J'J` has the eigen decomposition :math:`(\lambda_i,
- e_i)`, where :math:`lambda_i` is the :math:`i^\textrm{th}`
- eigenvalue and :math:`e_i` is the corresponding eigenvector, then
- the inverse of :math:`J'J` is
-
- .. math:: (J'J)^{-1} = \sum_i \frac{1}{\lambda_i} e_i e_i'
-
- and computing the pseudo inverse involves dropping terms from this
- sum that correspond to small eigenvalues.
-
- How terms are dropped is controlled by
- `min_reciprocal_condition_number` and `null_space_rank`.
-
- If `null_space_rank` is non-negative, then the smallest
- `null_space_rank` eigenvalue/eigenvectors are dropped irrespective
- of the magnitude of :math:`\lambda_i`. If the ratio of the
- smallest non-zero eigenvalue to the largest eigenvalue in the
- truncated matrix is still below min_reciprocal_condition_number,
- then the `Covariance::Compute()` will fail and return `false`.
-
- Setting `null_space_rank = -1` drops all terms for which
-
- .. math:: \frac{\lambda_i}{\lambda_{\textrm{max}}} < \textrm{min_reciprocal_condition_number}
-
- This option has no effect on ``EIGEN_SPARSE_QR`` and
- ``SUITE_SPARSE_QR``.
-
-.. member:: bool Covariance::Options::apply_loss_function
-
- Default: `true`
-
- Even though the residual blocks in the problem may contain loss
- functions, setting ``apply_loss_function`` to false will turn off
- the application of the loss function to the output of the cost
- function and in turn its effect on the covariance.
-
-.. class:: Covariance
-
- :class:`Covariance::Options` as the name implies is used to control
- the covariance estimation algorithm. Covariance estimation is a
- complicated and numerically sensitive procedure. Please read the
- entire documentation for :class:`Covariance::Options` before using
- :class:`Covariance`.
-
-.. function:: bool Covariance::Compute(const vector<pair<const double*, const double*> >& covariance_blocks, Problem* problem)
-
- Compute a part of the covariance matrix.
-
- The vector ``covariance_blocks``, indexes into the covariance
- matrix block-wise using pairs of parameter blocks. This allows the
- covariance estimation algorithm to only compute and store these
- blocks.
-
- Since the covariance matrix is symmetric, if the user passes
- ``<block1, block2>``, then ``GetCovarianceBlock`` can be called with
- ``block1``, ``block2`` as well as ``block2``, ``block1``.
-
- ``covariance_blocks`` cannot contain duplicates. Bad things will
- happen if they do.
-
- Note that the list of ``covariance_blocks`` is only used to
- determine what parts of the covariance matrix are computed. The
- full Jacobian is used to do the computation, i.e. they do not have
- an impact on what part of the Jacobian is used for computation.
-
- The return value indicates the success or failure of the covariance
- computation. Please see the documentation for
- :class:`Covariance::Options` for more on the conditions under which
- this function returns ``false``.
-
-.. function:: bool GetCovarianceBlock(const double* parameter_block1, const double* parameter_block2, double* covariance_block) const
-
- Return the block of the cross-covariance matrix corresponding to
- ``parameter_block1`` and ``parameter_block2``.
-
- Compute must be called before the first call to ``GetCovarianceBlock``
- and the pair ``<parameter_block1, parameter_block2>`` OR the pair
- ``<parameter_block2, parameter_block1>`` must have been present in the
- vector covariance_blocks when ``Compute`` was called. Otherwise
- ``GetCovarianceBlock`` will return false.
-
- ``covariance_block`` must point to a memory location that can store
- a ``parameter_block1_size x parameter_block2_size`` matrix. The
- returned covariance will be a row-major matrix.
-
-.. function:: bool GetCovarianceBlockInTangentSpace(const double* parameter_block1, const double* parameter_block2, double* covariance_block) const
-
- Return the block of the cross-covariance matrix corresponding to
- ``parameter_block1`` and ``parameter_block2``.
- Returns cross-covariance in the tangent space if a local
- parameterization is associated with either parameter block;
- else returns cross-covariance in the ambient space.
-
- Compute must be called before the first call to ``GetCovarianceBlock``
- and the pair ``<parameter_block1, parameter_block2>`` OR the pair
- ``<parameter_block2, parameter_block1>`` must have been present in the
- vector covariance_blocks when ``Compute`` was called. Otherwise
- ``GetCovarianceBlock`` will return false.
-
- ``covariance_block`` must point to a memory location that can store
- a ``parameter_block1_local_size x parameter_block2_local_size`` matrix. The
- returned covariance will be a row-major matrix.
-
-Example Usage
--------------
-
-.. code-block:: c++
-
- double x[3];
- double y[2];
-
- Problem problem;
- problem.AddParameterBlock(x, 3);
- problem.AddParameterBlock(y, 2);
- <Build Problem>
- <Solve Problem>
-
- Covariance::Options options;
- Covariance covariance(options);
-
- vector<pair<const double*, const double*> > covariance_blocks;
- covariance_blocks.push_back(make_pair(x, x));
- covariance_blocks.push_back(make_pair(y, y));
- covariance_blocks.push_back(make_pair(x, y));
-
- CHECK(covariance.Compute(covariance_blocks, &problem));
-
- double covariance_xx[3 * 3];
- double covariance_yy[2 * 2];
- double covariance_xy[3 * 2];
- covariance.GetCovarianceBlock(x, x, covariance_xx)
- covariance.GetCovarianceBlock(y, y, covariance_yy)
- covariance.GetCovarianceBlock(x, y, covariance_xy)
diff --git a/include/ceres/covariance.h b/include/ceres/covariance.h
index 930f96c..0538522 100644
--- a/include/ceres/covariance.h
+++ b/include/ceres/covariance.h
@@ -200,19 +200,28 @@
class CERES_EXPORT Covariance {
public:
struct CERES_EXPORT Options {
- Options()
-#ifndef CERES_NO_SUITESPARSE
- : algorithm_type(SUITE_SPARSE_QR),
-#else
- : algorithm_type(EIGEN_SPARSE_QR),
+ Options() {
+ algorithm_type = SPARSE_QR;
+
+ // Eigen's QR factorization is always available.
+ sparse_linear_algebra_library_type = EIGEN_SPARSE;
+#if !defined(CERES_NO_SUITESPARSE)
+ sparse_linear_algebra_library_type = SUITE_SPARSE;
#endif
- min_reciprocal_condition_number(1e-14),
- null_space_rank(0),
- num_threads(1),
- apply_loss_function(true) {
+
+ min_reciprocal_condition_number = 1e-14;
+ null_space_rank = 0;
+ num_threads = 1;
+ apply_loss_function = true;
}
- // Ceres supports three different algorithms for covariance
+ // Sparse linear algebra library to use when a sparse matrix
+ // factorization is being used to compute the covariance matrix.
+ //
+ // Currently this only applies to SPARSE_QR.
+ SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type;
+
+ // Ceres supports two different algorithms for covariance
// estimation, which represent different tradeoffs in speed,
// accuracy and reliability.
//
@@ -229,22 +238,19 @@
// for small to moderate sized problems. It can handle
// full-rank as well as rank deficient Jacobians.
//
- // 2. EIGEN_SPARSE_QR uses the sparse QR factorization algorithm
- // in Eigen to compute the decomposition
+ // 2. SPARSE_QR uses the sparse QR factorization algorithm
+ // to compute the decomposition
//
// Q * R = J
//
// [J'J]^-1 = [R*R']^-1
//
- // It is a moderately fast algorithm for sparse matrices.
- //
- // 3. SUITE_SPARSE_QR uses the SuiteSparseQR sparse QR
- // factorization algorithm. It uses dense linear algebra and is
- // multi threaded, so for large sparse sparse matrices it is
- // significantly faster than EIGEN_SPARSE_QR.
- //
- // Neither EIGEN_SPARSE_QR not SUITE_SPARSE_QR are capable of
- // computing the covariance if the Jacobian is rank deficient.
+ // SPARSE_QR is not capable of computing the covariance if the
+ // Jacobian is rank deficient. Depending on the value of
+ // Covariance::Options::sparse_linear_algebra_library_type, either
+ // Eigen's Sparse QR factorization algorithm will be used or
+ // SuiteSparse's high performance SuiteSparseQR algorithm will be
+ // used.
CovarianceAlgorithmType algorithm_type;
// If the Jacobian matrix is near singular, then inverting J'J
@@ -270,7 +276,7 @@
// where min_sigma and max_sigma are the minimum and maxiumum
// singular values of J respectively.
//
- // 2. SUITE_SPARSE_QR and EIGEN_SPARSE_QR
+ // 2. SPARSE_QR
//
// rank(J) < num_col(J)
//
diff --git a/include/ceres/types.h b/include/ceres/types.h
index 6b9da84..643eb23 100644
--- a/include/ceres/types.h
+++ b/include/ceres/types.h
@@ -420,8 +420,18 @@
enum CovarianceAlgorithmType {
DENSE_SVD,
- SUITE_SPARSE_QR,
- EIGEN_SPARSE_QR
+ SPARSE_QR,
+
+ // TODO(sameeragarwal): Expand this to include
+ // DENSE_QR (Eigen)
+ // DENSE_SCHUR_SVD (Eigen)
+ // SPARSE_SCHUR_LU (Eigen, SuiteSparse)
+ //
+ // Are the following two a good idea? given that they are not rank
+ // revealing.
+ //
+ // DENSE_SCHUR_CHOLESKY (Eigen)
+ // SPARSE_SCHUR_CHOLESKY (Eigen, SuiteSparse)
};
// It is a near impossibility that user code generates this exact
diff --git a/include/ceres/version.h b/include/ceres/version.h
index 2f1cc29..beab7d9 100644
--- a/include/ceres/version.h
+++ b/include/ceres/version.h
@@ -32,7 +32,7 @@
#define CERES_PUBLIC_VERSION_H_
#define CERES_VERSION_MAJOR 1
-#define CERES_VERSION_MINOR 12
+#define CERES_VERSION_MINOR 13
#define CERES_VERSION_REVISION 0
// Classic CPP stringifcation; the extra level of indirection allows the
diff --git a/internal/ceres/covariance_impl.cc b/internal/ceres/covariance_impl.cc
index d698f88..1f594c1 100644
--- a/internal/ceres/covariance_impl.cc
+++ b/internal/ceres/covariance_impl.cc
@@ -538,24 +538,37 @@
}
bool CovarianceImpl::ComputeCovarianceValues() {
- switch (options_.algorithm_type) {
- case DENSE_SVD:
- return ComputeCovarianceValuesUsingDenseSVD();
- case SUITE_SPARSE_QR:
-#ifndef CERES_NO_SUITESPARSE
+ if (options_.algorithm_type == DENSE_SVD) {
+ return ComputeCovarianceValuesUsingDenseSVD();
+ }
+
+ if (options_.algorithm_type == SPARSE_QR) {
+ if (options_.sparse_linear_algebra_library_type == EIGEN_SPARSE) {
+ return ComputeCovarianceValuesUsingEigenSparseQR();
+ }
+
+ if (options_.sparse_linear_algebra_library_type == SUITE_SPARSE) {
+#if !defined(CERES_NO_SUITESPARSE)
return ComputeCovarianceValuesUsingSuiteSparseQR();
#else
- LOG(ERROR) << "SuiteSparse is required to use the "
- << "SUITE_SPARSE_QR algorithm.";
+ LOG(ERROR) << "SuiteSparse is required to use the SPARSE_QR algorithm "
+ << "with "
+ << "Covariance::Options::sparse_linear_algebra_library_type "
+ << "= SUITE_SPARSE.";
return false;
#endif
- case EIGEN_SPARSE_QR:
- return ComputeCovarianceValuesUsingEigenSparseQR();
- default:
- LOG(ERROR) << "Unsupported covariance estimation algorithm type: "
- << CovarianceAlgorithmTypeToString(options_.algorithm_type);
- return false;
+ }
+
+ LOG(ERROR) << "Unsupported "
+ << "Covariance::Options::sparse_linear_algebra_library_type "
+ << "= "
+ << SparseLinearAlgebraLibraryTypeToString(
+ options_.sparse_linear_algebra_library_type);
+ return false;
}
+
+ LOG(ERROR) << "Unsupported Covariance::Options::algorithm_type = "
+ << CovarianceAlgorithmTypeToString(options_.algorithm_type);
return false;
}
diff --git a/internal/ceres/covariance_test.cc b/internal/ceres/covariance_test.cc
index 63f85c4..92a7626 100644
--- a/internal/ceres/covariance_test.cc
+++ b/internal/ceres/covariance_test.cc
@@ -629,14 +629,16 @@
Covariance::Options options;
#ifndef CERES_NO_SUITESPARSE
- options.algorithm_type = SUITE_SPARSE_QR;
+ options.algorithm_type = SPARSE_QR;
+ options.sparse_linear_algebra_library_type = SUITE_SPARSE;
ComputeAndCompareCovarianceBlocks(options, expected_covariance);
#endif
options.algorithm_type = DENSE_SVD;
ComputeAndCompareCovarianceBlocks(options, expected_covariance);
- options.algorithm_type = EIGEN_SPARSE_QR;
+ options.algorithm_type = SPARSE_QR;
+ options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
ComputeAndCompareCovarianceBlocks(options, expected_covariance);
}
@@ -677,14 +679,16 @@
options.num_threads = 4;
#ifndef CERES_NO_SUITESPARSE
- options.algorithm_type = SUITE_SPARSE_QR;
+ options.algorithm_type = SPARSE_QR;
+ options.sparse_linear_algebra_library_type = SUITE_SPARSE;
ComputeAndCompareCovarianceBlocks(options, expected_covariance);
#endif
options.algorithm_type = DENSE_SVD;
ComputeAndCompareCovarianceBlocks(options, expected_covariance);
- options.algorithm_type = EIGEN_SPARSE_QR;
+ options.algorithm_type = SPARSE_QR;
+ options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
ComputeAndCompareCovarianceBlocks(options, expected_covariance);
}
@@ -726,14 +730,16 @@
Covariance::Options options;
#ifndef CERES_NO_SUITESPARSE
- options.algorithm_type = SUITE_SPARSE_QR;
+ options.algorithm_type = SPARSE_QR;
+ options.sparse_linear_algebra_library_type = SUITE_SPARSE;
ComputeAndCompareCovarianceBlocks(options, expected_covariance);
#endif
options.algorithm_type = DENSE_SVD;
ComputeAndCompareCovarianceBlocks(options, expected_covariance);
- options.algorithm_type = EIGEN_SPARSE_QR;
+ options.algorithm_type = SPARSE_QR;
+ options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
ComputeAndCompareCovarianceBlocks(options, expected_covariance);
}
@@ -781,14 +787,16 @@
Covariance::Options options;
#ifndef CERES_NO_SUITESPARSE
- options.algorithm_type = SUITE_SPARSE_QR;
+ options.algorithm_type = SPARSE_QR;
+ options.sparse_linear_algebra_library_type = SUITE_SPARSE;
ComputeAndCompareCovarianceBlocks(options, expected_covariance);
#endif
options.algorithm_type = DENSE_SVD;
ComputeAndCompareCovarianceBlocks(options, expected_covariance);
- options.algorithm_type = EIGEN_SPARSE_QR;
+ options.algorithm_type = SPARSE_QR;
+ options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
ComputeAndCompareCovarianceBlocks(options, expected_covariance);
}
@@ -839,14 +847,17 @@
Covariance::Options options;
#ifndef CERES_NO_SUITESPARSE
- options.algorithm_type = SUITE_SPARSE_QR;
+ options.algorithm_type = SPARSE_QR;
+ options.sparse_linear_algebra_library_type = SUITE_SPARSE;
+
ComputeAndCompareCovarianceBlocksInTangentSpace(options, expected_covariance);
#endif
options.algorithm_type = DENSE_SVD;
ComputeAndCompareCovarianceBlocksInTangentSpace(options, expected_covariance);
- options.algorithm_type = EIGEN_SPARSE_QR;
+ options.algorithm_type = SPARSE_QR;
+ options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
ComputeAndCompareCovarianceBlocksInTangentSpace(options, expected_covariance);
}
@@ -899,14 +910,17 @@
Covariance::Options options;
#ifndef CERES_NO_SUITESPARSE
- options.algorithm_type = SUITE_SPARSE_QR;
+ options.algorithm_type = SPARSE_QR;
+ options.sparse_linear_algebra_library_type = SUITE_SPARSE;
+
ComputeAndCompareCovarianceBlocksInTangentSpace(options, expected_covariance);
#endif
options.algorithm_type = DENSE_SVD;
ComputeAndCompareCovarianceBlocksInTangentSpace(options, expected_covariance);
- options.algorithm_type = EIGEN_SPARSE_QR;
+ options.algorithm_type = SPARSE_QR;
+ options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
ComputeAndCompareCovarianceBlocksInTangentSpace(options, expected_covariance);
}
@@ -978,14 +992,16 @@
covariance.GetCovarianceMatrix(parameter_blocks, expected_covariance);
#ifndef CERES_NO_SUITESPARSE
- options.algorithm_type = SUITE_SPARSE_QR;
+ options.algorithm_type = SPARSE_QR;
+ options.sparse_linear_algebra_library_type = SUITE_SPARSE;
ComputeAndCompareCovarianceBlocks(options, expected_covariance);
#endif
options.algorithm_type = DENSE_SVD;
ComputeAndCompareCovarianceBlocks(options, expected_covariance);
- options.algorithm_type = EIGEN_SPARSE_QR;
+ options.algorithm_type = SPARSE_QR;
+ options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
ComputeAndCompareCovarianceBlocks(options, expected_covariance);
}
@@ -1005,14 +1021,16 @@
covariance.GetCovarianceMatrix(parameter_blocks, expected_covariance);
#ifndef CERES_NO_SUITESPARSE
- options.algorithm_type = SUITE_SPARSE_QR;
+ options.algorithm_type = SPARSE_QR;
+ options.sparse_linear_algebra_library_type = SUITE_SPARSE;
ComputeAndCompareCovarianceBlocks(options, expected_covariance);
#endif
options.algorithm_type = DENSE_SVD;
ComputeAndCompareCovarianceBlocks(options, expected_covariance);
- options.algorithm_type = EIGEN_SPARSE_QR;
+ options.algorithm_type = SPARSE_QR;
+ options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
ComputeAndCompareCovarianceBlocks(options, expected_covariance);
}
@@ -1043,14 +1061,17 @@
expected_covariance);
#ifndef CERES_NO_SUITESPARSE
- options.algorithm_type = SUITE_SPARSE_QR;
+ options.algorithm_type = SPARSE_QR;
+ options.sparse_linear_algebra_library_type = SUITE_SPARSE;
+
ComputeAndCompareCovarianceBlocksInTangentSpace(options, expected_covariance);
#endif
options.algorithm_type = DENSE_SVD;
ComputeAndCompareCovarianceBlocksInTangentSpace(options, expected_covariance);
- options.algorithm_type = EIGEN_SPARSE_QR;
+ options.algorithm_type = SPARSE_QR;
+ options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
ComputeAndCompareCovarianceBlocksInTangentSpace(options, expected_covariance);
}
@@ -1197,10 +1218,14 @@
}
}
- void ComputeAndCompare(CovarianceAlgorithmType algorithm_type,
- int num_threads) {
+ void ComputeAndCompare(
+ CovarianceAlgorithmType algorithm_type,
+ SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type,
+ int num_threads) {
Covariance::Options options;
options.algorithm_type = algorithm_type;
+ options.sparse_linear_algebra_library_type =
+ sparse_linear_algebra_library_type;
options.num_threads = num_threads;
Covariance covariance(options);
EXPECT_TRUE(covariance.Compute(all_covariance_blocks_, &problem_));
@@ -1243,7 +1268,7 @@
#if !defined(CERES_NO_SUITESPARSE) && defined(CERES_USE_OPENMP)
TEST_F(LargeScaleCovarianceTest, Parallel) {
- ComputeAndCompare(SUITE_SPARSE_QR, 4);
+ ComputeAndCompare(SPARSE_QR, SUITE_SPARSE, 4);
}
#endif // !defined(CERES_NO_SUITESPARSE) && defined(CERES_USE_OPENMP)
diff --git a/internal/ceres/types.cc b/internal/ceres/types.cc
index f86fb78..b833928 100644
--- a/internal/ceres/types.cc
+++ b/internal/ceres/types.cc
@@ -267,8 +267,7 @@
CovarianceAlgorithmType type) {
switch (type) {
CASESTR(DENSE_SVD);
- CASESTR(EIGEN_SPARSE_QR);
- CASESTR(SUITE_SPARSE_QR);
+ CASESTR(SPARSE_QR);
default:
return "UNKNOWN";
}
@@ -279,8 +278,7 @@
CovarianceAlgorithmType* type) {
UpperCase(&value);
STRENUM(DENSE_SVD);
- STRENUM(EIGEN_SPARSE_QR);
- STRENUM(SUITE_SPARSE_QR);
+ STRENUM(SPARSE_QR);
return false;
}