blob: 52bd5941211b15b8b14f806631b496f57cc154d1 [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/solver.h"
32
Austin Schuh1d1e6ea2020-12-23 21:56:30 -080033#include <cmath>
Austin Schuh70cc9552019-01-21 19:46:48 -080034#include <limits>
35#include <memory>
Austin Schuh3de38b02024-06-25 18:25:10 -070036#include <string>
Austin Schuh70cc9552019-01-21 19:46:48 -080037#include <vector>
Austin Schuh1d1e6ea2020-12-23 21:56:30 -080038
Austin Schuh70cc9552019-01-21 19:46:48 -080039#include "ceres/autodiff_cost_function.h"
Austin Schuh1d1e6ea2020-12-23 21:56:30 -080040#include "ceres/evaluation_callback.h"
Austin Schuh3de38b02024-06-25 18:25:10 -070041#include "ceres/manifold.h"
Austin Schuh70cc9552019-01-21 19:46:48 -080042#include "ceres/problem.h"
43#include "ceres/problem_impl.h"
Austin Schuh1d1e6ea2020-12-23 21:56:30 -080044#include "ceres/sized_cost_function.h"
45#include "gtest/gtest.h"
Austin Schuh70cc9552019-01-21 19:46:48 -080046
Austin Schuh3de38b02024-06-25 18:25:10 -070047namespace ceres::internal {
Austin Schuh70cc9552019-01-21 19:46:48 -080048
49TEST(SolverOptions, DefaultTrustRegionOptionsAreValid) {
50 Solver::Options options;
51 options.minimizer_type = TRUST_REGION;
Austin Schuh3de38b02024-06-25 18:25:10 -070052 std::string error;
Austin Schuh70cc9552019-01-21 19:46:48 -080053 EXPECT_TRUE(options.IsValid(&error)) << error;
54}
55
56TEST(SolverOptions, DefaultLineSearchOptionsAreValid) {
57 Solver::Options options;
58 options.minimizer_type = LINE_SEARCH;
Austin Schuh3de38b02024-06-25 18:25:10 -070059 std::string error;
Austin Schuh70cc9552019-01-21 19:46:48 -080060 EXPECT_TRUE(options.IsValid(&error)) << error;
61}
62
63struct QuadraticCostFunctor {
Austin Schuh1d1e6ea2020-12-23 21:56:30 -080064 template <typename T>
65 bool operator()(const T* const x, T* residual) const {
Austin Schuh70cc9552019-01-21 19:46:48 -080066 residual[0] = T(5.0) - *x;
67 return true;
68 }
69
70 static CostFunction* Create() {
71 return new AutoDiffCostFunction<QuadraticCostFunctor, 1, 1>(
72 new QuadraticCostFunctor);
73 }
74};
75
76struct RememberingCallback : public IterationCallback {
Austin Schuh1d1e6ea2020-12-23 21:56:30 -080077 explicit RememberingCallback(double* x) : calls(0), x(x) {}
Austin Schuh1d1e6ea2020-12-23 21:56:30 -080078 CallbackReturnType operator()(const IterationSummary& summary) final {
Austin Schuh70cc9552019-01-21 19:46:48 -080079 x_values.push_back(*x);
80 return SOLVER_CONTINUE;
81 }
82 int calls;
Austin Schuh1d1e6ea2020-12-23 21:56:30 -080083 double* x;
Austin Schuh70cc9552019-01-21 19:46:48 -080084 std::vector<double> x_values;
85};
86
87struct NoOpEvaluationCallback : EvaluationCallback {
Austin Schuh1d1e6ea2020-12-23 21:56:30 -080088 void PrepareForEvaluation(bool evaluate_jacobians,
89 bool new_evaluation_point) final {
90 (void)evaluate_jacobians;
91 (void)new_evaluation_point;
Austin Schuh70cc9552019-01-21 19:46:48 -080092 }
93};
94
Austin Schuh1d1e6ea2020-12-23 21:56:30 -080095TEST(Solver, UpdateStateEveryIterationOptionNoEvaluationCallback) {
Austin Schuh70cc9552019-01-21 19:46:48 -080096 double x = 50.0;
97 const double original_x = x;
98
Austin Schuh70cc9552019-01-21 19:46:48 -080099 Problem::Options problem_options;
Austin Schuh70cc9552019-01-21 19:46:48 -0800100 Problem problem(problem_options);
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800101 problem.AddResidualBlock(QuadraticCostFunctor::Create(), nullptr, &x);
Austin Schuh70cc9552019-01-21 19:46:48 -0800102
103 Solver::Options options;
104 options.linear_solver_type = DENSE_QR;
105
106 RememberingCallback callback(&x);
107 options.callbacks.push_back(&callback);
108
109 Solver::Summary summary;
110
111 int num_iterations;
112
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800113 // First: update_state_every_iteration=false, evaluation_callback=nullptr.
Austin Schuh70cc9552019-01-21 19:46:48 -0800114 Solve(options, &problem, &summary);
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800115 num_iterations =
116 summary.num_successful_steps + summary.num_unsuccessful_steps;
Austin Schuh70cc9552019-01-21 19:46:48 -0800117 EXPECT_GT(num_iterations, 1);
Austin Schuh3de38b02024-06-25 18:25:10 -0700118 for (double value : callback.x_values) {
119 EXPECT_EQ(50.0, value);
Austin Schuh70cc9552019-01-21 19:46:48 -0800120 }
121
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800122 // Second: update_state_every_iteration=true, evaluation_callback=nullptr.
Austin Schuh70cc9552019-01-21 19:46:48 -0800123 x = 50.0;
124 options.update_state_every_iteration = true;
125 callback.x_values.clear();
126 Solve(options, &problem, &summary);
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800127 num_iterations =
128 summary.num_successful_steps + summary.num_unsuccessful_steps;
Austin Schuh70cc9552019-01-21 19:46:48 -0800129 EXPECT_GT(num_iterations, 1);
130 EXPECT_EQ(original_x, callback.x_values[0]);
131 EXPECT_NE(original_x, callback.x_values[1]);
132}
133
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800134TEST(Solver, UpdateStateEveryIterationOptionWithEvaluationCallback) {
135 double x = 50.0;
136 const double original_x = x;
137
138 Problem::Options problem_options;
139 NoOpEvaluationCallback evaluation_callback;
140 problem_options.evaluation_callback = &evaluation_callback;
141
142 Problem problem(problem_options);
143 problem.AddResidualBlock(QuadraticCostFunctor::Create(), nullptr, &x);
144
145 Solver::Options options;
146 options.linear_solver_type = DENSE_QR;
147 RememberingCallback callback(&x);
148 options.callbacks.push_back(&callback);
149
150 Solver::Summary summary;
151
152 int num_iterations;
153
154 // First: update_state_every_iteration=true, evaluation_callback=!nullptr.
155 x = 50.0;
156 options.update_state_every_iteration = true;
157 callback.x_values.clear();
158 Solve(options, &problem, &summary);
159 num_iterations =
160 summary.num_successful_steps + summary.num_unsuccessful_steps;
161 EXPECT_GT(num_iterations, 1);
162 EXPECT_EQ(original_x, callback.x_values[0]);
163 EXPECT_NE(original_x, callback.x_values[1]);
164
165 // Second: update_state_every_iteration=false, evaluation_callback=!nullptr.
166 x = 50.0;
167 options.update_state_every_iteration = false;
168 callback.x_values.clear();
169 Solve(options, &problem, &summary);
170 num_iterations =
171 summary.num_successful_steps + summary.num_unsuccessful_steps;
172 EXPECT_GT(num_iterations, 1);
173 EXPECT_EQ(original_x, callback.x_values[0]);
174 EXPECT_NE(original_x, callback.x_values[1]);
175}
176
177TEST(Solver, CantMixEvaluationCallbackWithInnerIterations) {
178 double x = 50.0;
179 double y = 60.0;
180
181 Problem::Options problem_options;
182 NoOpEvaluationCallback evaluation_callback;
183 problem_options.evaluation_callback = &evaluation_callback;
184
185 Problem problem(problem_options);
186 problem.AddResidualBlock(QuadraticCostFunctor::Create(), nullptr, &x);
187 problem.AddResidualBlock(QuadraticCostFunctor::Create(), nullptr, &y);
188
189 Solver::Options options;
190 options.use_inner_iterations = true;
191 Solver::Summary summary;
192 Solve(options, &problem, &summary);
193 EXPECT_EQ(summary.termination_type, FAILURE);
194
195 options.use_inner_iterations = false;
196 Solve(options, &problem, &summary);
197 EXPECT_EQ(summary.termination_type, CONVERGENCE);
198}
199
Austin Schuh70cc9552019-01-21 19:46:48 -0800200// The parameters must be in separate blocks so that they can be individually
201// set constant or not.
202struct Quadratic4DCostFunction {
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800203 template <typename T>
204 bool operator()(const T* const x,
205 const T* const y,
206 const T* const z,
207 const T* const w,
208 T* residual) const {
Austin Schuh70cc9552019-01-21 19:46:48 -0800209 // A 4-dimension axis-aligned quadratic.
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800210 residual[0] = T(10.0) - *x + T(20.0) - *y + T(30.0) - *z + T(40.0) - *w;
Austin Schuh70cc9552019-01-21 19:46:48 -0800211 return true;
212 }
213
214 static CostFunction* Create() {
215 return new AutoDiffCostFunction<Quadratic4DCostFunction, 1, 1, 1, 1, 1>(
216 new Quadratic4DCostFunction);
217 }
218};
219
220// A cost function that simply returns its argument.
221class UnaryIdentityCostFunction : public SizedCostFunction<1, 1> {
222 public:
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800223 bool Evaluate(double const* const* parameters,
224 double* residuals,
225 double** jacobians) const final {
Austin Schuh70cc9552019-01-21 19:46:48 -0800226 residuals[0] = parameters[0][0];
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800227 if (jacobians != nullptr && jacobians[0] != nullptr) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800228 jacobians[0][0] = 1.0;
229 }
230 return true;
231 }
232};
233
234TEST(Solver, TrustRegionProblemHasNoParameterBlocks) {
235 Problem problem;
236 Solver::Options options;
237 options.minimizer_type = TRUST_REGION;
238 Solver::Summary summary;
239 Solve(options, &problem, &summary);
240 EXPECT_EQ(summary.termination_type, CONVERGENCE);
241 EXPECT_EQ(summary.message,
242 "Function tolerance reached. "
243 "No non-constant parameter blocks found.");
244}
245
246TEST(Solver, LineSearchProblemHasNoParameterBlocks) {
247 Problem problem;
248 Solver::Options options;
249 options.minimizer_type = LINE_SEARCH;
250 Solver::Summary summary;
251 Solve(options, &problem, &summary);
252 EXPECT_EQ(summary.termination_type, CONVERGENCE);
253 EXPECT_EQ(summary.message,
254 "Function tolerance reached. "
255 "No non-constant parameter blocks found.");
256}
257
258TEST(Solver, TrustRegionProblemHasZeroResiduals) {
259 Problem problem;
260 double x = 1;
261 problem.AddParameterBlock(&x, 1);
262 Solver::Options options;
263 options.minimizer_type = TRUST_REGION;
264 Solver::Summary summary;
265 Solve(options, &problem, &summary);
266 EXPECT_EQ(summary.termination_type, CONVERGENCE);
267 EXPECT_EQ(summary.message,
268 "Function tolerance reached. "
269 "No non-constant parameter blocks found.");
270}
271
272TEST(Solver, LineSearchProblemHasZeroResiduals) {
273 Problem problem;
274 double x = 1;
275 problem.AddParameterBlock(&x, 1);
276 Solver::Options options;
277 options.minimizer_type = LINE_SEARCH;
278 Solver::Summary summary;
279 Solve(options, &problem, &summary);
280 EXPECT_EQ(summary.termination_type, CONVERGENCE);
281 EXPECT_EQ(summary.message,
282 "Function tolerance reached. "
283 "No non-constant parameter blocks found.");
284}
285
286TEST(Solver, TrustRegionProblemIsConstant) {
287 Problem problem;
288 double x = 1;
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800289 problem.AddResidualBlock(new UnaryIdentityCostFunction, nullptr, &x);
Austin Schuh70cc9552019-01-21 19:46:48 -0800290 problem.SetParameterBlockConstant(&x);
291 Solver::Options options;
292 options.minimizer_type = TRUST_REGION;
293 Solver::Summary summary;
294 Solve(options, &problem, &summary);
295 EXPECT_EQ(summary.termination_type, CONVERGENCE);
296 EXPECT_EQ(summary.initial_cost, 1.0 / 2.0);
297 EXPECT_EQ(summary.final_cost, 1.0 / 2.0);
298}
299
300TEST(Solver, LineSearchProblemIsConstant) {
301 Problem problem;
302 double x = 1;
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800303 problem.AddResidualBlock(new UnaryIdentityCostFunction, nullptr, &x);
Austin Schuh70cc9552019-01-21 19:46:48 -0800304 problem.SetParameterBlockConstant(&x);
305 Solver::Options options;
306 options.minimizer_type = LINE_SEARCH;
307 Solver::Summary summary;
308 Solve(options, &problem, &summary);
309 EXPECT_EQ(summary.termination_type, CONVERGENCE);
310 EXPECT_EQ(summary.initial_cost, 1.0 / 2.0);
311 EXPECT_EQ(summary.final_cost, 1.0 / 2.0);
312}
313
Austin Schuh70cc9552019-01-21 19:46:48 -0800314template <int kNumResiduals, int... Ns>
315class DummyCostFunction : public SizedCostFunction<kNumResiduals, Ns...> {
316 public:
317 bool Evaluate(double const* const* parameters,
318 double* residuals,
Austin Schuh3de38b02024-06-25 18:25:10 -0700319 double** jacobians) const override {
Austin Schuh70cc9552019-01-21 19:46:48 -0800320 for (int i = 0; i < kNumResiduals; ++i) {
321 residuals[i] = kNumResiduals * kNumResiduals + i;
322 }
323
324 return true;
325 }
326};
327
328TEST(Solver, FixedCostForConstantProblem) {
329 double x = 1.0;
330 Problem problem;
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800331 problem.AddResidualBlock(new DummyCostFunction<2, 1>(), nullptr, &x);
Austin Schuh70cc9552019-01-21 19:46:48 -0800332 problem.SetParameterBlockConstant(&x);
333 const double expected_cost = 41.0 / 2.0; // 1/2 * ((4 + 0)^2 + (4 + 1)^2)
334 Solver::Options options;
335 Solver::Summary summary;
336 Solve(options, &problem, &summary);
337 EXPECT_TRUE(summary.IsSolutionUsable());
338 EXPECT_EQ(summary.fixed_cost, expected_cost);
339 EXPECT_EQ(summary.initial_cost, expected_cost);
340 EXPECT_EQ(summary.final_cost, expected_cost);
341 EXPECT_EQ(summary.iterations.size(), 0);
342}
343
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800344struct LinearCostFunction {
345 template <typename T>
346 bool operator()(const T* x, const T* y, T* residual) const {
347 residual[0] = T(10.0) - *x;
348 residual[1] = T(5.0) - *y;
349 return true;
350 }
351 static CostFunction* Create() {
352 return new AutoDiffCostFunction<LinearCostFunction, 2, 1, 1>(
353 new LinearCostFunction);
354 }
355};
356
Austin Schuh3de38b02024-06-25 18:25:10 -0700357TEST(Solver, ZeroSizedManifoldHoldsParameterBlockConstant) {
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800358 double x = 0.0;
359 double y = 1.0;
360 Problem problem;
361 problem.AddResidualBlock(LinearCostFunction::Create(), nullptr, &x, &y);
Austin Schuh3de38b02024-06-25 18:25:10 -0700362 problem.SetManifold(&y, new SubsetManifold(1, {0}));
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800363 EXPECT_TRUE(problem.IsParameterBlockConstant(&y));
364
365 Solver::Options options;
366 options.function_tolerance = 0.0;
367 options.gradient_tolerance = 0.0;
368 options.parameter_tolerance = 0.0;
369 Solver::Summary summary;
370 Solve(options, &problem, &summary);
371
372 EXPECT_EQ(summary.termination_type, CONVERGENCE);
373 EXPECT_NEAR(x, 10.0, 1e-7);
374 EXPECT_EQ(y, 1.0);
375}
376
Austin Schuh3de38b02024-06-25 18:25:10 -0700377TEST(Solver, DenseNormalCholeskyOptions) {
378 std::string message;
379 Solver::Options options;
380 options.linear_solver_type = DENSE_NORMAL_CHOLESKY;
381 EXPECT_TRUE(options.IsValid(&message));
382
383 options.dense_linear_algebra_library_type = EIGEN;
384 options.use_mixed_precision_solves = false;
385 EXPECT_TRUE(options.IsValid(&message));
386
387 options.use_mixed_precision_solves = true;
388 EXPECT_TRUE(options.IsValid(&message));
389
390 if (IsDenseLinearAlgebraLibraryTypeAvailable(LAPACK)) {
391 options.use_mixed_precision_solves = false;
392 options.dense_linear_algebra_library_type = LAPACK;
393
394 EXPECT_TRUE(options.IsValid(&message));
395 options.use_mixed_precision_solves = true;
396 EXPECT_TRUE(options.IsValid(&message));
397 } else {
398 options.use_mixed_precision_solves = false;
399 options.dense_linear_algebra_library_type = LAPACK;
400 EXPECT_FALSE(options.IsValid(&message));
401 }
402}
403
404TEST(Solver, DenseQrOptions) {
405 std::string message;
406 Solver::Options options;
407 options.linear_solver_type = DENSE_QR;
408
409 options.use_mixed_precision_solves = false;
410 options.dense_linear_algebra_library_type = EIGEN;
411 EXPECT_TRUE(options.IsValid(&message));
412
413 options.use_mixed_precision_solves = true;
414 EXPECT_FALSE(options.IsValid(&message));
415
416 if (IsDenseLinearAlgebraLibraryTypeAvailable(LAPACK)) {
417 options.use_mixed_precision_solves = false;
418 options.dense_linear_algebra_library_type = LAPACK;
419 EXPECT_TRUE(options.IsValid(&message));
420 options.use_mixed_precision_solves = true;
421 EXPECT_FALSE(options.IsValid(&message));
422 } else {
423 options.use_mixed_precision_solves = false;
424 options.dense_linear_algebra_library_type = LAPACK;
425 EXPECT_FALSE(options.IsValid(&message));
426 }
427}
428
429TEST(Solver, SparseNormalCholeskyOptionsNoSparse) {
430 std::string message;
431 Solver::Options options;
432 options.linear_solver_type = SPARSE_NORMAL_CHOLESKY;
433 options.sparse_linear_algebra_library_type = NO_SPARSE;
434 EXPECT_FALSE(options.IsValid(&message));
435}
436
437TEST(Solver, SparseNormalCholeskyOptionsEigenSparse) {
438 std::string message;
439 Solver::Options options;
440 options.linear_solver_type = SPARSE_NORMAL_CHOLESKY;
441 options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
442 options.linear_solver_ordering_type = AMD;
443
444 options.use_mixed_precision_solves = false;
445 options.dynamic_sparsity = false;
446 if (IsSparseLinearAlgebraLibraryTypeAvailable(EIGEN_SPARSE)) {
447 EXPECT_TRUE(options.IsValid(&message));
448 } else {
449 EXPECT_FALSE(options.IsValid(&message));
450 }
451
452 if (IsSparseLinearAlgebraLibraryTypeAvailable(EIGEN_SPARSE)) {
453 options.use_mixed_precision_solves = true;
454 options.dynamic_sparsity = false;
455 EXPECT_TRUE(options.IsValid(&message));
456
457 options.use_mixed_precision_solves = false;
458 options.dynamic_sparsity = true;
459 EXPECT_TRUE(options.IsValid(&message));
460
461 options.use_mixed_precision_solves = true;
462 options.dynamic_sparsity = true;
463 EXPECT_TRUE(options.IsValid(&message));
464 }
465
466#ifndef CERES_NO_EIGEN_METIS
467 options.linear_solver_ordering_type = NESDIS;
468 if (IsSparseLinearAlgebraLibraryTypeAvailable(EIGEN_SPARSE)) {
469 options.use_mixed_precision_solves = false;
470 options.dynamic_sparsity = false;
471 EXPECT_TRUE(options.IsValid(&message));
472
473 options.use_mixed_precision_solves = true;
474 options.dynamic_sparsity = false;
475 EXPECT_TRUE(options.IsValid(&message));
476
477 options.use_mixed_precision_solves = false;
478 options.dynamic_sparsity = true;
479 EXPECT_TRUE(options.IsValid(&message));
480
481 options.use_mixed_precision_solves = true;
482 options.dynamic_sparsity = true;
483 EXPECT_TRUE(options.IsValid(&message));
484 }
485#else
486 options.linear_solver_ordering_type = NESDIS;
487 options.use_mixed_precision_solves = false;
488 options.dynamic_sparsity = false;
489 EXPECT_FALSE(options.IsValid(&message));
490#endif
491}
492
493TEST(Solver, SparseNormalCholeskyOptionsSuiteSparse) {
494 std::string message;
495 Solver::Options options;
496 options.linear_solver_type = SPARSE_NORMAL_CHOLESKY;
497 options.sparse_linear_algebra_library_type = SUITE_SPARSE;
498 options.linear_solver_ordering_type = AMD;
499
500 options.use_mixed_precision_solves = false;
501 options.dynamic_sparsity = false;
502 if (IsSparseLinearAlgebraLibraryTypeAvailable(
503 options.sparse_linear_algebra_library_type)) {
504 EXPECT_TRUE(options.IsValid(&message));
505 } else {
506 EXPECT_FALSE(options.IsValid(&message));
507 }
508
509 if (IsSparseLinearAlgebraLibraryTypeAvailable(
510 options.sparse_linear_algebra_library_type)) {
511 options.use_mixed_precision_solves = true;
512 options.dynamic_sparsity = false;
513 EXPECT_FALSE(options.IsValid(&message));
514
515 options.use_mixed_precision_solves = false;
516 options.dynamic_sparsity = true;
517 EXPECT_TRUE(options.IsValid(&message));
518
519 options.use_mixed_precision_solves = true;
520 options.dynamic_sparsity = true;
521 EXPECT_FALSE(options.IsValid(&message));
522 }
523
524#ifndef CERES_NO_CHOLMOD_PARTITION
525 options.linear_solver_ordering_type = NESDIS;
526 if (IsSparseLinearAlgebraLibraryTypeAvailable(
527 options.sparse_linear_algebra_library_type)) {
528 options.use_mixed_precision_solves = false;
529 options.dynamic_sparsity = false;
530 EXPECT_TRUE(options.IsValid(&message));
531
532 options.use_mixed_precision_solves = true;
533 options.dynamic_sparsity = false;
534 EXPECT_FALSE(options.IsValid(&message));
535
536 options.use_mixed_precision_solves = false;
537 options.dynamic_sparsity = true;
538 EXPECT_TRUE(options.IsValid(&message));
539
540 options.use_mixed_precision_solves = true;
541 options.dynamic_sparsity = true;
542 EXPECT_FALSE(options.IsValid(&message));
543 }
544#else
545 options.linear_solver_ordering_type = NESDIS;
546 options.use_mixed_precision_solves = false;
547 options.dynamic_sparsity = false;
548 EXPECT_FALSE(options.IsValid(&message));
549#endif
550}
551
552TEST(Solver, SparseNormalCholeskyOptionsAccelerateSparse) {
553 std::string message;
554 Solver::Options options;
555 options.linear_solver_type = SPARSE_NORMAL_CHOLESKY;
556 options.sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
557 options.linear_solver_ordering_type = AMD;
558
559 options.use_mixed_precision_solves = false;
560 options.dynamic_sparsity = false;
561 if (IsSparseLinearAlgebraLibraryTypeAvailable(
562 options.sparse_linear_algebra_library_type)) {
563 EXPECT_TRUE(options.IsValid(&message));
564 } else {
565 EXPECT_FALSE(options.IsValid(&message));
566 }
567
568 if (IsSparseLinearAlgebraLibraryTypeAvailable(
569 options.sparse_linear_algebra_library_type)) {
570 options.use_mixed_precision_solves = true;
571 options.dynamic_sparsity = false;
572 EXPECT_TRUE(options.IsValid(&message));
573
574 options.use_mixed_precision_solves = false;
575 options.dynamic_sparsity = true;
576 EXPECT_FALSE(options.IsValid(&message));
577
578 options.use_mixed_precision_solves = true;
579 options.dynamic_sparsity = true;
580 EXPECT_FALSE(options.IsValid(&message));
581 }
582
583 options.linear_solver_ordering_type = NESDIS;
584 if (IsSparseLinearAlgebraLibraryTypeAvailable(
585 options.sparse_linear_algebra_library_type)) {
586 options.use_mixed_precision_solves = false;
587 options.dynamic_sparsity = false;
588 EXPECT_TRUE(options.IsValid(&message));
589
590 options.use_mixed_precision_solves = true;
591 options.dynamic_sparsity = false;
592 EXPECT_TRUE(options.IsValid(&message));
593
594 options.use_mixed_precision_solves = false;
595 options.dynamic_sparsity = true;
596 EXPECT_FALSE(options.IsValid(&message));
597
598 options.use_mixed_precision_solves = true;
599 options.dynamic_sparsity = true;
600 EXPECT_FALSE(options.IsValid(&message));
601 }
602}
603
604TEST(Solver, DenseSchurOptions) {
605 std::string message;
606 Solver::Options options;
607 options.linear_solver_type = DENSE_SCHUR;
608 options.dense_linear_algebra_library_type = EIGEN;
609
610 options.use_mixed_precision_solves = false;
611 options.dynamic_sparsity = false;
612 EXPECT_TRUE(options.IsValid(&message));
613
614 options.use_mixed_precision_solves = true;
615 options.dynamic_sparsity = false;
616 EXPECT_TRUE(options.IsValid(&message));
617
618 options.use_mixed_precision_solves = true;
619 options.dynamic_sparsity = true;
620 EXPECT_FALSE(options.IsValid(&message));
621
622 options.use_mixed_precision_solves = false;
623 options.dynamic_sparsity = true;
624 EXPECT_FALSE(options.IsValid(&message));
625
626 options.dense_linear_algebra_library_type = LAPACK;
627 if (IsDenseLinearAlgebraLibraryTypeAvailable(
628 options.dense_linear_algebra_library_type)) {
629 options.use_mixed_precision_solves = false;
630 options.dynamic_sparsity = false;
631 EXPECT_TRUE(options.IsValid(&message));
632
633 options.use_mixed_precision_solves = true;
634 options.dynamic_sparsity = false;
635 EXPECT_TRUE(options.IsValid(&message));
636
637 options.use_mixed_precision_solves = true;
638 options.dynamic_sparsity = true;
639 EXPECT_FALSE(options.IsValid(&message));
640
641 options.use_mixed_precision_solves = false;
642 options.dynamic_sparsity = true;
643 EXPECT_FALSE(options.IsValid(&message));
644 }
645}
646
647TEST(Solver, SparseSchurOptionsNoSparse) {
648 std::string message;
649 Solver::Options options;
650 options.linear_solver_type = SPARSE_SCHUR;
651 options.sparse_linear_algebra_library_type = NO_SPARSE;
652 EXPECT_FALSE(options.IsValid(&message));
653}
654
655TEST(Solver, SparseSchurOptionsEigenSparse) {
656 std::string message;
657 Solver::Options options;
658 options.linear_solver_type = SPARSE_SCHUR;
659 options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
660 options.linear_solver_ordering_type = AMD;
661
662 options.use_mixed_precision_solves = false;
663 options.dynamic_sparsity = false;
664 if (IsSparseLinearAlgebraLibraryTypeAvailable(EIGEN_SPARSE)) {
665 EXPECT_TRUE(options.IsValid(&message));
666 } else {
667 EXPECT_FALSE(options.IsValid(&message));
668 }
669
670 if (IsSparseLinearAlgebraLibraryTypeAvailable(EIGEN_SPARSE)) {
671 options.use_mixed_precision_solves = true;
672 options.dynamic_sparsity = false;
673 EXPECT_TRUE(options.IsValid(&message));
674
675 options.use_mixed_precision_solves = false;
676 options.dynamic_sparsity = true;
677 EXPECT_FALSE(options.IsValid(&message));
678
679 options.use_mixed_precision_solves = true;
680 options.dynamic_sparsity = true;
681 EXPECT_FALSE(options.IsValid(&message));
682 }
683
684#ifndef CERES_NO_EIGEN_METIS
685 options.linear_solver_ordering_type = NESDIS;
686 if (IsSparseLinearAlgebraLibraryTypeAvailable(EIGEN_SPARSE)) {
687 options.use_mixed_precision_solves = false;
688 options.dynamic_sparsity = false;
689 EXPECT_TRUE(options.IsValid(&message));
690
691 options.use_mixed_precision_solves = true;
692 options.dynamic_sparsity = false;
693 EXPECT_TRUE(options.IsValid(&message));
694
695 options.use_mixed_precision_solves = false;
696 options.dynamic_sparsity = true;
697 EXPECT_FALSE(options.IsValid(&message));
698
699 options.use_mixed_precision_solves = true;
700 options.dynamic_sparsity = true;
701 EXPECT_FALSE(options.IsValid(&message));
702 }
703#else
704 options.linear_solver_ordering_type = NESDIS;
705 options.use_mixed_precision_solves = false;
706 options.dynamic_sparsity = false;
707 EXPECT_FALSE(options.IsValid(&message));
708#endif
709}
710
711TEST(Solver, SparseSchurOptionsSuiteSparse) {
712 std::string message;
713 Solver::Options options;
714 options.linear_solver_type = SPARSE_SCHUR;
715 options.sparse_linear_algebra_library_type = SUITE_SPARSE;
716 options.linear_solver_ordering_type = AMD;
717
718 options.use_mixed_precision_solves = false;
719 options.dynamic_sparsity = false;
720 if (IsSparseLinearAlgebraLibraryTypeAvailable(
721 options.sparse_linear_algebra_library_type)) {
722 EXPECT_TRUE(options.IsValid(&message));
723 } else {
724 EXPECT_FALSE(options.IsValid(&message));
725 }
726
727 if (IsSparseLinearAlgebraLibraryTypeAvailable(
728 options.sparse_linear_algebra_library_type)) {
729 options.use_mixed_precision_solves = true;
730 options.dynamic_sparsity = false;
731 EXPECT_FALSE(options.IsValid(&message));
732
733 options.use_mixed_precision_solves = false;
734 options.dynamic_sparsity = true;
735 EXPECT_FALSE(options.IsValid(&message));
736
737 options.use_mixed_precision_solves = true;
738 options.dynamic_sparsity = true;
739 EXPECT_FALSE(options.IsValid(&message));
740 }
741
742#ifndef CERES_NO_CHOLMOD_PARTITION
743 options.linear_solver_ordering_type = NESDIS;
744 if (IsSparseLinearAlgebraLibraryTypeAvailable(
745 options.sparse_linear_algebra_library_type)) {
746 options.use_mixed_precision_solves = false;
747 options.dynamic_sparsity = false;
748 EXPECT_TRUE(options.IsValid(&message));
749
750 options.use_mixed_precision_solves = true;
751 options.dynamic_sparsity = false;
752 EXPECT_FALSE(options.IsValid(&message));
753
754 options.use_mixed_precision_solves = false;
755 options.dynamic_sparsity = true;
756 EXPECT_FALSE(options.IsValid(&message));
757
758 options.use_mixed_precision_solves = true;
759 options.dynamic_sparsity = true;
760 EXPECT_FALSE(options.IsValid(&message));
761 }
762#else
763 options.linear_solver_ordering_type = NESDIS;
764 options.use_mixed_precision_solves = false;
765 options.dynamic_sparsity = false;
766 EXPECT_FALSE(options.IsValid(&message));
767#endif
768}
769
770TEST(Solver, SparseSchurOptionsAccelerateSparse) {
771 std::string message;
772 Solver::Options options;
773 options.linear_solver_type = SPARSE_SCHUR;
774 options.sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
775 options.linear_solver_ordering_type = AMD;
776
777 options.use_mixed_precision_solves = false;
778 options.dynamic_sparsity = false;
779 if (IsSparseLinearAlgebraLibraryTypeAvailable(
780 options.sparse_linear_algebra_library_type)) {
781 EXPECT_TRUE(options.IsValid(&message));
782 } else {
783 EXPECT_FALSE(options.IsValid(&message));
784 }
785
786 if (IsSparseLinearAlgebraLibraryTypeAvailable(
787 options.sparse_linear_algebra_library_type)) {
788 options.use_mixed_precision_solves = true;
789 options.dynamic_sparsity = false;
790 EXPECT_TRUE(options.IsValid(&message));
791
792 options.use_mixed_precision_solves = false;
793 options.dynamic_sparsity = true;
794 EXPECT_FALSE(options.IsValid(&message));
795
796 options.use_mixed_precision_solves = true;
797 options.dynamic_sparsity = true;
798 EXPECT_FALSE(options.IsValid(&message));
799 }
800
801 options.linear_solver_ordering_type = NESDIS;
802 if (IsSparseLinearAlgebraLibraryTypeAvailable(
803 options.sparse_linear_algebra_library_type)) {
804 options.use_mixed_precision_solves = false;
805 options.dynamic_sparsity = false;
806 EXPECT_TRUE(options.IsValid(&message));
807
808 options.use_mixed_precision_solves = true;
809 options.dynamic_sparsity = false;
810 EXPECT_TRUE(options.IsValid(&message));
811
812 options.use_mixed_precision_solves = false;
813 options.dynamic_sparsity = true;
814 EXPECT_FALSE(options.IsValid(&message));
815
816 options.use_mixed_precision_solves = true;
817 options.dynamic_sparsity = true;
818 EXPECT_FALSE(options.IsValid(&message));
819 }
820}
821
822TEST(Solver, CgnrOptionsIdentityPreconditioner) {
823 std::string message;
824 Solver::Options options;
825 options.linear_solver_type = CGNR;
826 options.preconditioner_type = IDENTITY;
827 options.sparse_linear_algebra_library_type = NO_SPARSE;
828
829 options.dynamic_sparsity = false;
830 options.use_mixed_precision_solves = false;
831 EXPECT_TRUE(options.IsValid(&message));
832
833 options.dynamic_sparsity = true;
834 options.use_mixed_precision_solves = false;
835 EXPECT_FALSE(options.IsValid(&message));
836
837 options.dynamic_sparsity = false;
838 options.use_mixed_precision_solves = true;
839 EXPECT_FALSE(options.IsValid(&message));
840
841 options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
842 options.dynamic_sparsity = false;
843 options.use_mixed_precision_solves = false;
844 EXPECT_TRUE(options.IsValid(&message));
845
846 options.dynamic_sparsity = true;
847 options.use_mixed_precision_solves = false;
848 EXPECT_FALSE(options.IsValid(&message));
849
850 options.dynamic_sparsity = false;
851 options.use_mixed_precision_solves = true;
852 EXPECT_FALSE(options.IsValid(&message));
853
854 options.sparse_linear_algebra_library_type = SUITE_SPARSE;
855 options.dynamic_sparsity = false;
856 options.use_mixed_precision_solves = false;
857 EXPECT_TRUE(options.IsValid(&message));
858
859 options.dynamic_sparsity = true;
860 options.use_mixed_precision_solves = false;
861 EXPECT_FALSE(options.IsValid(&message));
862
863 options.dynamic_sparsity = false;
864 options.use_mixed_precision_solves = true;
865 EXPECT_FALSE(options.IsValid(&message));
866
867 options.sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
868 options.dynamic_sparsity = false;
869 options.use_mixed_precision_solves = false;
870 EXPECT_TRUE(options.IsValid(&message));
871
872 options.dynamic_sparsity = true;
873 options.use_mixed_precision_solves = false;
874 EXPECT_FALSE(options.IsValid(&message));
875
876 options.dynamic_sparsity = false;
877 options.use_mixed_precision_solves = true;
878 EXPECT_FALSE(options.IsValid(&message));
879
880 options.sparse_linear_algebra_library_type = CUDA_SPARSE;
881 options.dynamic_sparsity = false;
882 options.use_mixed_precision_solves = false;
883 EXPECT_EQ(options.IsValid(&message),
884 IsSparseLinearAlgebraLibraryTypeAvailable(CUDA_SPARSE));
885
886 options.dynamic_sparsity = true;
887 options.use_mixed_precision_solves = false;
888 EXPECT_FALSE(options.IsValid(&message));
889
890 options.dynamic_sparsity = false;
891 options.use_mixed_precision_solves = true;
892 EXPECT_FALSE(options.IsValid(&message));
893}
894
895TEST(Solver, CgnrOptionsJacobiPreconditioner) {
896 std::string message;
897 Solver::Options options;
898 options.linear_solver_type = CGNR;
899 options.preconditioner_type = JACOBI;
900 options.sparse_linear_algebra_library_type = NO_SPARSE;
901
902 options.dynamic_sparsity = false;
903 options.use_mixed_precision_solves = false;
904 EXPECT_TRUE(options.IsValid(&message));
905
906 options.dynamic_sparsity = true;
907 options.use_mixed_precision_solves = false;
908 EXPECT_FALSE(options.IsValid(&message));
909
910 options.dynamic_sparsity = false;
911 options.use_mixed_precision_solves = true;
912 EXPECT_FALSE(options.IsValid(&message));
913
914 options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
915
916 options.dynamic_sparsity = false;
917 options.use_mixed_precision_solves = false;
918 EXPECT_TRUE(options.IsValid(&message));
919
920 options.dynamic_sparsity = true;
921 options.use_mixed_precision_solves = false;
922 EXPECT_FALSE(options.IsValid(&message));
923
924 options.dynamic_sparsity = false;
925 options.use_mixed_precision_solves = true;
926 EXPECT_FALSE(options.IsValid(&message));
927
928 options.sparse_linear_algebra_library_type = SUITE_SPARSE;
929
930 options.dynamic_sparsity = false;
931 options.use_mixed_precision_solves = false;
932 EXPECT_TRUE(options.IsValid(&message));
933
934 options.dynamic_sparsity = true;
935 options.use_mixed_precision_solves = false;
936 EXPECT_FALSE(options.IsValid(&message));
937
938 options.dynamic_sparsity = false;
939 options.use_mixed_precision_solves = true;
940 EXPECT_FALSE(options.IsValid(&message));
941
942 options.sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
943
944 options.dynamic_sparsity = false;
945 options.use_mixed_precision_solves = false;
946 EXPECT_TRUE(options.IsValid(&message));
947
948 options.dynamic_sparsity = true;
949 options.use_mixed_precision_solves = false;
950 EXPECT_FALSE(options.IsValid(&message));
951
952 options.dynamic_sparsity = false;
953 options.use_mixed_precision_solves = true;
954 EXPECT_FALSE(options.IsValid(&message));
955
956 options.sparse_linear_algebra_library_type = CUDA_SPARSE;
957
958 options.dynamic_sparsity = false;
959 options.use_mixed_precision_solves = false;
960 EXPECT_EQ(options.IsValid(&message),
961 IsSparseLinearAlgebraLibraryTypeAvailable(CUDA_SPARSE));
962
963 options.dynamic_sparsity = true;
964 options.use_mixed_precision_solves = false;
965 EXPECT_FALSE(options.IsValid(&message));
966
967 options.dynamic_sparsity = false;
968 options.use_mixed_precision_solves = true;
969 EXPECT_FALSE(options.IsValid(&message));
970}
971
972TEST(Solver, CgnrOptionsSubsetPreconditioner) {
973 std::string message;
974 Solver::Options options;
975 options.linear_solver_type = CGNR;
976 options.preconditioner_type = SUBSET;
977
978 options.sparse_linear_algebra_library_type = NO_SPARSE;
979 EXPECT_FALSE(options.IsValid(&message));
980 options.residual_blocks_for_subset_preconditioner.insert(nullptr);
981 EXPECT_FALSE(options.IsValid(&message));
982
983 options.dynamic_sparsity = false;
984 options.use_mixed_precision_solves = false;
985 EXPECT_FALSE(options.IsValid(&message));
986
987 options.dynamic_sparsity = true;
988 options.use_mixed_precision_solves = false;
989 EXPECT_FALSE(options.IsValid(&message));
990
991 options.dynamic_sparsity = false;
992 options.use_mixed_precision_solves = true;
993 EXPECT_FALSE(options.IsValid(&message));
994
995 options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
996 if (IsSparseLinearAlgebraLibraryTypeAvailable(
997 options.sparse_linear_algebra_library_type)) {
998 options.dynamic_sparsity = false;
999 options.use_mixed_precision_solves = false;
1000 EXPECT_TRUE(options.IsValid(&message));
1001
1002 options.dynamic_sparsity = true;
1003 options.use_mixed_precision_solves = false;
1004 EXPECT_FALSE(options.IsValid(&message));
1005
1006 options.dynamic_sparsity = false;
1007 options.use_mixed_precision_solves = true;
1008 EXPECT_FALSE(options.IsValid(&message));
1009 }
1010
1011 options.sparse_linear_algebra_library_type = SUITE_SPARSE;
1012 if (IsSparseLinearAlgebraLibraryTypeAvailable(
1013 options.sparse_linear_algebra_library_type)) {
1014 options.dynamic_sparsity = false;
1015 options.use_mixed_precision_solves = false;
1016 EXPECT_TRUE(options.IsValid(&message));
1017
1018 options.dynamic_sparsity = true;
1019 options.use_mixed_precision_solves = false;
1020 EXPECT_FALSE(options.IsValid(&message));
1021
1022 options.dynamic_sparsity = false;
1023 options.use_mixed_precision_solves = true;
1024 EXPECT_FALSE(options.IsValid(&message));
1025 }
1026
1027 options.sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
1028 if (IsSparseLinearAlgebraLibraryTypeAvailable(
1029 options.sparse_linear_algebra_library_type)) {
1030 options.dynamic_sparsity = false;
1031 options.use_mixed_precision_solves = false;
1032 EXPECT_TRUE(options.IsValid(&message));
1033
1034 options.dynamic_sparsity = true;
1035 options.use_mixed_precision_solves = false;
1036 EXPECT_FALSE(options.IsValid(&message));
1037
1038 options.dynamic_sparsity = false;
1039 options.use_mixed_precision_solves = true;
1040 EXPECT_FALSE(options.IsValid(&message));
1041 }
1042
1043 options.sparse_linear_algebra_library_type = CUDA_SPARSE;
1044 options.dynamic_sparsity = false;
1045 options.use_mixed_precision_solves = false;
1046 EXPECT_FALSE(options.IsValid(&message));
1047
1048 options.dynamic_sparsity = true;
1049 options.use_mixed_precision_solves = false;
1050 EXPECT_FALSE(options.IsValid(&message));
1051
1052 options.dynamic_sparsity = false;
1053 options.use_mixed_precision_solves = true;
1054 EXPECT_FALSE(options.IsValid(&message));
1055}
1056
1057TEST(Solver, CgnrOptionsSchurPreconditioners) {
1058 std::string message;
1059 Solver::Options options;
1060 options.linear_solver_type = CGNR;
1061 options.preconditioner_type = SCHUR_JACOBI;
1062 EXPECT_FALSE(options.IsValid(&message));
1063 options.preconditioner_type = CLUSTER_JACOBI;
1064 EXPECT_FALSE(options.IsValid(&message));
1065 options.preconditioner_type = CLUSTER_TRIDIAGONAL;
1066 EXPECT_FALSE(options.IsValid(&message));
1067}
1068
1069TEST(Solver, IterativeSchurOptionsNoSparse) {
1070 std::string message;
1071 Solver::Options options;
1072 options.linear_solver_type = ITERATIVE_SCHUR;
1073 options.sparse_linear_algebra_library_type = NO_SPARSE;
1074 options.preconditioner_type = IDENTITY;
1075 EXPECT_TRUE(options.IsValid(&message));
1076 options.preconditioner_type = JACOBI;
1077 EXPECT_TRUE(options.IsValid(&message));
1078 options.preconditioner_type = SCHUR_JACOBI;
1079 EXPECT_TRUE(options.IsValid(&message));
1080 options.preconditioner_type = CLUSTER_JACOBI;
1081 EXPECT_FALSE(options.IsValid(&message));
1082 options.preconditioner_type = CLUSTER_TRIDIAGONAL;
1083 EXPECT_FALSE(options.IsValid(&message));
1084 options.preconditioner_type = SUBSET;
1085 EXPECT_FALSE(options.IsValid(&message));
1086
1087 options.use_explicit_schur_complement = true;
1088 options.preconditioner_type = IDENTITY;
1089 EXPECT_FALSE(options.IsValid(&message));
1090 options.preconditioner_type = JACOBI;
1091 EXPECT_FALSE(options.IsValid(&message));
1092 options.preconditioner_type = SCHUR_JACOBI;
1093 EXPECT_TRUE(options.IsValid(&message));
1094 options.preconditioner_type = CLUSTER_JACOBI;
1095 EXPECT_FALSE(options.IsValid(&message));
1096 options.preconditioner_type = CLUSTER_TRIDIAGONAL;
1097 EXPECT_FALSE(options.IsValid(&message));
1098}
1099
1100TEST(Solver, IterativeSchurOptionsEigenSparse) {
1101 std::string message;
1102 Solver::Options options;
1103 options.linear_solver_type = ITERATIVE_SCHUR;
1104 options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
1105 options.preconditioner_type = IDENTITY;
1106 EXPECT_TRUE(options.IsValid(&message));
1107 options.preconditioner_type = JACOBI;
1108 EXPECT_TRUE(options.IsValid(&message));
1109 options.preconditioner_type = SCHUR_JACOBI;
1110 EXPECT_TRUE(options.IsValid(&message));
1111 options.preconditioner_type = CLUSTER_JACOBI;
1112 EXPECT_EQ(options.IsValid(&message),
1113 IsSparseLinearAlgebraLibraryTypeAvailable(
1114 options.sparse_linear_algebra_library_type));
1115 options.preconditioner_type = CLUSTER_TRIDIAGONAL;
1116 EXPECT_EQ(options.IsValid(&message),
1117 IsSparseLinearAlgebraLibraryTypeAvailable(
1118 options.sparse_linear_algebra_library_type));
1119 options.preconditioner_type = SUBSET;
1120 EXPECT_FALSE(options.IsValid(&message));
1121
1122 options.use_explicit_schur_complement = true;
1123 options.preconditioner_type = IDENTITY;
1124 EXPECT_FALSE(options.IsValid(&message));
1125 options.preconditioner_type = JACOBI;
1126 EXPECT_FALSE(options.IsValid(&message));
1127 options.preconditioner_type = SCHUR_JACOBI;
1128 EXPECT_TRUE(options.IsValid(&message));
1129 options.preconditioner_type = CLUSTER_JACOBI;
1130 EXPECT_FALSE(options.IsValid(&message));
1131 options.preconditioner_type = CLUSTER_TRIDIAGONAL;
1132 EXPECT_FALSE(options.IsValid(&message));
1133}
1134
1135TEST(Solver, IterativeSchurOptionsSuiteSparse) {
1136 std::string message;
1137 Solver::Options options;
1138 options.linear_solver_type = ITERATIVE_SCHUR;
1139 options.sparse_linear_algebra_library_type = SUITE_SPARSE;
1140 options.preconditioner_type = IDENTITY;
1141 EXPECT_TRUE(options.IsValid(&message));
1142 options.preconditioner_type = JACOBI;
1143 EXPECT_TRUE(options.IsValid(&message));
1144 options.preconditioner_type = SCHUR_JACOBI;
1145 EXPECT_TRUE(options.IsValid(&message));
1146 options.preconditioner_type = CLUSTER_JACOBI;
1147 EXPECT_EQ(options.IsValid(&message),
1148 IsSparseLinearAlgebraLibraryTypeAvailable(
1149 options.sparse_linear_algebra_library_type));
1150 options.preconditioner_type = CLUSTER_TRIDIAGONAL;
1151 EXPECT_EQ(options.IsValid(&message),
1152 IsSparseLinearAlgebraLibraryTypeAvailable(
1153 options.sparse_linear_algebra_library_type));
1154 options.preconditioner_type = SUBSET;
1155 EXPECT_FALSE(options.IsValid(&message));
1156
1157 options.use_explicit_schur_complement = true;
1158 options.preconditioner_type = IDENTITY;
1159 EXPECT_FALSE(options.IsValid(&message));
1160 options.preconditioner_type = JACOBI;
1161 EXPECT_FALSE(options.IsValid(&message));
1162 options.preconditioner_type = SCHUR_JACOBI;
1163 EXPECT_TRUE(options.IsValid(&message));
1164 options.preconditioner_type = CLUSTER_JACOBI;
1165 EXPECT_FALSE(options.IsValid(&message));
1166 options.preconditioner_type = CLUSTER_TRIDIAGONAL;
1167 EXPECT_FALSE(options.IsValid(&message));
1168}
1169
1170TEST(Solver, IterativeSchurOptionsAccelerateSparse) {
1171 std::string message;
1172 Solver::Options options;
1173 options.linear_solver_type = ITERATIVE_SCHUR;
1174 options.sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
1175 options.preconditioner_type = IDENTITY;
1176 EXPECT_TRUE(options.IsValid(&message));
1177 options.preconditioner_type = JACOBI;
1178 EXPECT_TRUE(options.IsValid(&message));
1179 options.preconditioner_type = SCHUR_JACOBI;
1180 EXPECT_TRUE(options.IsValid(&message));
1181 options.preconditioner_type = CLUSTER_JACOBI;
1182 EXPECT_EQ(options.IsValid(&message),
1183 IsSparseLinearAlgebraLibraryTypeAvailable(
1184 options.sparse_linear_algebra_library_type));
1185 options.preconditioner_type = CLUSTER_TRIDIAGONAL;
1186 EXPECT_EQ(options.IsValid(&message),
1187 IsSparseLinearAlgebraLibraryTypeAvailable(
1188 options.sparse_linear_algebra_library_type));
1189 options.preconditioner_type = SUBSET;
1190 EXPECT_FALSE(options.IsValid(&message));
1191
1192 options.use_explicit_schur_complement = true;
1193 options.preconditioner_type = IDENTITY;
1194 EXPECT_FALSE(options.IsValid(&message));
1195 options.preconditioner_type = JACOBI;
1196 EXPECT_FALSE(options.IsValid(&message));
1197 options.preconditioner_type = SCHUR_JACOBI;
1198 EXPECT_TRUE(options.IsValid(&message));
1199 options.preconditioner_type = CLUSTER_JACOBI;
1200 EXPECT_FALSE(options.IsValid(&message));
1201 options.preconditioner_type = CLUSTER_TRIDIAGONAL;
1202 EXPECT_FALSE(options.IsValid(&message));
1203}
1204
1205class LargeCostCostFunction : public SizedCostFunction<1, 1> {
1206 public:
1207 bool Evaluate(double const* const* parameters,
1208 double* residuals,
1209 double** jacobians) const override {
1210 residuals[0] = 1e300;
1211 if (jacobians && jacobians[0]) {
1212 jacobians[0][0] = 1.0;
1213 }
1214 return true;
1215 }
1216};
1217
1218TEST(Solver, LargeCostProblem) {
1219 double x = 1;
1220 Problem problem;
1221 problem.AddResidualBlock(new LargeCostCostFunction, nullptr, &x);
1222 Solver::Options options;
1223 Solver::Summary summary;
1224 Solve(options, &problem, &summary);
1225 LOG(INFO) << summary.FullReport();
1226 EXPECT_EQ(summary.termination_type, FAILURE);
1227}
1228
1229} // namespace ceres::internal