solver_test.cc 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205
  1. // Ceres Solver - A fast non-linear least squares minimizer
  2. // Copyright 2022 Google Inc. All rights reserved.
  3. // 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. #include "ceres/solver.h"
  31. #include <cmath>
  32. #include <limits>
  33. #include <memory>
  34. #include <string>
  35. #include <vector>
  36. #include "ceres/autodiff_cost_function.h"
  37. #include "ceres/evaluation_callback.h"
  38. #include "ceres/manifold.h"
  39. #include "ceres/problem.h"
  40. #include "ceres/problem_impl.h"
  41. #include "ceres/sized_cost_function.h"
  42. #include "gtest/gtest.h"
  43. namespace ceres::internal {
  44. TEST(SolverOptions, DefaultTrustRegionOptionsAreValid) {
  45. Solver::Options options;
  46. options.minimizer_type = TRUST_REGION;
  47. std::string error;
  48. EXPECT_TRUE(options.IsValid(&error)) << error;
  49. }
  50. TEST(SolverOptions, DefaultLineSearchOptionsAreValid) {
  51. Solver::Options options;
  52. options.minimizer_type = LINE_SEARCH;
  53. std::string error;
  54. EXPECT_TRUE(options.IsValid(&error)) << error;
  55. }
  56. struct QuadraticCostFunctor {
  57. template <typename T>
  58. bool operator()(const T* const x, T* residual) const {
  59. residual[0] = T(5.0) - *x;
  60. return true;
  61. }
  62. static CostFunction* Create() {
  63. return new AutoDiffCostFunction<QuadraticCostFunctor, 1, 1>(
  64. new QuadraticCostFunctor);
  65. }
  66. };
  67. struct RememberingCallback : public IterationCallback {
  68. explicit RememberingCallback(double* x) : calls(0), x(x) {}
  69. CallbackReturnType operator()(const IterationSummary& summary) final {
  70. x_values.push_back(*x);
  71. return SOLVER_CONTINUE;
  72. }
  73. int calls;
  74. double* x;
  75. std::vector<double> x_values;
  76. };
  77. struct NoOpEvaluationCallback : EvaluationCallback {
  78. void PrepareForEvaluation(bool evaluate_jacobians,
  79. bool new_evaluation_point) final {
  80. (void)evaluate_jacobians;
  81. (void)new_evaluation_point;
  82. }
  83. };
  84. TEST(Solver, UpdateStateEveryIterationOptionNoEvaluationCallback) {
  85. double x = 50.0;
  86. const double original_x = x;
  87. Problem::Options problem_options;
  88. Problem problem(problem_options);
  89. problem.AddResidualBlock(QuadraticCostFunctor::Create(), nullptr, &x);
  90. Solver::Options options;
  91. options.linear_solver_type = DENSE_QR;
  92. RememberingCallback callback(&x);
  93. options.callbacks.push_back(&callback);
  94. Solver::Summary summary;
  95. int num_iterations;
  96. // First: update_state_every_iteration=false, evaluation_callback=nullptr.
  97. Solve(options, &problem, &summary);
  98. num_iterations =
  99. summary.num_successful_steps + summary.num_unsuccessful_steps;
  100. EXPECT_GT(num_iterations, 1);
  101. for (double value : callback.x_values) {
  102. EXPECT_EQ(50.0, value);
  103. }
  104. // Second: update_state_every_iteration=true, evaluation_callback=nullptr.
  105. x = 50.0;
  106. options.update_state_every_iteration = true;
  107. callback.x_values.clear();
  108. Solve(options, &problem, &summary);
  109. num_iterations =
  110. summary.num_successful_steps + summary.num_unsuccessful_steps;
  111. EXPECT_GT(num_iterations, 1);
  112. EXPECT_EQ(original_x, callback.x_values[0]);
  113. EXPECT_NE(original_x, callback.x_values[1]);
  114. }
  115. TEST(Solver, UpdateStateEveryIterationOptionWithEvaluationCallback) {
  116. double x = 50.0;
  117. const double original_x = x;
  118. Problem::Options problem_options;
  119. NoOpEvaluationCallback evaluation_callback;
  120. problem_options.evaluation_callback = &evaluation_callback;
  121. Problem problem(problem_options);
  122. problem.AddResidualBlock(QuadraticCostFunctor::Create(), nullptr, &x);
  123. Solver::Options options;
  124. options.linear_solver_type = DENSE_QR;
  125. RememberingCallback callback(&x);
  126. options.callbacks.push_back(&callback);
  127. Solver::Summary summary;
  128. int num_iterations;
  129. // First: update_state_every_iteration=true, evaluation_callback=!nullptr.
  130. x = 50.0;
  131. options.update_state_every_iteration = true;
  132. callback.x_values.clear();
  133. Solve(options, &problem, &summary);
  134. num_iterations =
  135. summary.num_successful_steps + summary.num_unsuccessful_steps;
  136. EXPECT_GT(num_iterations, 1);
  137. EXPECT_EQ(original_x, callback.x_values[0]);
  138. EXPECT_NE(original_x, callback.x_values[1]);
  139. // Second: update_state_every_iteration=false, evaluation_callback=!nullptr.
  140. x = 50.0;
  141. options.update_state_every_iteration = false;
  142. callback.x_values.clear();
  143. Solve(options, &problem, &summary);
  144. num_iterations =
  145. summary.num_successful_steps + summary.num_unsuccessful_steps;
  146. EXPECT_GT(num_iterations, 1);
  147. EXPECT_EQ(original_x, callback.x_values[0]);
  148. EXPECT_NE(original_x, callback.x_values[1]);
  149. }
  150. TEST(Solver, CantMixEvaluationCallbackWithInnerIterations) {
  151. double x = 50.0;
  152. double y = 60.0;
  153. Problem::Options problem_options;
  154. NoOpEvaluationCallback evaluation_callback;
  155. problem_options.evaluation_callback = &evaluation_callback;
  156. Problem problem(problem_options);
  157. problem.AddResidualBlock(QuadraticCostFunctor::Create(), nullptr, &x);
  158. problem.AddResidualBlock(QuadraticCostFunctor::Create(), nullptr, &y);
  159. Solver::Options options;
  160. options.use_inner_iterations = true;
  161. Solver::Summary summary;
  162. Solve(options, &problem, &summary);
  163. EXPECT_EQ(summary.termination_type, FAILURE);
  164. options.use_inner_iterations = false;
  165. Solve(options, &problem, &summary);
  166. EXPECT_EQ(summary.termination_type, CONVERGENCE);
  167. }
  168. // The parameters must be in separate blocks so that they can be individually
  169. // set constant or not.
  170. struct Quadratic4DCostFunction {
  171. template <typename T>
  172. bool operator()(const T* const x,
  173. const T* const y,
  174. const T* const z,
  175. const T* const w,
  176. T* residual) const {
  177. // A 4-dimension axis-aligned quadratic.
  178. residual[0] = T(10.0) - *x + T(20.0) - *y + T(30.0) - *z + T(40.0) - *w;
  179. return true;
  180. }
  181. static CostFunction* Create() {
  182. return new AutoDiffCostFunction<Quadratic4DCostFunction, 1, 1, 1, 1, 1>(
  183. new Quadratic4DCostFunction);
  184. }
  185. };
  186. // A cost function that simply returns its argument.
  187. class UnaryIdentityCostFunction : public SizedCostFunction<1, 1> {
  188. public:
  189. bool Evaluate(double const* const* parameters,
  190. double* residuals,
  191. double** jacobians) const final {
  192. residuals[0] = parameters[0][0];
  193. if (jacobians != nullptr && jacobians[0] != nullptr) {
  194. jacobians[0][0] = 1.0;
  195. }
  196. return true;
  197. }
  198. };
  199. TEST(Solver, TrustRegionProblemHasNoParameterBlocks) {
  200. Problem problem;
  201. Solver::Options options;
  202. options.minimizer_type = TRUST_REGION;
  203. Solver::Summary summary;
  204. Solve(options, &problem, &summary);
  205. EXPECT_EQ(summary.termination_type, CONVERGENCE);
  206. EXPECT_EQ(summary.message,
  207. "Function tolerance reached. "
  208. "No non-constant parameter blocks found.");
  209. }
  210. TEST(Solver, LineSearchProblemHasNoParameterBlocks) {
  211. Problem problem;
  212. Solver::Options options;
  213. options.minimizer_type = LINE_SEARCH;
  214. Solver::Summary summary;
  215. Solve(options, &problem, &summary);
  216. EXPECT_EQ(summary.termination_type, CONVERGENCE);
  217. EXPECT_EQ(summary.message,
  218. "Function tolerance reached. "
  219. "No non-constant parameter blocks found.");
  220. }
  221. TEST(Solver, TrustRegionProblemHasZeroResiduals) {
  222. Problem problem;
  223. double x = 1;
  224. problem.AddParameterBlock(&x, 1);
  225. Solver::Options options;
  226. options.minimizer_type = TRUST_REGION;
  227. Solver::Summary summary;
  228. Solve(options, &problem, &summary);
  229. EXPECT_EQ(summary.termination_type, CONVERGENCE);
  230. EXPECT_EQ(summary.message,
  231. "Function tolerance reached. "
  232. "No non-constant parameter blocks found.");
  233. }
  234. TEST(Solver, LineSearchProblemHasZeroResiduals) {
  235. Problem problem;
  236. double x = 1;
  237. problem.AddParameterBlock(&x, 1);
  238. Solver::Options options;
  239. options.minimizer_type = LINE_SEARCH;
  240. Solver::Summary summary;
  241. Solve(options, &problem, &summary);
  242. EXPECT_EQ(summary.termination_type, CONVERGENCE);
  243. EXPECT_EQ(summary.message,
  244. "Function tolerance reached. "
  245. "No non-constant parameter blocks found.");
  246. }
  247. TEST(Solver, TrustRegionProblemIsConstant) {
  248. Problem problem;
  249. double x = 1;
  250. problem.AddResidualBlock(new UnaryIdentityCostFunction, nullptr, &x);
  251. problem.SetParameterBlockConstant(&x);
  252. Solver::Options options;
  253. options.minimizer_type = TRUST_REGION;
  254. Solver::Summary summary;
  255. Solve(options, &problem, &summary);
  256. EXPECT_EQ(summary.termination_type, CONVERGENCE);
  257. EXPECT_EQ(summary.initial_cost, 1.0 / 2.0);
  258. EXPECT_EQ(summary.final_cost, 1.0 / 2.0);
  259. }
  260. TEST(Solver, LineSearchProblemIsConstant) {
  261. Problem problem;
  262. double x = 1;
  263. problem.AddResidualBlock(new UnaryIdentityCostFunction, nullptr, &x);
  264. problem.SetParameterBlockConstant(&x);
  265. Solver::Options options;
  266. options.minimizer_type = LINE_SEARCH;
  267. Solver::Summary summary;
  268. Solve(options, &problem, &summary);
  269. EXPECT_EQ(summary.termination_type, CONVERGENCE);
  270. EXPECT_EQ(summary.initial_cost, 1.0 / 2.0);
  271. EXPECT_EQ(summary.final_cost, 1.0 / 2.0);
  272. }
  273. template <int kNumResiduals, int... Ns>
  274. class DummyCostFunction : public SizedCostFunction<kNumResiduals, Ns...> {
  275. public:
  276. bool Evaluate(double const* const* parameters,
  277. double* residuals,
  278. double** jacobians) const override {
  279. for (int i = 0; i < kNumResiduals; ++i) {
  280. residuals[i] = kNumResiduals * kNumResiduals + i;
  281. }
  282. return true;
  283. }
  284. };
  285. TEST(Solver, FixedCostForConstantProblem) {
  286. double x = 1.0;
  287. Problem problem;
  288. problem.AddResidualBlock(new DummyCostFunction<2, 1>(), nullptr, &x);
  289. problem.SetParameterBlockConstant(&x);
  290. const double expected_cost = 41.0 / 2.0; // 1/2 * ((4 + 0)^2 + (4 + 1)^2)
  291. Solver::Options options;
  292. Solver::Summary summary;
  293. Solve(options, &problem, &summary);
  294. EXPECT_TRUE(summary.IsSolutionUsable());
  295. EXPECT_EQ(summary.fixed_cost, expected_cost);
  296. EXPECT_EQ(summary.initial_cost, expected_cost);
  297. EXPECT_EQ(summary.final_cost, expected_cost);
  298. EXPECT_EQ(summary.iterations.size(), 0);
  299. }
  300. struct LinearCostFunction {
  301. template <typename T>
  302. bool operator()(const T* x, const T* y, T* residual) const {
  303. residual[0] = T(10.0) - *x;
  304. residual[1] = T(5.0) - *y;
  305. return true;
  306. }
  307. static CostFunction* Create() {
  308. return new AutoDiffCostFunction<LinearCostFunction, 2, 1, 1>(
  309. new LinearCostFunction);
  310. }
  311. };
  312. TEST(Solver, ZeroSizedManifoldHoldsParameterBlockConstant) {
  313. double x = 0.0;
  314. double y = 1.0;
  315. Problem problem;
  316. problem.AddResidualBlock(LinearCostFunction::Create(), nullptr, &x, &y);
  317. problem.SetManifold(&y, new SubsetManifold(1, {0}));
  318. EXPECT_TRUE(problem.IsParameterBlockConstant(&y));
  319. Solver::Options options;
  320. options.function_tolerance = 0.0;
  321. options.gradient_tolerance = 0.0;
  322. options.parameter_tolerance = 0.0;
  323. Solver::Summary summary;
  324. Solve(options, &problem, &summary);
  325. EXPECT_EQ(summary.termination_type, CONVERGENCE);
  326. EXPECT_NEAR(x, 10.0, 1e-7);
  327. EXPECT_EQ(y, 1.0);
  328. }
  329. TEST(Solver, DenseNormalCholeskyOptions) {
  330. std::string message;
  331. Solver::Options options;
  332. options.linear_solver_type = DENSE_NORMAL_CHOLESKY;
  333. EXPECT_TRUE(options.IsValid(&message));
  334. options.dense_linear_algebra_library_type = EIGEN;
  335. options.use_mixed_precision_solves = false;
  336. EXPECT_TRUE(options.IsValid(&message));
  337. options.use_mixed_precision_solves = true;
  338. EXPECT_TRUE(options.IsValid(&message));
  339. if (IsDenseLinearAlgebraLibraryTypeAvailable(LAPACK)) {
  340. options.use_mixed_precision_solves = false;
  341. options.dense_linear_algebra_library_type = LAPACK;
  342. EXPECT_TRUE(options.IsValid(&message));
  343. options.use_mixed_precision_solves = true;
  344. EXPECT_TRUE(options.IsValid(&message));
  345. } else {
  346. options.use_mixed_precision_solves = false;
  347. options.dense_linear_algebra_library_type = LAPACK;
  348. EXPECT_FALSE(options.IsValid(&message));
  349. }
  350. }
  351. TEST(Solver, DenseQrOptions) {
  352. std::string message;
  353. Solver::Options options;
  354. options.linear_solver_type = DENSE_QR;
  355. options.use_mixed_precision_solves = false;
  356. options.dense_linear_algebra_library_type = EIGEN;
  357. EXPECT_TRUE(options.IsValid(&message));
  358. options.use_mixed_precision_solves = true;
  359. EXPECT_FALSE(options.IsValid(&message));
  360. if (IsDenseLinearAlgebraLibraryTypeAvailable(LAPACK)) {
  361. options.use_mixed_precision_solves = false;
  362. options.dense_linear_algebra_library_type = LAPACK;
  363. EXPECT_TRUE(options.IsValid(&message));
  364. options.use_mixed_precision_solves = true;
  365. EXPECT_FALSE(options.IsValid(&message));
  366. } else {
  367. options.use_mixed_precision_solves = false;
  368. options.dense_linear_algebra_library_type = LAPACK;
  369. EXPECT_FALSE(options.IsValid(&message));
  370. }
  371. }
  372. TEST(Solver, SparseNormalCholeskyOptionsNoSparse) {
  373. std::string message;
  374. Solver::Options options;
  375. options.linear_solver_type = SPARSE_NORMAL_CHOLESKY;
  376. options.sparse_linear_algebra_library_type = NO_SPARSE;
  377. EXPECT_FALSE(options.IsValid(&message));
  378. }
  379. TEST(Solver, SparseNormalCholeskyOptionsEigenSparse) {
  380. std::string message;
  381. Solver::Options options;
  382. options.linear_solver_type = SPARSE_NORMAL_CHOLESKY;
  383. options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
  384. options.linear_solver_ordering_type = AMD;
  385. options.use_mixed_precision_solves = false;
  386. options.dynamic_sparsity = false;
  387. if (IsSparseLinearAlgebraLibraryTypeAvailable(EIGEN_SPARSE)) {
  388. EXPECT_TRUE(options.IsValid(&message));
  389. } else {
  390. EXPECT_FALSE(options.IsValid(&message));
  391. }
  392. if (IsSparseLinearAlgebraLibraryTypeAvailable(EIGEN_SPARSE)) {
  393. options.use_mixed_precision_solves = true;
  394. options.dynamic_sparsity = false;
  395. EXPECT_TRUE(options.IsValid(&message));
  396. options.use_mixed_precision_solves = false;
  397. options.dynamic_sparsity = true;
  398. EXPECT_TRUE(options.IsValid(&message));
  399. options.use_mixed_precision_solves = true;
  400. options.dynamic_sparsity = true;
  401. EXPECT_TRUE(options.IsValid(&message));
  402. }
  403. #ifndef CERES_NO_EIGEN_METIS
  404. options.linear_solver_ordering_type = NESDIS;
  405. if (IsSparseLinearAlgebraLibraryTypeAvailable(EIGEN_SPARSE)) {
  406. options.use_mixed_precision_solves = false;
  407. options.dynamic_sparsity = false;
  408. EXPECT_TRUE(options.IsValid(&message));
  409. options.use_mixed_precision_solves = true;
  410. options.dynamic_sparsity = false;
  411. EXPECT_TRUE(options.IsValid(&message));
  412. options.use_mixed_precision_solves = false;
  413. options.dynamic_sparsity = true;
  414. EXPECT_TRUE(options.IsValid(&message));
  415. options.use_mixed_precision_solves = true;
  416. options.dynamic_sparsity = true;
  417. EXPECT_TRUE(options.IsValid(&message));
  418. }
  419. #else
  420. options.linear_solver_ordering_type = NESDIS;
  421. options.use_mixed_precision_solves = false;
  422. options.dynamic_sparsity = false;
  423. EXPECT_FALSE(options.IsValid(&message));
  424. #endif
  425. }
  426. TEST(Solver, SparseNormalCholeskyOptionsSuiteSparse) {
  427. std::string message;
  428. Solver::Options options;
  429. options.linear_solver_type = SPARSE_NORMAL_CHOLESKY;
  430. options.sparse_linear_algebra_library_type = SUITE_SPARSE;
  431. options.linear_solver_ordering_type = AMD;
  432. options.use_mixed_precision_solves = false;
  433. options.dynamic_sparsity = false;
  434. if (IsSparseLinearAlgebraLibraryTypeAvailable(
  435. options.sparse_linear_algebra_library_type)) {
  436. EXPECT_TRUE(options.IsValid(&message));
  437. } else {
  438. EXPECT_FALSE(options.IsValid(&message));
  439. }
  440. if (IsSparseLinearAlgebraLibraryTypeAvailable(
  441. options.sparse_linear_algebra_library_type)) {
  442. options.use_mixed_precision_solves = true;
  443. options.dynamic_sparsity = false;
  444. EXPECT_FALSE(options.IsValid(&message));
  445. options.use_mixed_precision_solves = false;
  446. options.dynamic_sparsity = true;
  447. EXPECT_TRUE(options.IsValid(&message));
  448. options.use_mixed_precision_solves = true;
  449. options.dynamic_sparsity = true;
  450. EXPECT_FALSE(options.IsValid(&message));
  451. }
  452. #ifndef CERES_NO_CHOLMOD_PARTITION
  453. options.linear_solver_ordering_type = NESDIS;
  454. if (IsSparseLinearAlgebraLibraryTypeAvailable(
  455. options.sparse_linear_algebra_library_type)) {
  456. options.use_mixed_precision_solves = false;
  457. options.dynamic_sparsity = false;
  458. EXPECT_TRUE(options.IsValid(&message));
  459. options.use_mixed_precision_solves = true;
  460. options.dynamic_sparsity = false;
  461. EXPECT_FALSE(options.IsValid(&message));
  462. options.use_mixed_precision_solves = false;
  463. options.dynamic_sparsity = true;
  464. EXPECT_TRUE(options.IsValid(&message));
  465. options.use_mixed_precision_solves = true;
  466. options.dynamic_sparsity = true;
  467. EXPECT_FALSE(options.IsValid(&message));
  468. }
  469. #else
  470. options.linear_solver_ordering_type = NESDIS;
  471. options.use_mixed_precision_solves = false;
  472. options.dynamic_sparsity = false;
  473. EXPECT_FALSE(options.IsValid(&message));
  474. #endif
  475. }
  476. TEST(Solver, SparseNormalCholeskyOptionsAccelerateSparse) {
  477. std::string message;
  478. Solver::Options options;
  479. options.linear_solver_type = SPARSE_NORMAL_CHOLESKY;
  480. options.sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
  481. options.linear_solver_ordering_type = AMD;
  482. options.use_mixed_precision_solves = false;
  483. options.dynamic_sparsity = false;
  484. if (IsSparseLinearAlgebraLibraryTypeAvailable(
  485. options.sparse_linear_algebra_library_type)) {
  486. EXPECT_TRUE(options.IsValid(&message));
  487. } else {
  488. EXPECT_FALSE(options.IsValid(&message));
  489. }
  490. if (IsSparseLinearAlgebraLibraryTypeAvailable(
  491. options.sparse_linear_algebra_library_type)) {
  492. options.use_mixed_precision_solves = true;
  493. options.dynamic_sparsity = false;
  494. EXPECT_TRUE(options.IsValid(&message));
  495. options.use_mixed_precision_solves = false;
  496. options.dynamic_sparsity = true;
  497. EXPECT_FALSE(options.IsValid(&message));
  498. options.use_mixed_precision_solves = true;
  499. options.dynamic_sparsity = true;
  500. EXPECT_FALSE(options.IsValid(&message));
  501. }
  502. options.linear_solver_ordering_type = NESDIS;
  503. if (IsSparseLinearAlgebraLibraryTypeAvailable(
  504. options.sparse_linear_algebra_library_type)) {
  505. options.use_mixed_precision_solves = false;
  506. options.dynamic_sparsity = false;
  507. EXPECT_TRUE(options.IsValid(&message));
  508. options.use_mixed_precision_solves = true;
  509. options.dynamic_sparsity = false;
  510. EXPECT_TRUE(options.IsValid(&message));
  511. options.use_mixed_precision_solves = false;
  512. options.dynamic_sparsity = true;
  513. EXPECT_FALSE(options.IsValid(&message));
  514. options.use_mixed_precision_solves = true;
  515. options.dynamic_sparsity = true;
  516. EXPECT_FALSE(options.IsValid(&message));
  517. }
  518. }
  519. TEST(Solver, DenseSchurOptions) {
  520. std::string message;
  521. Solver::Options options;
  522. options.linear_solver_type = DENSE_SCHUR;
  523. options.dense_linear_algebra_library_type = EIGEN;
  524. options.use_mixed_precision_solves = false;
  525. options.dynamic_sparsity = false;
  526. EXPECT_TRUE(options.IsValid(&message));
  527. options.use_mixed_precision_solves = true;
  528. options.dynamic_sparsity = false;
  529. EXPECT_TRUE(options.IsValid(&message));
  530. options.use_mixed_precision_solves = true;
  531. options.dynamic_sparsity = true;
  532. EXPECT_FALSE(options.IsValid(&message));
  533. options.use_mixed_precision_solves = false;
  534. options.dynamic_sparsity = true;
  535. EXPECT_FALSE(options.IsValid(&message));
  536. options.dense_linear_algebra_library_type = LAPACK;
  537. if (IsDenseLinearAlgebraLibraryTypeAvailable(
  538. options.dense_linear_algebra_library_type)) {
  539. options.use_mixed_precision_solves = false;
  540. options.dynamic_sparsity = false;
  541. EXPECT_TRUE(options.IsValid(&message));
  542. options.use_mixed_precision_solves = true;
  543. options.dynamic_sparsity = false;
  544. EXPECT_TRUE(options.IsValid(&message));
  545. options.use_mixed_precision_solves = true;
  546. options.dynamic_sparsity = true;
  547. EXPECT_FALSE(options.IsValid(&message));
  548. options.use_mixed_precision_solves = false;
  549. options.dynamic_sparsity = true;
  550. EXPECT_FALSE(options.IsValid(&message));
  551. }
  552. }
  553. TEST(Solver, SparseSchurOptionsNoSparse) {
  554. std::string message;
  555. Solver::Options options;
  556. options.linear_solver_type = SPARSE_SCHUR;
  557. options.sparse_linear_algebra_library_type = NO_SPARSE;
  558. EXPECT_FALSE(options.IsValid(&message));
  559. }
  560. TEST(Solver, SparseSchurOptionsEigenSparse) {
  561. std::string message;
  562. Solver::Options options;
  563. options.linear_solver_type = SPARSE_SCHUR;
  564. options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
  565. options.linear_solver_ordering_type = AMD;
  566. options.use_mixed_precision_solves = false;
  567. options.dynamic_sparsity = false;
  568. if (IsSparseLinearAlgebraLibraryTypeAvailable(EIGEN_SPARSE)) {
  569. EXPECT_TRUE(options.IsValid(&message));
  570. } else {
  571. EXPECT_FALSE(options.IsValid(&message));
  572. }
  573. if (IsSparseLinearAlgebraLibraryTypeAvailable(EIGEN_SPARSE)) {
  574. options.use_mixed_precision_solves = true;
  575. options.dynamic_sparsity = false;
  576. EXPECT_TRUE(options.IsValid(&message));
  577. options.use_mixed_precision_solves = false;
  578. options.dynamic_sparsity = true;
  579. EXPECT_FALSE(options.IsValid(&message));
  580. options.use_mixed_precision_solves = true;
  581. options.dynamic_sparsity = true;
  582. EXPECT_FALSE(options.IsValid(&message));
  583. }
  584. #ifndef CERES_NO_EIGEN_METIS
  585. options.linear_solver_ordering_type = NESDIS;
  586. if (IsSparseLinearAlgebraLibraryTypeAvailable(EIGEN_SPARSE)) {
  587. options.use_mixed_precision_solves = false;
  588. options.dynamic_sparsity = false;
  589. EXPECT_TRUE(options.IsValid(&message));
  590. options.use_mixed_precision_solves = true;
  591. options.dynamic_sparsity = false;
  592. EXPECT_TRUE(options.IsValid(&message));
  593. options.use_mixed_precision_solves = false;
  594. options.dynamic_sparsity = true;
  595. EXPECT_FALSE(options.IsValid(&message));
  596. options.use_mixed_precision_solves = true;
  597. options.dynamic_sparsity = true;
  598. EXPECT_FALSE(options.IsValid(&message));
  599. }
  600. #else
  601. options.linear_solver_ordering_type = NESDIS;
  602. options.use_mixed_precision_solves = false;
  603. options.dynamic_sparsity = false;
  604. EXPECT_FALSE(options.IsValid(&message));
  605. #endif
  606. }
  607. TEST(Solver, SparseSchurOptionsSuiteSparse) {
  608. std::string message;
  609. Solver::Options options;
  610. options.linear_solver_type = SPARSE_SCHUR;
  611. options.sparse_linear_algebra_library_type = SUITE_SPARSE;
  612. options.linear_solver_ordering_type = AMD;
  613. options.use_mixed_precision_solves = false;
  614. options.dynamic_sparsity = false;
  615. if (IsSparseLinearAlgebraLibraryTypeAvailable(
  616. options.sparse_linear_algebra_library_type)) {
  617. EXPECT_TRUE(options.IsValid(&message));
  618. } else {
  619. EXPECT_FALSE(options.IsValid(&message));
  620. }
  621. if (IsSparseLinearAlgebraLibraryTypeAvailable(
  622. options.sparse_linear_algebra_library_type)) {
  623. options.use_mixed_precision_solves = true;
  624. options.dynamic_sparsity = false;
  625. EXPECT_FALSE(options.IsValid(&message));
  626. options.use_mixed_precision_solves = false;
  627. options.dynamic_sparsity = true;
  628. EXPECT_FALSE(options.IsValid(&message));
  629. options.use_mixed_precision_solves = true;
  630. options.dynamic_sparsity = true;
  631. EXPECT_FALSE(options.IsValid(&message));
  632. }
  633. #ifndef CERES_NO_CHOLMOD_PARTITION
  634. options.linear_solver_ordering_type = NESDIS;
  635. if (IsSparseLinearAlgebraLibraryTypeAvailable(
  636. options.sparse_linear_algebra_library_type)) {
  637. options.use_mixed_precision_solves = false;
  638. options.dynamic_sparsity = false;
  639. EXPECT_TRUE(options.IsValid(&message));
  640. options.use_mixed_precision_solves = true;
  641. options.dynamic_sparsity = false;
  642. EXPECT_FALSE(options.IsValid(&message));
  643. options.use_mixed_precision_solves = false;
  644. options.dynamic_sparsity = true;
  645. EXPECT_FALSE(options.IsValid(&message));
  646. options.use_mixed_precision_solves = true;
  647. options.dynamic_sparsity = true;
  648. EXPECT_FALSE(options.IsValid(&message));
  649. }
  650. #else
  651. options.linear_solver_ordering_type = NESDIS;
  652. options.use_mixed_precision_solves = false;
  653. options.dynamic_sparsity = false;
  654. EXPECT_FALSE(options.IsValid(&message));
  655. #endif
  656. }
  657. TEST(Solver, SparseSchurOptionsAccelerateSparse) {
  658. std::string message;
  659. Solver::Options options;
  660. options.linear_solver_type = SPARSE_SCHUR;
  661. options.sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
  662. options.linear_solver_ordering_type = AMD;
  663. options.use_mixed_precision_solves = false;
  664. options.dynamic_sparsity = false;
  665. if (IsSparseLinearAlgebraLibraryTypeAvailable(
  666. options.sparse_linear_algebra_library_type)) {
  667. EXPECT_TRUE(options.IsValid(&message));
  668. } else {
  669. EXPECT_FALSE(options.IsValid(&message));
  670. }
  671. if (IsSparseLinearAlgebraLibraryTypeAvailable(
  672. options.sparse_linear_algebra_library_type)) {
  673. options.use_mixed_precision_solves = true;
  674. options.dynamic_sparsity = false;
  675. EXPECT_TRUE(options.IsValid(&message));
  676. options.use_mixed_precision_solves = false;
  677. options.dynamic_sparsity = true;
  678. EXPECT_FALSE(options.IsValid(&message));
  679. options.use_mixed_precision_solves = true;
  680. options.dynamic_sparsity = true;
  681. EXPECT_FALSE(options.IsValid(&message));
  682. }
  683. options.linear_solver_ordering_type = NESDIS;
  684. if (IsSparseLinearAlgebraLibraryTypeAvailable(
  685. options.sparse_linear_algebra_library_type)) {
  686. options.use_mixed_precision_solves = false;
  687. options.dynamic_sparsity = false;
  688. EXPECT_TRUE(options.IsValid(&message));
  689. options.use_mixed_precision_solves = true;
  690. options.dynamic_sparsity = false;
  691. EXPECT_TRUE(options.IsValid(&message));
  692. options.use_mixed_precision_solves = false;
  693. options.dynamic_sparsity = true;
  694. EXPECT_FALSE(options.IsValid(&message));
  695. options.use_mixed_precision_solves = true;
  696. options.dynamic_sparsity = true;
  697. EXPECT_FALSE(options.IsValid(&message));
  698. }
  699. }
  700. TEST(Solver, CgnrOptionsIdentityPreconditioner) {
  701. std::string message;
  702. Solver::Options options;
  703. options.linear_solver_type = CGNR;
  704. options.preconditioner_type = IDENTITY;
  705. options.sparse_linear_algebra_library_type = NO_SPARSE;
  706. options.dynamic_sparsity = false;
  707. options.use_mixed_precision_solves = false;
  708. EXPECT_TRUE(options.IsValid(&message));
  709. options.dynamic_sparsity = true;
  710. options.use_mixed_precision_solves = false;
  711. EXPECT_FALSE(options.IsValid(&message));
  712. options.dynamic_sparsity = false;
  713. options.use_mixed_precision_solves = true;
  714. EXPECT_FALSE(options.IsValid(&message));
  715. options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
  716. options.dynamic_sparsity = false;
  717. options.use_mixed_precision_solves = false;
  718. EXPECT_TRUE(options.IsValid(&message));
  719. options.dynamic_sparsity = true;
  720. options.use_mixed_precision_solves = false;
  721. EXPECT_FALSE(options.IsValid(&message));
  722. options.dynamic_sparsity = false;
  723. options.use_mixed_precision_solves = true;
  724. EXPECT_FALSE(options.IsValid(&message));
  725. options.sparse_linear_algebra_library_type = SUITE_SPARSE;
  726. options.dynamic_sparsity = false;
  727. options.use_mixed_precision_solves = false;
  728. EXPECT_TRUE(options.IsValid(&message));
  729. options.dynamic_sparsity = true;
  730. options.use_mixed_precision_solves = false;
  731. EXPECT_FALSE(options.IsValid(&message));
  732. options.dynamic_sparsity = false;
  733. options.use_mixed_precision_solves = true;
  734. EXPECT_FALSE(options.IsValid(&message));
  735. options.sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
  736. options.dynamic_sparsity = false;
  737. options.use_mixed_precision_solves = false;
  738. EXPECT_TRUE(options.IsValid(&message));
  739. options.dynamic_sparsity = true;
  740. options.use_mixed_precision_solves = false;
  741. EXPECT_FALSE(options.IsValid(&message));
  742. options.dynamic_sparsity = false;
  743. options.use_mixed_precision_solves = true;
  744. EXPECT_FALSE(options.IsValid(&message));
  745. options.sparse_linear_algebra_library_type = CUDA_SPARSE;
  746. options.dynamic_sparsity = false;
  747. options.use_mixed_precision_solves = false;
  748. EXPECT_EQ(options.IsValid(&message),
  749. IsSparseLinearAlgebraLibraryTypeAvailable(CUDA_SPARSE));
  750. options.dynamic_sparsity = true;
  751. options.use_mixed_precision_solves = false;
  752. EXPECT_FALSE(options.IsValid(&message));
  753. options.dynamic_sparsity = false;
  754. options.use_mixed_precision_solves = true;
  755. EXPECT_FALSE(options.IsValid(&message));
  756. }
  757. TEST(Solver, CgnrOptionsJacobiPreconditioner) {
  758. std::string message;
  759. Solver::Options options;
  760. options.linear_solver_type = CGNR;
  761. options.preconditioner_type = JACOBI;
  762. options.sparse_linear_algebra_library_type = NO_SPARSE;
  763. options.dynamic_sparsity = false;
  764. options.use_mixed_precision_solves = false;
  765. EXPECT_TRUE(options.IsValid(&message));
  766. options.dynamic_sparsity = true;
  767. options.use_mixed_precision_solves = false;
  768. EXPECT_FALSE(options.IsValid(&message));
  769. options.dynamic_sparsity = false;
  770. options.use_mixed_precision_solves = true;
  771. EXPECT_FALSE(options.IsValid(&message));
  772. options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
  773. options.dynamic_sparsity = false;
  774. options.use_mixed_precision_solves = false;
  775. EXPECT_TRUE(options.IsValid(&message));
  776. options.dynamic_sparsity = true;
  777. options.use_mixed_precision_solves = false;
  778. EXPECT_FALSE(options.IsValid(&message));
  779. options.dynamic_sparsity = false;
  780. options.use_mixed_precision_solves = true;
  781. EXPECT_FALSE(options.IsValid(&message));
  782. options.sparse_linear_algebra_library_type = SUITE_SPARSE;
  783. options.dynamic_sparsity = false;
  784. options.use_mixed_precision_solves = false;
  785. EXPECT_TRUE(options.IsValid(&message));
  786. options.dynamic_sparsity = true;
  787. options.use_mixed_precision_solves = false;
  788. EXPECT_FALSE(options.IsValid(&message));
  789. options.dynamic_sparsity = false;
  790. options.use_mixed_precision_solves = true;
  791. EXPECT_FALSE(options.IsValid(&message));
  792. options.sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
  793. options.dynamic_sparsity = false;
  794. options.use_mixed_precision_solves = false;
  795. EXPECT_TRUE(options.IsValid(&message));
  796. options.dynamic_sparsity = true;
  797. options.use_mixed_precision_solves = false;
  798. EXPECT_FALSE(options.IsValid(&message));
  799. options.dynamic_sparsity = false;
  800. options.use_mixed_precision_solves = true;
  801. EXPECT_FALSE(options.IsValid(&message));
  802. options.sparse_linear_algebra_library_type = CUDA_SPARSE;
  803. options.dynamic_sparsity = false;
  804. options.use_mixed_precision_solves = false;
  805. EXPECT_EQ(options.IsValid(&message),
  806. IsSparseLinearAlgebraLibraryTypeAvailable(CUDA_SPARSE));
  807. options.dynamic_sparsity = true;
  808. options.use_mixed_precision_solves = false;
  809. EXPECT_FALSE(options.IsValid(&message));
  810. options.dynamic_sparsity = false;
  811. options.use_mixed_precision_solves = true;
  812. EXPECT_FALSE(options.IsValid(&message));
  813. }
  814. TEST(Solver, CgnrOptionsSubsetPreconditioner) {
  815. std::string message;
  816. Solver::Options options;
  817. options.linear_solver_type = CGNR;
  818. options.preconditioner_type = SUBSET;
  819. options.sparse_linear_algebra_library_type = NO_SPARSE;
  820. EXPECT_FALSE(options.IsValid(&message));
  821. options.residual_blocks_for_subset_preconditioner.insert(nullptr);
  822. EXPECT_FALSE(options.IsValid(&message));
  823. options.dynamic_sparsity = false;
  824. options.use_mixed_precision_solves = false;
  825. EXPECT_FALSE(options.IsValid(&message));
  826. options.dynamic_sparsity = true;
  827. options.use_mixed_precision_solves = false;
  828. EXPECT_FALSE(options.IsValid(&message));
  829. options.dynamic_sparsity = false;
  830. options.use_mixed_precision_solves = true;
  831. EXPECT_FALSE(options.IsValid(&message));
  832. options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
  833. if (IsSparseLinearAlgebraLibraryTypeAvailable(
  834. options.sparse_linear_algebra_library_type)) {
  835. options.dynamic_sparsity = false;
  836. options.use_mixed_precision_solves = false;
  837. EXPECT_TRUE(options.IsValid(&message));
  838. options.dynamic_sparsity = true;
  839. options.use_mixed_precision_solves = false;
  840. EXPECT_FALSE(options.IsValid(&message));
  841. options.dynamic_sparsity = false;
  842. options.use_mixed_precision_solves = true;
  843. EXPECT_FALSE(options.IsValid(&message));
  844. }
  845. options.sparse_linear_algebra_library_type = SUITE_SPARSE;
  846. if (IsSparseLinearAlgebraLibraryTypeAvailable(
  847. options.sparse_linear_algebra_library_type)) {
  848. options.dynamic_sparsity = false;
  849. options.use_mixed_precision_solves = false;
  850. EXPECT_TRUE(options.IsValid(&message));
  851. options.dynamic_sparsity = true;
  852. options.use_mixed_precision_solves = false;
  853. EXPECT_FALSE(options.IsValid(&message));
  854. options.dynamic_sparsity = false;
  855. options.use_mixed_precision_solves = true;
  856. EXPECT_FALSE(options.IsValid(&message));
  857. }
  858. options.sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
  859. if (IsSparseLinearAlgebraLibraryTypeAvailable(
  860. options.sparse_linear_algebra_library_type)) {
  861. options.dynamic_sparsity = false;
  862. options.use_mixed_precision_solves = false;
  863. EXPECT_TRUE(options.IsValid(&message));
  864. options.dynamic_sparsity = true;
  865. options.use_mixed_precision_solves = false;
  866. EXPECT_FALSE(options.IsValid(&message));
  867. options.dynamic_sparsity = false;
  868. options.use_mixed_precision_solves = true;
  869. EXPECT_FALSE(options.IsValid(&message));
  870. }
  871. options.sparse_linear_algebra_library_type = CUDA_SPARSE;
  872. options.dynamic_sparsity = false;
  873. options.use_mixed_precision_solves = false;
  874. EXPECT_FALSE(options.IsValid(&message));
  875. options.dynamic_sparsity = true;
  876. options.use_mixed_precision_solves = false;
  877. EXPECT_FALSE(options.IsValid(&message));
  878. options.dynamic_sparsity = false;
  879. options.use_mixed_precision_solves = true;
  880. EXPECT_FALSE(options.IsValid(&message));
  881. }
  882. TEST(Solver, CgnrOptionsSchurPreconditioners) {
  883. std::string message;
  884. Solver::Options options;
  885. options.linear_solver_type = CGNR;
  886. options.preconditioner_type = SCHUR_JACOBI;
  887. EXPECT_FALSE(options.IsValid(&message));
  888. options.preconditioner_type = CLUSTER_JACOBI;
  889. EXPECT_FALSE(options.IsValid(&message));
  890. options.preconditioner_type = CLUSTER_TRIDIAGONAL;
  891. EXPECT_FALSE(options.IsValid(&message));
  892. }
  893. TEST(Solver, IterativeSchurOptionsNoSparse) {
  894. std::string message;
  895. Solver::Options options;
  896. options.linear_solver_type = ITERATIVE_SCHUR;
  897. options.sparse_linear_algebra_library_type = NO_SPARSE;
  898. options.preconditioner_type = IDENTITY;
  899. EXPECT_TRUE(options.IsValid(&message));
  900. options.preconditioner_type = JACOBI;
  901. EXPECT_TRUE(options.IsValid(&message));
  902. options.preconditioner_type = SCHUR_JACOBI;
  903. EXPECT_TRUE(options.IsValid(&message));
  904. options.preconditioner_type = CLUSTER_JACOBI;
  905. EXPECT_FALSE(options.IsValid(&message));
  906. options.preconditioner_type = CLUSTER_TRIDIAGONAL;
  907. EXPECT_FALSE(options.IsValid(&message));
  908. options.preconditioner_type = SUBSET;
  909. EXPECT_FALSE(options.IsValid(&message));
  910. options.use_explicit_schur_complement = true;
  911. options.preconditioner_type = IDENTITY;
  912. EXPECT_FALSE(options.IsValid(&message));
  913. options.preconditioner_type = JACOBI;
  914. EXPECT_FALSE(options.IsValid(&message));
  915. options.preconditioner_type = SCHUR_JACOBI;
  916. EXPECT_TRUE(options.IsValid(&message));
  917. options.preconditioner_type = CLUSTER_JACOBI;
  918. EXPECT_FALSE(options.IsValid(&message));
  919. options.preconditioner_type = CLUSTER_TRIDIAGONAL;
  920. EXPECT_FALSE(options.IsValid(&message));
  921. }
  922. TEST(Solver, IterativeSchurOptionsEigenSparse) {
  923. std::string message;
  924. Solver::Options options;
  925. options.linear_solver_type = ITERATIVE_SCHUR;
  926. options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
  927. options.preconditioner_type = IDENTITY;
  928. EXPECT_TRUE(options.IsValid(&message));
  929. options.preconditioner_type = JACOBI;
  930. EXPECT_TRUE(options.IsValid(&message));
  931. options.preconditioner_type = SCHUR_JACOBI;
  932. EXPECT_TRUE(options.IsValid(&message));
  933. options.preconditioner_type = CLUSTER_JACOBI;
  934. EXPECT_EQ(options.IsValid(&message),
  935. IsSparseLinearAlgebraLibraryTypeAvailable(
  936. options.sparse_linear_algebra_library_type));
  937. options.preconditioner_type = CLUSTER_TRIDIAGONAL;
  938. EXPECT_EQ(options.IsValid(&message),
  939. IsSparseLinearAlgebraLibraryTypeAvailable(
  940. options.sparse_linear_algebra_library_type));
  941. options.preconditioner_type = SUBSET;
  942. EXPECT_FALSE(options.IsValid(&message));
  943. options.use_explicit_schur_complement = true;
  944. options.preconditioner_type = IDENTITY;
  945. EXPECT_FALSE(options.IsValid(&message));
  946. options.preconditioner_type = JACOBI;
  947. EXPECT_FALSE(options.IsValid(&message));
  948. options.preconditioner_type = SCHUR_JACOBI;
  949. EXPECT_TRUE(options.IsValid(&message));
  950. options.preconditioner_type = CLUSTER_JACOBI;
  951. EXPECT_FALSE(options.IsValid(&message));
  952. options.preconditioner_type = CLUSTER_TRIDIAGONAL;
  953. EXPECT_FALSE(options.IsValid(&message));
  954. }
  955. TEST(Solver, IterativeSchurOptionsSuiteSparse) {
  956. std::string message;
  957. Solver::Options options;
  958. options.linear_solver_type = ITERATIVE_SCHUR;
  959. options.sparse_linear_algebra_library_type = SUITE_SPARSE;
  960. options.preconditioner_type = IDENTITY;
  961. EXPECT_TRUE(options.IsValid(&message));
  962. options.preconditioner_type = JACOBI;
  963. EXPECT_TRUE(options.IsValid(&message));
  964. options.preconditioner_type = SCHUR_JACOBI;
  965. EXPECT_TRUE(options.IsValid(&message));
  966. options.preconditioner_type = CLUSTER_JACOBI;
  967. EXPECT_EQ(options.IsValid(&message),
  968. IsSparseLinearAlgebraLibraryTypeAvailable(
  969. options.sparse_linear_algebra_library_type));
  970. options.preconditioner_type = CLUSTER_TRIDIAGONAL;
  971. EXPECT_EQ(options.IsValid(&message),
  972. IsSparseLinearAlgebraLibraryTypeAvailable(
  973. options.sparse_linear_algebra_library_type));
  974. options.preconditioner_type = SUBSET;
  975. EXPECT_FALSE(options.IsValid(&message));
  976. options.use_explicit_schur_complement = true;
  977. options.preconditioner_type = IDENTITY;
  978. EXPECT_FALSE(options.IsValid(&message));
  979. options.preconditioner_type = JACOBI;
  980. EXPECT_FALSE(options.IsValid(&message));
  981. options.preconditioner_type = SCHUR_JACOBI;
  982. EXPECT_TRUE(options.IsValid(&message));
  983. options.preconditioner_type = CLUSTER_JACOBI;
  984. EXPECT_FALSE(options.IsValid(&message));
  985. options.preconditioner_type = CLUSTER_TRIDIAGONAL;
  986. EXPECT_FALSE(options.IsValid(&message));
  987. }
  988. TEST(Solver, IterativeSchurOptionsAccelerateSparse) {
  989. std::string message;
  990. Solver::Options options;
  991. options.linear_solver_type = ITERATIVE_SCHUR;
  992. options.sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
  993. options.preconditioner_type = IDENTITY;
  994. EXPECT_TRUE(options.IsValid(&message));
  995. options.preconditioner_type = JACOBI;
  996. EXPECT_TRUE(options.IsValid(&message));
  997. options.preconditioner_type = SCHUR_JACOBI;
  998. EXPECT_TRUE(options.IsValid(&message));
  999. options.preconditioner_type = CLUSTER_JACOBI;
  1000. EXPECT_EQ(options.IsValid(&message),
  1001. IsSparseLinearAlgebraLibraryTypeAvailable(
  1002. options.sparse_linear_algebra_library_type));
  1003. options.preconditioner_type = CLUSTER_TRIDIAGONAL;
  1004. EXPECT_EQ(options.IsValid(&message),
  1005. IsSparseLinearAlgebraLibraryTypeAvailable(
  1006. options.sparse_linear_algebra_library_type));
  1007. options.preconditioner_type = SUBSET;
  1008. EXPECT_FALSE(options.IsValid(&message));
  1009. options.use_explicit_schur_complement = true;
  1010. options.preconditioner_type = IDENTITY;
  1011. EXPECT_FALSE(options.IsValid(&message));
  1012. options.preconditioner_type = JACOBI;
  1013. EXPECT_FALSE(options.IsValid(&message));
  1014. options.preconditioner_type = SCHUR_JACOBI;
  1015. EXPECT_TRUE(options.IsValid(&message));
  1016. options.preconditioner_type = CLUSTER_JACOBI;
  1017. EXPECT_FALSE(options.IsValid(&message));
  1018. options.preconditioner_type = CLUSTER_TRIDIAGONAL;
  1019. EXPECT_FALSE(options.IsValid(&message));
  1020. }
  1021. } // namespace ceres::internal