blob: 4f1bf87669022af74feb35f74b878d7c6477346e [file] [log] [blame]
Austin Schuh70cc9552019-01-21 19:46:48 -08001// Ceres Solver - A fast non-linear least squares minimizer
Austin Schuh3de38b02024-06-25 18:25:10 -07002// Copyright 2023 Google Inc. All rights reserved.
Austin Schuh70cc9552019-01-21 19:46:48 -08003// http://ceres-solver.org/
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are met:
7//
8// * Redistributions of source code must retain the above copyright notice,
9// this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above copyright notice,
11// this list of conditions and the following disclaimer in the documentation
12// and/or other materials provided with the distribution.
13// * Neither the name of Google Inc. nor the names of its contributors may be
14// used to endorse or promote products derived from this software without
15// specific prior written permission.
16//
17// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27// POSSIBILITY OF SUCH DAMAGE.
28//
29// Author: sameeragarwal@google.com (Sameer Agarwal)
30
31#include "ceres/sparse_cholesky.h"
32
Austin Schuh3de38b02024-06-25 18:25:10 -070033#include <memory>
34#include <utility>
35
Austin Schuh70cc9552019-01-21 19:46:48 -080036#include "ceres/accelerate_sparse.h"
Austin Schuh70cc9552019-01-21 19:46:48 -080037#include "ceres/eigensparse.h"
Austin Schuh70cc9552019-01-21 19:46:48 -080038#include "ceres/float_suitesparse.h"
39#include "ceres/iterative_refiner.h"
40#include "ceres/suitesparse.h"
41
Austin Schuh3de38b02024-06-25 18:25:10 -070042namespace ceres::internal {
Austin Schuh70cc9552019-01-21 19:46:48 -080043
44std::unique_ptr<SparseCholesky> SparseCholesky::Create(
45 const LinearSolver::Options& options) {
Austin Schuh70cc9552019-01-21 19:46:48 -080046 std::unique_ptr<SparseCholesky> sparse_cholesky;
47
48 switch (options.sparse_linear_algebra_library_type) {
49 case SUITE_SPARSE:
50#ifndef CERES_NO_SUITESPARSE
51 if (options.use_mixed_precision_solves) {
Austin Schuh3de38b02024-06-25 18:25:10 -070052 sparse_cholesky =
53 FloatSuiteSparseCholesky::Create(options.ordering_type);
Austin Schuh70cc9552019-01-21 19:46:48 -080054 } else {
Austin Schuh3de38b02024-06-25 18:25:10 -070055 sparse_cholesky = SuiteSparseCholesky::Create(options.ordering_type);
Austin Schuh70cc9552019-01-21 19:46:48 -080056 }
57 break;
58#else
59 LOG(FATAL) << "Ceres was compiled without support for SuiteSparse.";
60#endif
61
62 case EIGEN_SPARSE:
63#ifdef CERES_USE_EIGEN_SPARSE
64 if (options.use_mixed_precision_solves) {
Austin Schuh3de38b02024-06-25 18:25:10 -070065 sparse_cholesky =
66 FloatEigenSparseCholesky::Create(options.ordering_type);
Austin Schuh70cc9552019-01-21 19:46:48 -080067 } else {
Austin Schuh3de38b02024-06-25 18:25:10 -070068 sparse_cholesky = EigenSparseCholesky::Create(options.ordering_type);
Austin Schuh70cc9552019-01-21 19:46:48 -080069 }
70 break;
71#else
72 LOG(FATAL) << "Ceres was compiled without support for "
73 << "Eigen's sparse Cholesky factorization routines.";
74#endif
75
Austin Schuh70cc9552019-01-21 19:46:48 -080076 case ACCELERATE_SPARSE:
77#ifndef CERES_NO_ACCELERATE_SPARSE
78 if (options.use_mixed_precision_solves) {
Austin Schuh3de38b02024-06-25 18:25:10 -070079 sparse_cholesky =
80 AppleAccelerateCholesky<float>::Create(options.ordering_type);
Austin Schuh70cc9552019-01-21 19:46:48 -080081 } else {
Austin Schuh1d1e6ea2020-12-23 21:56:30 -080082 sparse_cholesky =
Austin Schuh3de38b02024-06-25 18:25:10 -070083 AppleAccelerateCholesky<double>::Create(options.ordering_type);
Austin Schuh70cc9552019-01-21 19:46:48 -080084 }
85 break;
86#else
87 LOG(FATAL) << "Ceres was compiled without support for Apple's Accelerate "
88 << "framework solvers.";
89#endif
90
91 default:
92 LOG(FATAL) << "Unknown sparse linear algebra library type : "
93 << SparseLinearAlgebraLibraryTypeToString(
94 options.sparse_linear_algebra_library_type);
95 }
96
97 if (options.max_num_refinement_iterations > 0) {
Austin Schuh3de38b02024-06-25 18:25:10 -070098 auto refiner = std::make_unique<SparseIterativeRefiner>(
99 options.max_num_refinement_iterations);
100 sparse_cholesky = std::make_unique<RefinedSparseCholesky>(
101 std::move(sparse_cholesky), std::move(refiner));
Austin Schuh70cc9552019-01-21 19:46:48 -0800102 }
103 return sparse_cholesky;
104}
105
Austin Schuh3de38b02024-06-25 18:25:10 -0700106SparseCholesky::~SparseCholesky() = default;
Austin Schuh70cc9552019-01-21 19:46:48 -0800107
108LinearSolverTerminationType SparseCholesky::FactorAndSolve(
109 CompressedRowSparseMatrix* lhs,
110 const double* rhs,
111 double* solution,
112 std::string* message) {
113 LinearSolverTerminationType termination_type = Factorize(lhs, message);
Austin Schuh3de38b02024-06-25 18:25:10 -0700114 if (termination_type == LinearSolverTerminationType::SUCCESS) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800115 termination_type = Solve(rhs, solution, message);
116 }
117 return termination_type;
118}
119
Austin Schuh70cc9552019-01-21 19:46:48 -0800120RefinedSparseCholesky::RefinedSparseCholesky(
121 std::unique_ptr<SparseCholesky> sparse_cholesky,
Austin Schuh3de38b02024-06-25 18:25:10 -0700122 std::unique_ptr<SparseIterativeRefiner> iterative_refiner)
Austin Schuh70cc9552019-01-21 19:46:48 -0800123 : sparse_cholesky_(std::move(sparse_cholesky)),
124 iterative_refiner_(std::move(iterative_refiner)) {}
125
Austin Schuh3de38b02024-06-25 18:25:10 -0700126RefinedSparseCholesky::~RefinedSparseCholesky() = default;
Austin Schuh70cc9552019-01-21 19:46:48 -0800127
128CompressedRowSparseMatrix::StorageType RefinedSparseCholesky::StorageType()
129 const {
130 return sparse_cholesky_->StorageType();
131}
132
133LinearSolverTerminationType RefinedSparseCholesky::Factorize(
134 CompressedRowSparseMatrix* lhs, std::string* message) {
135 lhs_ = lhs;
136 return sparse_cholesky_->Factorize(lhs, message);
137}
138
139LinearSolverTerminationType RefinedSparseCholesky::Solve(const double* rhs,
140 double* solution,
141 std::string* message) {
142 CHECK(lhs_ != nullptr);
143 auto termination_type = sparse_cholesky_->Solve(rhs, solution, message);
Austin Schuh3de38b02024-06-25 18:25:10 -0700144 if (termination_type != LinearSolverTerminationType::SUCCESS) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800145 return termination_type;
146 }
147
148 iterative_refiner_->Refine(*lhs_, rhs, sparse_cholesky_.get(), solution);
Austin Schuh3de38b02024-06-25 18:25:10 -0700149 return LinearSolverTerminationType::SUCCESS;
Austin Schuh70cc9552019-01-21 19:46:48 -0800150}
151
Austin Schuh3de38b02024-06-25 18:25:10 -0700152} // namespace ceres::internal