mirror of
https://github.com/ceres-solver/ceres-solver.git
synced 2026-08-29 16:40:38 +08:00
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
This commit is contained 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@
|
||||
|
||||
|
||||
@@ -61,7 +61,6 @@ SET(CERES_INTERNAL_SRC
|
||||
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
|
||||
|
||||
@@ -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 @@ void BlockRandomAccessDiagonalMatrix::Invert() {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 @@ TEST_F(BlockRandomAccessDiagonalMatrixTest, Invert) {
|
||||
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);
|
||||
|
||||
|
||||
@@ -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 DenseNormalCholeskySolver::SolveUsingEigen(
|
||||
|
||||
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 @@ LinearSolver::Summary DenseNormalCholeskySolver::SolveUsingEigen(
|
||||
summary.message = "Success.";
|
||||
}
|
||||
|
||||
VectorRef(x, num_cols) = llt.solve(rhs);
|
||||
event_logger.AddEvent("Solve");
|
||||
return summary;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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 @@ void ImplicitSchurComplement::AddDiagonalAndInvert(
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 @@ class ImplicitSchurComplementTest : public ::testing::Test {
|
||||
|
||||
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 @@ class ImplicitSchurComplementTest : public ::testing::Test {
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
||||
@@ -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 @@ DenseSchurComplementSolver::SolveReducedLinearSystem(
|
||||
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 =
|
||||
|
||||
@@ -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 @@ Eliminate(const BlockSparseMatrix* A,
|
||||
// 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 @@ BackSubstitute(const BlockSparseMatrix* A,
|
||||
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
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 @@ class SchurEliminatorTest : public ::testing::Test {
|
||||
.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 @@ class SchurEliminatorTest : public ::testing::Test {
|
||||
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);
|
||||
|
||||
@@ -105,12 +105,6 @@ LOCAL_CFLAGS := $(CERES_EXTRA_DEFINES) \
|
||||
-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 @@ LOCAL_SRC_FILES := $(CERES_SRC_PATH)/array_utils.cc \
|
||||
$(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 \
|
||||
|
||||
Reference in New Issue
Block a user