Revert 81219ff.
Eigen upstream was broken a little while ago, and it seemed to be
the case that we needed a fix for using the LLT factorization on
ARM.
This has been fixed and AFAIK there are no stable eigen releases
with this bug in it.
For full gore, see
http://eigen.tuxfamily.org/bz/show_bug.cgi?id=992
In light of the fix, the extra layer of indirection introduced earlier
is not needed and we are reverting to normal programming.
Change-Id: I16929d2145253b38339b573b27b6b8fabd523704
diff --git a/cmake/config.h.in b/cmake/config.h.in
index 41d629e..aea7921 100644
--- a/cmake/config.h.in
+++ b/cmake/config.h.in
@@ -44,10 +44,6 @@
// If defined, use the LGPL code in Eigen.
@CERES_USE_EIGEN_SPARSE@
-// If defined, use Eigen's LDLT factorization instead of LLT
-// factorization.
-@CERES_USE_LDLT_FOR_EIGEN_CHOLESKY@
-
// If defined, Ceres was compiled without LAPACK.
@CERES_NO_LAPACK@
diff --git a/internal/ceres/CMakeLists.txt b/internal/ceres/CMakeLists.txt
index 6cac9c9..a06f3a5 100644
--- a/internal/ceres/CMakeLists.txt
+++ b/internal/ceres/CMakeLists.txt
@@ -61,7 +61,6 @@
dogleg_strategy.cc
dynamic_compressed_row_jacobian_writer.cc
dynamic_compressed_row_sparse_matrix.cc
- eigen_dense_cholesky.cc
evaluator.cc
file.cc
gradient_checking_cost_function.cc
diff --git a/internal/ceres/block_random_access_diagonal_matrix.cc b/internal/ceres/block_random_access_diagonal_matrix.cc
index afa10de..052690d 100644
--- a/internal/ceres/block_random_access_diagonal_matrix.cc
+++ b/internal/ceres/block_random_access_diagonal_matrix.cc
@@ -34,7 +34,7 @@
#include <set>
#include <utility>
#include <vector>
-#include "ceres/eigen_dense_cholesky.h"
+#include "Eigen/Dense"
#include "ceres/internal/port.h"
#include "ceres/internal/scoped_ptr.h"
#include "ceres/stl_util.h"
@@ -125,7 +125,12 @@
double* values = tsm_->mutable_values();
for (int i = 0; i < blocks_.size(); ++i) {
const int block_size = blocks_[i];
- InvertUpperTriangularUsingCholesky(block_size, values, values);
+ MatrixRef block(values, block_size, block_size);
+ block =
+ block
+ .selfadjointView<Eigen::Upper>()
+ .llt()
+ .solve(Matrix::Identity(block_size, block_size));
values += block_size * block_size;
}
}
diff --git a/internal/ceres/block_random_access_diagonal_matrix_test.cc b/internal/ceres/block_random_access_diagonal_matrix_test.cc
index 0bf9b79..8fa3798 100644
--- a/internal/ceres/block_random_access_diagonal_matrix_test.cc
+++ b/internal/ceres/block_random_access_diagonal_matrix_test.cc
@@ -32,10 +32,10 @@
#include <vector>
#include "ceres/block_random_access_diagonal_matrix.h"
-#include "ceres/eigen_dense_cholesky.h"
#include "ceres/internal/eigen.h"
#include "glog/logging.h"
#include "gtest/gtest.h"
+#include "Eigen/Cholesky"
namespace ceres {
namespace internal {
@@ -147,10 +147,9 @@
const TripletSparseMatrix* tsm = m_->matrix();
Matrix dense;
tsm->ToDenseMatrix(&dense);
- Matrix expected_inverse(dense.rows(), dense.rows());
- InvertUpperTriangularUsingCholesky(dense.rows(),
- dense.data(),
- expected_inverse.data());
+ Matrix expected_inverse =
+ dense.llt().solve(Matrix::Identity(dense.rows(), dense.rows()));
+
m_->Invert();
tsm->ToDenseMatrix(&dense);
diff --git a/internal/ceres/dense_normal_cholesky_solver.cc b/internal/ceres/dense_normal_cholesky_solver.cc
index 8682ae7..b13cf3f 100644
--- a/internal/ceres/dense_normal_cholesky_solver.cc
+++ b/internal/ceres/dense_normal_cholesky_solver.cc
@@ -32,9 +32,9 @@
#include <cstddef>
+#include "Eigen/Dense"
#include "ceres/blas.h"
#include "ceres/dense_sparse_matrix.h"
-#include "ceres/eigen_dense_cholesky.h"
#include "ceres/internal/eigen.h"
#include "ceres/internal/scoped_ptr.h"
#include "ceres/lapack.h"
@@ -95,8 +95,11 @@
LinearSolver::Summary summary;
summary.num_iterations = 1;
- if (SolveUpperTriangularUsingCholesky(num_cols, lhs.data(), rhs.data(), x)
- != Eigen::Success) {
+ summary.termination_type = LINEAR_SOLVER_SUCCESS;
+ Eigen::LLT<Matrix, Eigen::Upper> llt =
+ lhs.selfadjointView<Eigen::Upper>().llt();
+
+ if (llt.info() != Eigen::Success) {
summary.termination_type = LINEAR_SOLVER_FAILURE;
summary.message = "Eigen LLT decomposition failed.";
} else {
@@ -104,6 +107,7 @@
summary.message = "Success.";
}
+ VectorRef(x, num_cols) = llt.solve(rhs);
event_logger.AddEvent("Solve");
return summary;
}
diff --git a/internal/ceres/eigen_dense_cholesky.cc b/internal/ceres/eigen_dense_cholesky.cc
deleted file mode 100644
index 7b43ad2..0000000
--- a/internal/ceres/eigen_dense_cholesky.cc
+++ /dev/null
@@ -1,65 +0,0 @@
-#include "ceres/eigen_dense_cholesky.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
-#include "Eigen/Dense"
-
-namespace ceres {
-namespace internal {
-
-using Eigen::Upper;
-
-Eigen::ComputationInfo
-InvertUpperTriangularUsingCholesky(const int size,
- const double* values,
- double* inverse_values) {
- ConstMatrixRef m(values, size, size);
- MatrixRef inverse(inverse_values, size, size);
-
- // On ARM we have experienced significant numerical problems with
- // Eigen's LLT implementation. Defining
- // CERES_USE_LDLT_FOR_EIGEN_CHOLESKY switches to using the slightly
- // more expensive but much more numerically well behaved LDLT
- // factorization algorithm.
-
-#ifdef CERES_USE_LDLT_FOR_EIGEN_CHOLESKY
- Eigen::LDLT<Matrix, Upper> cholesky = m.selfadjointView<Upper>().ldlt();
-#else
- Eigen::LLT<Matrix, Upper> cholesky = m.selfadjointView<Upper>().llt();
-#endif
-
- inverse = cholesky.solve(Matrix::Identity(size, size));
- return cholesky.info();
-}
-
-Eigen::ComputationInfo
-SolveUpperTriangularUsingCholesky(int size,
- const double* lhs_values,
- const double* rhs_values,
- double* solution_values) {
- ConstMatrixRef lhs(lhs_values, size, size);
-
- // On ARM we have experienced significant numerical problems with
- // Eigen's LLT implementation. Defining
- // CERES_USE_LDLT_FOR_EIGEN_CHOLESKY switches to using the slightly
- // more expensive but much more numerically well behaved LDLT
- // factorization algorithm.
-
-#ifdef CERES_USE_LDLT_FOR_EIGEN_CHOLESKY
- Eigen::LDLT<Matrix, Upper> cholesky = lhs.selfadjointView<Upper>().ldlt();
-#else
- Eigen::LLT<Matrix, Upper> cholesky = lhs.selfadjointView<Upper>().llt();
-#endif
-
- VectorRef solution(solution_values, size);
- if (solution_values == rhs_values) {
- cholesky.solveInPlace(solution);
- } else {
- ConstVectorRef rhs(rhs_values, size);
- solution = cholesky.solve(rhs);
- }
-
- return cholesky.info();
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/internal/ceres/eigen_dense_cholesky.h b/internal/ceres/eigen_dense_cholesky.h
deleted file mode 100644
index 0d6b18a..0000000
--- a/internal/ceres/eigen_dense_cholesky.h
+++ /dev/null
@@ -1,67 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Wrappers around Eigen's dense Cholesky factorization
-// routines. Normally, if CERES_USE_LDLT_FOR_EIGEN_CHOLESKY is not
-// defined Eigen's LLT factorization is used, which is faster than the
-// LDLT factorization, however on ARM the LLT factorization seems to
-// give significantly worse results than LDLT and we are forced to use
-// LDLT instead.
-//
-// These wrapper functions provide a level of indirection to deal with
-// this switching and hide it from the rest of the code base.
-
-#ifndef CERES_INTERNAL_ARRAY_UTILS_H_
-#define CERES_INTERNAL_ARRAY_UTILS_H_
-
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-// Invert a matrix using Eigen's dense Cholesky factorization. values
-// and inverse_values can point to the same array.
-Eigen::ComputationInfo
-InvertUpperTriangularUsingCholesky(int size,
- const double* values,
- double* inverse_values);
-
-// Solve a linear system using Eigen's dense Cholesky
-// factorization. rhs_values and solution can point to the same array.
-Eigen::ComputationInfo
-SolveUpperTriangularUsingCholesky(int size,
- const double* lhs,
- const double* rhs,
- double* solution);
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_ARRAY_UTILS_H_
diff --git a/internal/ceres/implicit_schur_complement.cc b/internal/ceres/implicit_schur_complement.cc
index b943510..d05f038 100644
--- a/internal/ceres/implicit_schur_complement.cc
+++ b/internal/ceres/implicit_schur_complement.cc
@@ -30,9 +30,9 @@
#include "ceres/implicit_schur_complement.h"
+#include "Eigen/Dense"
#include "ceres/block_sparse_matrix.h"
#include "ceres/block_structure.h"
-#include "ceres/eigen_dense_cholesky.h"
#include "ceres/internal/eigen.h"
#include "ceres/internal/scoped_ptr.h"
#include "ceres/linear_solver.h"
@@ -148,16 +148,18 @@
const int row_block_pos = block_diagonal_structure->rows[r].block.position;
const int row_block_size = block_diagonal_structure->rows[r].block.size;
const Cell& cell = block_diagonal_structure->rows[r].cells[0];
- double* block_values = block_diagonal->mutable_values() + cell.position;
- MatrixRef m(block_values, row_block_size, row_block_size);
+ MatrixRef m(block_diagonal->mutable_values() + cell.position,
+ row_block_size, row_block_size);
+
if (D != NULL) {
ConstVectorRef d(D + row_block_pos, row_block_size);
m += d.array().square().matrix().asDiagonal();
}
- InvertUpperTriangularUsingCholesky(row_block_size,
- block_values,
- block_values);
+ m = m
+ .selfadjointView<Eigen::Upper>()
+ .llt()
+ .solve(Matrix::Identity(row_block_size, row_block_size));
}
}
diff --git a/internal/ceres/implicit_schur_complement_test.cc b/internal/ceres/implicit_schur_complement_test.cc
index 9bec91f..e586ea1 100644
--- a/internal/ceres/implicit_schur_complement_test.cc
+++ b/internal/ceres/implicit_schur_complement_test.cc
@@ -31,10 +31,10 @@
#include "ceres/implicit_schur_complement.h"
#include <cstddef>
+#include "Eigen/Dense"
#include "ceres/block_random_access_dense_matrix.h"
#include "ceres/block_sparse_matrix.h"
#include "ceres/casts.h"
-#include "ceres/eigen_dense_cholesky.h"
#include "ceres/internal/eigen.h"
#include "ceres/internal/scoped_ptr.h"
#include "ceres/linear_least_squares_problems.h"
@@ -107,16 +107,11 @@
solution->resize(num_cols_);
solution->setZero();
- double* schur_solution = solution->data() + num_cols_ - num_schur_rows;
- SolveUpperTriangularUsingCholesky(num_schur_rows,
- lhs->data(),
- rhs->data(),
- schur_solution);
- eliminator->BackSubstitute(A_.get(),
- b_.get(),
- D,
- schur_solution,
- solution->data());
+ VectorRef schur_solution(solution->data() + num_cols_ - num_schur_rows,
+ num_schur_rows);
+ schur_solution = lhs->selfadjointView<Eigen::Upper>().llt().solve(*rhs);
+ eliminator->BackSubstitute(A_.get(), b_.get(), D,
+ schur_solution.data(), solution->data());
}
AssertionResult TestImplicitSchurComplement(double* D) {
@@ -163,11 +158,8 @@
}
// Reference solution to the f_block.
- Vector reference_f_sol(rhs.rows());
- SolveUpperTriangularUsingCholesky(lhs.rows(),
- lhs.data(),
- rhs.data(),
- reference_f_sol.data());
+ const Vector reference_f_sol =
+ lhs.selfadjointView<Eigen::Upper>().llt().solve(rhs);
// Backsubstituted solution from the implicit schur solver using the
// reference solution to the f_block.
diff --git a/internal/ceres/schur_complement_solver.cc b/internal/ceres/schur_complement_solver.cc
index 6b1a458..2491060 100644
--- a/internal/ceres/schur_complement_solver.cc
+++ b/internal/ceres/schur_complement_solver.cc
@@ -43,7 +43,6 @@
#include "ceres/conjugate_gradients_solver.h"
#include "ceres/cxsparse.h"
#include "ceres/detect_structure.h"
-#include "ceres/eigen_dense_cholesky.h"
#include "ceres/internal/eigen.h"
#include "ceres/internal/scoped_ptr.h"
#include "ceres/lapack.h"
@@ -53,6 +52,7 @@
#include "ceres/triplet_sparse_matrix.h"
#include "ceres/types.h"
#include "ceres/wall_time.h"
+#include "Eigen/Dense"
#include "Eigen/SparseCore"
namespace ceres {
@@ -198,13 +198,18 @@
summary.num_iterations = 1;
if (options().dense_linear_algebra_library_type == EIGEN) {
- if (SolveUpperTriangularUsingCholesky(num_rows, m->values(), rhs(), solution)
- != Eigen::Success) {
+ Eigen::LLT<Matrix, Eigen::Upper> llt =
+ ConstMatrixRef(m->values(), num_rows, num_rows)
+ .selfadjointView<Eigen::Upper>()
+ .llt();
+ if (llt.info() != Eigen::Success) {
summary.termination_type = LINEAR_SOLVER_FAILURE;
summary.message =
"Eigen failure. Unable to perform dense Cholesky factorization.";
return summary;
}
+
+ VectorRef(solution, num_rows) = llt.solve(ConstVectorRef(rhs(), num_rows));
} else {
VectorRef(solution, num_rows) = ConstVectorRef(rhs(), num_rows);
summary.termination_type =
diff --git a/internal/ceres/schur_eliminator_impl.h b/internal/ceres/schur_eliminator_impl.h
index 50f7e66..7e06806 100644
--- a/internal/ceres/schur_eliminator_impl.h
+++ b/internal/ceres/schur_eliminator_impl.h
@@ -57,7 +57,6 @@
#include "ceres/block_random_access_matrix.h"
#include "ceres/block_sparse_matrix.h"
#include "ceres/block_structure.h"
-#include "ceres/eigen_dense_cholesky.h"
#include "ceres/internal/eigen.h"
#include "ceres/internal/fixed_array.h"
#include "ceres/internal/scoped_ptr.h"
@@ -269,11 +268,11 @@
// which case its much faster to compute the inverse once and
// use it to multiply other matrices/vectors instead of doing a
// Solve call over and over again.
- typename EigenTypes<kEBlockSize, kEBlockSize>::Matrix
- inverse_ete(e_block_size, e_block_size);
- InvertUpperTriangularUsingCholesky(e_block_size,
- ete.data(),
- inverse_ete.data());
+ typename EigenTypes<kEBlockSize, kEBlockSize>::Matrix inverse_ete =
+ ete
+ .template selfadjointView<Eigen::Upper>()
+ .llt()
+ .solve(Matrix::Identity(e_block_size, e_block_size));
// For the current chunk compute and update the rhs of the reduced
// linear system.
@@ -362,18 +361,7 @@
ete.data(), 0, 0, e_block_size, e_block_size);
}
- // On ARM we have experienced significant numerical problems with
- // Eigen's LLT implementation. Defining
- // CERES_USE_LDLT_FOR_EIGEN_CHOLESKY switches to using the slightly
- // more expensive but much more numerically well behaved LDLT
- // factorization algorithm.
-
-#ifdef CERES_USE_LDLT_FOR_EIGEN_CHOLESKY
- ete.ldlt().solveInPlace(y_block);
-#else
ete.llt().solveInPlace(y_block);
-#endif
-
}
}
diff --git a/internal/ceres/schur_eliminator_test.cc b/internal/ceres/schur_eliminator_test.cc
index 8217e8c..40bc904 100644
--- a/internal/ceres/schur_eliminator_test.cc
+++ b/internal/ceres/schur_eliminator_test.cc
@@ -35,7 +35,6 @@
#include "ceres/block_sparse_matrix.h"
#include "ceres/casts.h"
#include "ceres/detect_structure.h"
-#include "ceres/eigen_dense_cholesky.h"
#include "ceres/internal/eigen.h"
#include "ceres/internal/scoped_ptr.h"
#include "ceres/linear_least_squares_problems.h"
@@ -122,10 +121,7 @@
.triangularView<Eigen::Upper>() = R - Q.transpose() * P * Q;
rhs_expected =
g.tail(schur_size) - Q.transpose() * P * g.head(num_eliminate_cols);
- SolveUpperTriangularUsingCholesky(H.rows(),
- H.data(),
- g.data(),
- sol_expected.data());
+ sol_expected = H.llt().solve(g);
}
void EliminateSolveAndCompare(const VectorRef& diagonal,
@@ -161,11 +157,11 @@
eliminator->Eliminate(A.get(), b.get(), diagonal.data(), &lhs, rhs.data());
MatrixRef lhs_ref(lhs.mutable_values(), lhs.num_rows(), lhs.num_cols());
- Vector reduced_sol(lhs.num_rows());
- SolveUpperTriangularUsingCholesky(lhs.num_cols(),
- lhs.values(),
- rhs.data(),
- reduced_sol.data());
+ Vector reduced_sol =
+ lhs_ref
+ .selfadjointView<Eigen::Upper>()
+ .llt()
+ .solve(rhs);
// Solution to the linear least squares problem.
Vector sol(num_cols);
diff --git a/jni/Android.mk b/jni/Android.mk
index 2a9d337..d49ab4a 100644
--- a/jni/Android.mk
+++ b/jni/Android.mk
@@ -105,12 +105,6 @@
-DCERES_NO_CXSPARSE \
-DCERES_STD_UNORDERED_MAP
-# On ARM we have experienced significant numerical problems with
-# Eigen's LLT implementation. Defining
-# CERES_USE_LDLT_FOR_EIGEN_CHOLESKY switches to using the slightly
-# more expensive but much more numerically well behaved LDLT
-# factorization algorithm.
-LOCAL_CFLAGS += -DCERES_USE_LDLT_FOR_EIGEN_CHOLESKY
# If the user did not enable threads in CERES_EXTRA_DEFINES, then add
# CERES_NO_THREADS.
@@ -150,7 +144,6 @@
$(CERES_SRC_PATH)/dogleg_strategy.cc \
$(CERES_SRC_PATH)/dynamic_compressed_row_jacobian_writer.cc \
$(CERES_SRC_PATH)/dynamic_compressed_row_sparse_matrix.cc \
- $(CERES_SRC_PATH)/eigen_dense_cholesky.cc \
$(CERES_SRC_PATH)/evaluator.cc \
$(CERES_SRC_PATH)/file.cc \
$(CERES_SRC_PATH)/gradient_checking_cost_function.cc \