blob: 5e93d2e54d68dd81e4046ec4ea988fdc8c0ec468 [file] [log] [blame]
Keir Mierle8ebb0732012-04-30 23:09:08 -07001// Ceres Solver - A fast non-linear least squares minimizer
Keir Mierle7492b0d2015-03-17 22:30:16 -07002// Copyright 2015 Google Inc. All rights reserved.
3// http://ceres-solver.org/
Keir Mierle8ebb0732012-04-30 23:09:08 -07004//
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
Alex Stewartea765852014-05-07 20:46:17 +010031// This include must come before any #ifndef check on Ceres compile options.
32#include "ceres/internal/port.h"
33
Keir Mierle8ebb0732012-04-30 23:09:08 -070034#ifndef CERES_NO_SUITESPARSE
Keir Mierle8ebb0732012-04-30 23:09:08 -070035#include "ceres/suitesparse.h"
36
Sameer Agarwal7a3c43b2012-06-05 23:10:59 -070037#include <vector>
Sameer Agarwal29c21f52017-04-12 12:48:44 -070038
Sameer Agarwal344c09f2013-04-20 16:07:56 -070039#include "ceres/compressed_col_sparse_matrix_utils.h"
Keir Mierle8ebb0732012-04-30 23:09:08 -070040#include "ceres/compressed_row_sparse_matrix.h"
Sameer Agarwal79bde352013-11-21 21:33:51 -080041#include "ceres/linear_solver.h"
Keir Mierle8ebb0732012-04-30 23:09:08 -070042#include "ceres/triplet_sparse_matrix.h"
Sameer Agarwal29c21f52017-04-12 12:48:44 -070043#include "cholmod.h"
Sameer Agarwal222ca202013-04-01 09:11:07 -070044
Keir Mierle8ebb0732012-04-30 23:09:08 -070045namespace ceres {
46namespace internal {
Sameer Agarwal222ca202013-04-01 09:11:07 -070047
Sameer Agarwal05a07ec2015-01-07 15:10:46 -080048using std::string;
Sameer Agarwalbcc865f2014-12-17 07:35:09 -080049using std::vector;
50
Sameer Agarwal29c21f52017-04-12 12:48:44 -070051SuiteSparse::SuiteSparse() { cholmod_start(&cc_); }
Sameer Agarwal222ca202013-04-01 09:11:07 -070052
Sameer Agarwal29c21f52017-04-12 12:48:44 -070053SuiteSparse::~SuiteSparse() { cholmod_finish(&cc_); }
Sameer Agarwal222ca202013-04-01 09:11:07 -070054
Keir Mierle8ebb0732012-04-30 23:09:08 -070055cholmod_sparse* SuiteSparse::CreateSparseMatrix(TripletSparseMatrix* A) {
56 cholmod_triplet triplet;
57
58 triplet.nrow = A->num_rows();
59 triplet.ncol = A->num_cols();
60 triplet.nzmax = A->max_num_nonzeros();
61 triplet.nnz = A->num_nonzeros();
62 triplet.i = reinterpret_cast<void*>(A->mutable_rows());
63 triplet.j = reinterpret_cast<void*>(A->mutable_cols());
64 triplet.x = reinterpret_cast<void*>(A->mutable_values());
65 triplet.stype = 0; // Matrix is not symmetric.
66 triplet.itype = CHOLMOD_INT;
67 triplet.xtype = CHOLMOD_REAL;
68 triplet.dtype = CHOLMOD_DOUBLE;
69
70 return cholmod_triplet_to_sparse(&triplet, triplet.nnz, &cc_);
71}
72
Keir Mierle8ebb0732012-04-30 23:09:08 -070073cholmod_sparse* SuiteSparse::CreateSparseMatrixTranspose(
74 TripletSparseMatrix* A) {
75 cholmod_triplet triplet;
76
77 triplet.ncol = A->num_rows(); // swap row and columns
78 triplet.nrow = A->num_cols();
79 triplet.nzmax = A->max_num_nonzeros();
80 triplet.nnz = A->num_nonzeros();
81
82 // swap rows and columns
83 triplet.j = reinterpret_cast<void*>(A->mutable_rows());
84 triplet.i = reinterpret_cast<void*>(A->mutable_cols());
85 triplet.x = reinterpret_cast<void*>(A->mutable_values());
86 triplet.stype = 0; // Matrix is not symmetric.
87 triplet.itype = CHOLMOD_INT;
88 triplet.xtype = CHOLMOD_REAL;
89 triplet.dtype = CHOLMOD_DOUBLE;
90
91 return cholmod_triplet_to_sparse(&triplet, triplet.nnz, &cc_);
92}
93
Sameer Agarwal2560b172013-04-19 08:19:11 -070094cholmod_sparse SuiteSparse::CreateSparseMatrixTransposeView(
Sameer Agarwal2755fce2017-04-10 21:13:29 -070095 CompressedRowSparseMatrix* A) {
Sameer Agarwal2560b172013-04-19 08:19:11 -070096 cholmod_sparse m;
97 m.nrow = A->num_cols();
98 m.ncol = A->num_rows();
99 m.nzmax = A->num_nonzeros();
100 m.nz = NULL;
101 m.p = reinterpret_cast<void*>(A->mutable_rows());
102 m.i = reinterpret_cast<void*>(A->mutable_cols());
103 m.x = reinterpret_cast<void*>(A->mutable_values());
104 m.z = NULL;
Sameer Agarwal2755fce2017-04-10 21:13:29 -0700105
106 if (A->storage_type() == CompressedRowSparseMatrix::LOWER_TRIANGULAR) {
107 m.stype = 1;
108 } else if (A->storage_type() == CompressedRowSparseMatrix::UPPER_TRIANGULAR) {
109 m.stype = -1;
110 } else {
111 m.stype = 0;
112 }
113
Sameer Agarwal2560b172013-04-19 08:19:11 -0700114 m.itype = CHOLMOD_INT;
115 m.xtype = CHOLMOD_REAL;
116 m.dtype = CHOLMOD_DOUBLE;
117 m.sorted = 1;
118 m.packed = 1;
Keir Mierle8ebb0732012-04-30 23:09:08 -0700119
120 return m;
121}
122
123cholmod_dense* SuiteSparse::CreateDenseVector(const double* x,
124 int in_size,
125 int out_size) {
Sameer Agarwal29c21f52017-04-12 12:48:44 -0700126 CHECK_LE(in_size, out_size);
127 cholmod_dense* v = cholmod_zeros(out_size, 1, CHOLMOD_REAL, &cc_);
128 if (x != NULL) {
129 memcpy(v->x, x, in_size * sizeof(*x));
130 }
131 return v;
Keir Mierle8ebb0732012-04-30 23:09:08 -0700132}
133
Sameer Agarwalb16e1182013-11-25 05:47:43 -0800134cholmod_factor* SuiteSparse::AnalyzeCholesky(cholmod_sparse* A,
Sameer Agarwaled923662013-11-28 06:50:43 -0800135 string* message) {
Sameer Agarwal7a3c43b2012-06-05 23:10:59 -0700136 // Cholmod can try multiple re-ordering strategies to find a fill
137 // reducing ordering. Here we just tell it use AMD with automatic
138 // matrix dependence choice of supernodal versus simplicial
139 // factorization.
140 cc_.nmethods = 1;
141 cc_.method[0].ordering = CHOLMOD_AMD;
142 cc_.supernodal = CHOLMOD_AUTO;
Sameer Agarwal222ca202013-04-01 09:11:07 -0700143
Keir Mierle8ebb0732012-04-30 23:09:08 -0700144 cholmod_factor* factor = cholmod_analyze(A, &cc_);
Sameer Agarwal222ca202013-04-01 09:11:07 -0700145 if (VLOG_IS_ON(2)) {
146 cholmod_print_common(const_cast<char*>("Symbolic Analysis"), &cc_);
147 }
148
Sameer Agarwalb16e1182013-11-25 05:47:43 -0800149 if (cc_.status != CHOLMOD_OK) {
Sameer Agarwal29c21f52017-04-12 12:48:44 -0700150 *message =
151 StringPrintf("cholmod_analyze failed. error code: %d", cc_.status);
Sameer Agarwalb16e1182013-11-25 05:47:43 -0800152 return NULL;
153 }
154
155 return CHECK_NOTNULL(factor);
Keir Mierle8ebb0732012-04-30 23:09:08 -0700156}
157
Sameer Agarwal29c21f52017-04-12 12:48:44 -0700158cholmod_factor* SuiteSparse::BlockAnalyzeCholesky(cholmod_sparse* A,
159 const vector<int>& row_blocks,
160 const vector<int>& col_blocks,
161 string* message) {
Sameer Agarwal7a3c43b2012-06-05 23:10:59 -0700162 vector<int> ordering;
163 if (!BlockAMDOrdering(A, row_blocks, col_blocks, &ordering)) {
164 return NULL;
165 }
Sameer Agarwaled923662013-11-28 06:50:43 -0800166 return AnalyzeCholeskyWithUserOrdering(A, ordering, message);
Sameer Agarwal7a3c43b2012-06-05 23:10:59 -0700167}
168
Sameer Agarwal509f68c2013-02-20 01:39:03 -0800169cholmod_factor* SuiteSparse::AnalyzeCholeskyWithUserOrdering(
Sameer Agarwal29c21f52017-04-12 12:48:44 -0700170 cholmod_sparse* A, const vector<int>& ordering, string* message) {
Sameer Agarwal7a3c43b2012-06-05 23:10:59 -0700171 CHECK_EQ(ordering.size(), A->nrow);
Sameer Agarwal222ca202013-04-01 09:11:07 -0700172
Sameer Agarwal509f68c2013-02-20 01:39:03 -0800173 cc_.nmethods = 1;
Sameer Agarwal7a3c43b2012-06-05 23:10:59 -0700174 cc_.method[0].ordering = CHOLMOD_GIVEN;
Sameer Agarwal222ca202013-04-01 09:11:07 -0700175
Sameer Agarwal29c21f52017-04-12 12:48:44 -0700176 cholmod_factor* factor =
Sameer Agarwal7a3c43b2012-06-05 23:10:59 -0700177 cholmod_analyze_p(A, const_cast<int*>(&ordering[0]), NULL, 0, &cc_);
Sameer Agarwal222ca202013-04-01 09:11:07 -0700178 if (VLOG_IS_ON(2)) {
179 cholmod_print_common(const_cast<char*>("Symbolic Analysis"), &cc_);
180 }
Sameer Agarwalb16e1182013-11-25 05:47:43 -0800181 if (cc_.status != CHOLMOD_OK) {
Sameer Agarwal29c21f52017-04-12 12:48:44 -0700182 *message =
183 StringPrintf("cholmod_analyze failed. error code: %d", cc_.status);
Sameer Agarwalb16e1182013-11-25 05:47:43 -0800184 return NULL;
185 }
Sameer Agarwal222ca202013-04-01 09:11:07 -0700186
Sameer Agarwalb16e1182013-11-25 05:47:43 -0800187 return CHECK_NOTNULL(factor);
Sameer Agarwal7a3c43b2012-06-05 23:10:59 -0700188}
189
Sameer Agarwalcbdeb792013-04-22 10:18:18 -0700190cholmod_factor* SuiteSparse::AnalyzeCholeskyWithNaturalOrdering(
Sameer Agarwal29c21f52017-04-12 12:48:44 -0700191 cholmod_sparse* A, string* message) {
Sameer Agarwal2560b172013-04-19 08:19:11 -0700192 cc_.nmethods = 1;
193 cc_.method[0].ordering = CHOLMOD_NATURAL;
194 cc_.postorder = 0;
195
Sameer Agarwal29c21f52017-04-12 12:48:44 -0700196 cholmod_factor* factor = cholmod_analyze(A, &cc_);
Sameer Agarwal2560b172013-04-19 08:19:11 -0700197 if (VLOG_IS_ON(2)) {
198 cholmod_print_common(const_cast<char*>("Symbolic Analysis"), &cc_);
199 }
Sameer Agarwalb16e1182013-11-25 05:47:43 -0800200 if (cc_.status != CHOLMOD_OK) {
Sameer Agarwal29c21f52017-04-12 12:48:44 -0700201 *message =
202 StringPrintf("cholmod_analyze failed. error code: %d", cc_.status);
Sameer Agarwalb16e1182013-11-25 05:47:43 -0800203 return NULL;
204 }
Sameer Agarwal2560b172013-04-19 08:19:11 -0700205
Sameer Agarwalb16e1182013-11-25 05:47:43 -0800206 return CHECK_NOTNULL(factor);
Sameer Agarwal2560b172013-04-19 08:19:11 -0700207}
208
Sameer Agarwal7a3c43b2012-06-05 23:10:59 -0700209bool SuiteSparse::BlockAMDOrdering(const cholmod_sparse* A,
210 const vector<int>& row_blocks,
211 const vector<int>& col_blocks,
212 vector<int>* ordering) {
213 const int num_row_blocks = row_blocks.size();
214 const int num_col_blocks = col_blocks.size();
215
216 // Arrays storing the compressed column structure of the matrix
217 // incoding the block sparsity of A.
218 vector<int> block_cols;
219 vector<int> block_rows;
220
Sameer Agarwal344c09f2013-04-20 16:07:56 -0700221 CompressedColumnScalarMatrixToBlockMatrix(reinterpret_cast<const int*>(A->i),
222 reinterpret_cast<const int*>(A->p),
223 row_blocks,
224 col_blocks,
225 &block_rows,
226 &block_cols);
Sameer Agarwal7a3c43b2012-06-05 23:10:59 -0700227 cholmod_sparse_struct block_matrix;
228 block_matrix.nrow = num_row_blocks;
229 block_matrix.ncol = num_col_blocks;
230 block_matrix.nzmax = block_rows.size();
231 block_matrix.p = reinterpret_cast<void*>(&block_cols[0]);
232 block_matrix.i = reinterpret_cast<void*>(&block_rows[0]);
233 block_matrix.x = NULL;
234 block_matrix.stype = A->stype;
235 block_matrix.itype = CHOLMOD_INT;
236 block_matrix.xtype = CHOLMOD_PATTERN;
237 block_matrix.dtype = CHOLMOD_DOUBLE;
238 block_matrix.sorted = 1;
239 block_matrix.packed = 1;
240
241 vector<int> block_ordering(num_row_blocks);
242 if (!cholmod_amd(&block_matrix, NULL, 0, &block_ordering[0], &cc_)) {
243 return false;
244 }
245
246 BlockOrderingToScalarOrdering(row_blocks, block_ordering, ordering);
247 return true;
248}
249
Sameer Agarwalb16e1182013-11-25 05:47:43 -0800250LinearSolverTerminationType SuiteSparse::Cholesky(cholmod_sparse* A,
251 cholmod_factor* L,
Sameer Agarwaled923662013-11-28 06:50:43 -0800252 string* message) {
Keir Mierle8ebb0732012-04-30 23:09:08 -0700253 CHECK_NOTNULL(A);
254 CHECK_NOTNULL(L);
255
Sameer Agarwal222ca202013-04-01 09:11:07 -0700256 // Save the current print level and silence CHOLMOD, otherwise
257 // CHOLMOD is prone to dumping stuff to stderr, which can be
258 // distracting when the error (matrix is indefinite) is not a fatal
259 // failure.
260 const int old_print_level = cc_.print;
261 cc_.print = 0;
262
Keir Mierle8ebb0732012-04-30 23:09:08 -0700263 cc_.quick_return_if_not_posdef = 1;
Sameer Agarwalb16e1182013-11-25 05:47:43 -0800264 int cholmod_status = cholmod_factorize(A, L, &cc_);
Sameer Agarwal222ca202013-04-01 09:11:07 -0700265 cc_.print = old_print_level;
266
Keir Mierle8ebb0732012-04-30 23:09:08 -0700267 switch (cc_.status) {
268 case CHOLMOD_NOT_INSTALLED:
Sameer Agarwaled923662013-11-28 06:50:43 -0800269 *message = "CHOLMOD failure: Method not installed.";
Sameer Agarwal33e01b92013-11-27 10:24:03 -0800270 return LINEAR_SOLVER_FATAL_ERROR;
Keir Mierle8ebb0732012-04-30 23:09:08 -0700271 case CHOLMOD_OUT_OF_MEMORY:
Sameer Agarwaled923662013-11-28 06:50:43 -0800272 *message = "CHOLMOD failure: Out of memory.";
Sameer Agarwal33e01b92013-11-27 10:24:03 -0800273 return LINEAR_SOLVER_FATAL_ERROR;
Keir Mierle8ebb0732012-04-30 23:09:08 -0700274 case CHOLMOD_TOO_LARGE:
Sameer Agarwal7ed9e2f2016-10-19 04:45:23 -0700275 *message = "CHOLMOD failure: Integer overflow occurred.";
Sameer Agarwal33e01b92013-11-27 10:24:03 -0800276 return LINEAR_SOLVER_FATAL_ERROR;
Keir Mierle8ebb0732012-04-30 23:09:08 -0700277 case CHOLMOD_INVALID:
Sameer Agarwaled923662013-11-28 06:50:43 -0800278 *message = "CHOLMOD failure: Invalid input.";
Sameer Agarwal33e01b92013-11-27 10:24:03 -0800279 return LINEAR_SOLVER_FATAL_ERROR;
Keir Mierle8ebb0732012-04-30 23:09:08 -0700280 case CHOLMOD_NOT_POSDEF:
Sameer Agarwaled923662013-11-28 06:50:43 -0800281 *message = "CHOLMOD warning: Matrix not positive definite.";
Sameer Agarwal33e01b92013-11-27 10:24:03 -0800282 return LINEAR_SOLVER_FAILURE;
Keir Mierle8ebb0732012-04-30 23:09:08 -0700283 case CHOLMOD_DSMALL:
Sameer Agarwal29c21f52017-04-12 12:48:44 -0700284 *message =
285 "CHOLMOD warning: D for LDL' or diag(L) or "
286 "LL' has tiny absolute value.";
Sameer Agarwal33e01b92013-11-27 10:24:03 -0800287 return LINEAR_SOLVER_FAILURE;
Keir Mierle8ebb0732012-04-30 23:09:08 -0700288 case CHOLMOD_OK:
Sameer Agarwal3faac6a2013-11-28 07:13:26 -0800289 if (cholmod_status != 0) {
Sameer Agarwal33e01b92013-11-27 10:24:03 -0800290 return LINEAR_SOLVER_SUCCESS;
Keir Mierle8ebb0732012-04-30 23:09:08 -0700291 }
Sameer Agarwalb16e1182013-11-25 05:47:43 -0800292
Sameer Agarwal29c21f52017-04-12 12:48:44 -0700293 *message =
294 "CHOLMOD failure: cholmod_factorize returned false "
Sameer Agarwald73acd02013-12-02 12:02:03 -0800295 "but cholmod_common::status is CHOLMOD_OK."
296 "Please report this to ceres-solver@googlegroups.com.";
Sameer Agarwal33e01b92013-11-27 10:24:03 -0800297 return LINEAR_SOLVER_FATAL_ERROR;
Keir Mierle8ebb0732012-04-30 23:09:08 -0700298 default:
Sameer Agarwal29c21f52017-04-12 12:48:44 -0700299 *message = StringPrintf(
300 "Unknown cholmod return code: %d. "
301 "Please report this to ceres-solver@googlegroups.com.",
302 cc_.status);
Sameer Agarwal33e01b92013-11-27 10:24:03 -0800303 return LINEAR_SOLVER_FATAL_ERROR;
Keir Mierle8ebb0732012-04-30 23:09:08 -0700304 }
Sameer Agarwalb16e1182013-11-25 05:47:43 -0800305
Sameer Agarwal33e01b92013-11-27 10:24:03 -0800306 return LINEAR_SOLVER_FATAL_ERROR;
Keir Mierle8ebb0732012-04-30 23:09:08 -0700307}
308
309cholmod_dense* SuiteSparse::Solve(cholmod_factor* L,
Sameer Agarwalb16e1182013-11-25 05:47:43 -0800310 cholmod_dense* b,
Sameer Agarwaled923662013-11-28 06:50:43 -0800311 string* message) {
Keir Mierle8ebb0732012-04-30 23:09:08 -0700312 if (cc_.status != CHOLMOD_OK) {
Sameer Agarwaled923662013-11-28 06:50:43 -0800313 *message = "cholmod_solve failed. CHOLMOD status is not CHOLMOD_OK";
Keir Mierle8ebb0732012-04-30 23:09:08 -0700314 return NULL;
315 }
316
317 return cholmod_solve(CHOLMOD_A, L, b, &cc_);
318}
319
Sameer Agarwalb16e1182013-11-25 05:47:43 -0800320bool SuiteSparse::ApproximateMinimumDegreeOrdering(cholmod_sparse* matrix,
Sameer Agarwalf7ed22e2013-04-19 14:24:48 -0700321 int* ordering) {
Sameer Agarwalb16e1182013-11-25 05:47:43 -0800322 return cholmod_amd(matrix, NULL, 0, ordering, &cc_);
Sameer Agarwalf7ed22e2013-04-19 14:24:48 -0700323}
324
Sameer Agarwalb16e1182013-11-25 05:47:43 -0800325bool SuiteSparse::ConstrainedApproximateMinimumDegreeOrdering(
Sameer Agarwal29c21f52017-04-12 12:48:44 -0700326 cholmod_sparse* matrix, int* constraints, int* ordering) {
Sameer Agarwald5b93bf2013-04-26 21:17:49 -0700327#ifndef CERES_NO_CAMD
Sameer Agarwalb16e1182013-11-25 05:47:43 -0800328 return cholmod_camd(matrix, NULL, 0, constraints, ordering, &cc_);
Sameer Agarwald5b93bf2013-04-26 21:17:49 -0700329#else
330 LOG(FATAL) << "Congratulations you have found a bug in Ceres."
331 << "Ceres Solver was compiled with SuiteSparse "
332 << "version 4.1.0 or less. Calling this function "
333 << "in that case is a bug. Please contact the"
Sameer Agarwal0e0a4542013-04-29 17:27:26 -0700334 << "the Ceres Solver developers.";
Sameer Agarwalb16e1182013-11-25 05:47:43 -0800335 return false;
Sameer Agarwald5b93bf2013-04-26 21:17:49 -0700336#endif
337}
338
Sameer Agarwal29c21f52017-04-12 12:48:44 -0700339SuiteSparseCholesky* SuiteSparseCholesky::Create(
340 const OrderingType ordering_type) {
341 return new SuiteSparseCholesky(ordering_type);
342}
343
344SuiteSparseCholesky::SuiteSparseCholesky(const OrderingType ordering_type)
345 : ordering_type_(ordering_type), factor_(NULL) {}
346
347SuiteSparseCholesky::~SuiteSparseCholesky() {
348 if (factor_ != NULL) {
349 ss_.Free(factor_);
350 }
351}
352
353LinearSolverTerminationType SuiteSparseCholesky::Factorize(
354 CompressedRowSparseMatrix* lhs, string* message) {
355 if (lhs == NULL) {
356 *message = "Failure: Input lhs is NULL.";
357 return LINEAR_SOLVER_FATAL_ERROR;
358 }
359
360 cholmod_sparse cholmod_lhs = ss_.CreateSparseMatrixTransposeView(lhs);
361
362 if (factor_ == NULL) {
363 if (ordering_type_ == NATURAL) {
364 factor_ = ss_.AnalyzeCholeskyWithNaturalOrdering(&cholmod_lhs, message);
365 } else {
366 if (!lhs->col_blocks().empty() && !(lhs->row_blocks().empty())) {
367 factor_ = ss_.BlockAnalyzeCholesky(
368 &cholmod_lhs, lhs->col_blocks(), lhs->row_blocks(), message);
369 } else {
370 factor_ = ss_.AnalyzeCholesky(&cholmod_lhs, message);
371 }
372 }
373
374 if (factor_ == NULL) {
375 return LINEAR_SOLVER_FATAL_ERROR;
376 }
377 }
378
379 return ss_.Cholesky(&cholmod_lhs, factor_, message);
380}
381
382CompressedRowSparseMatrix::StorageType SuiteSparseCholesky::StorageType()
383 const {
384 return ((ordering_type_ == NATURAL)
385 ? CompressedRowSparseMatrix::UPPER_TRIANGULAR
386 : CompressedRowSparseMatrix::LOWER_TRIANGULAR);
387}
388
389LinearSolverTerminationType SuiteSparseCholesky::Solve(const double* rhs,
390 double* solution,
391 string* message) {
392 // Error checking
393 if (factor_ == NULL) {
394 *message = "Solve called without a call to Factorize first.";
395 return LINEAR_SOLVER_FATAL_ERROR;
396 }
397
398 const int num_cols = factor_->n;
399 cholmod_dense* cholmod_dense_rhs =
400 ss_.CreateDenseVector(rhs, num_cols, num_cols);
401 cholmod_dense* cholmod_dense_solution =
402 ss_.Solve(factor_, cholmod_dense_rhs, message);
403 ss_.Free(cholmod_dense_rhs);
404 if (cholmod_dense_solution == NULL) {
405 return LINEAR_SOLVER_FAILURE;
406 }
407
408 memcpy(solution, cholmod_dense_solution->x, num_cols * sizeof(*solution));
Sameer Agarwal97cefd42017-05-24 01:17:03 -0700409 ss_.Free(cholmod_dense_solution);
Sameer Agarwal29c21f52017-04-12 12:48:44 -0700410 return LINEAR_SOLVER_SUCCESS;
411}
412
Keir Mierle8ebb0732012-04-30 23:09:08 -0700413} // namespace internal
414} // namespace ceres
415
416#endif // CERES_NO_SUITESPARSE