1 // Ceres Solver - A fast non-linear least squares minimizer
2 // Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
3 // http://code.google.com/p/ceres-solver/
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/linear_least_squares_problems.h"
32
33 #include <cstdio>
34 #include <string>
35 #include <vector>
36 #include "ceres/block_sparse_matrix.h"
37 #include "ceres/block_structure.h"
38 #include "ceres/casts.h"
39 #include "ceres/compressed_row_sparse_matrix.h"
40 #include "ceres/file.h"
41 #include "ceres/internal/scoped_ptr.h"
42 #include "ceres/matrix_proto.h"
43 #include "ceres/stringprintf.h"
44 #include "ceres/triplet_sparse_matrix.h"
45 #include "ceres/types.h"
46 #include "glog/logging.h"
47
48 namespace ceres {
49 namespace internal {
50
CreateLinearLeastSquaresProblemFromId(int id)51 LinearLeastSquaresProblem* CreateLinearLeastSquaresProblemFromId(int id) {
52 switch (id) {
53 case 0:
54 return LinearLeastSquaresProblem0();
55 case 1:
56 return LinearLeastSquaresProblem1();
57 case 2:
58 return LinearLeastSquaresProblem2();
59 case 3:
60 return LinearLeastSquaresProblem3();
61 default:
62 LOG(FATAL) << "Unknown problem id requested " << id;
63 }
64 return NULL;
65 }
66
67 #ifndef CERES_NO_PROTOCOL_BUFFERS
CreateLinearLeastSquaresProblemFromFile(const string & filename)68 LinearLeastSquaresProblem* CreateLinearLeastSquaresProblemFromFile(
69 const string& filename) {
70 LinearLeastSquaresProblemProto problem_proto;
71 {
72 string serialized_proto;
73 ReadFileToStringOrDie(filename, &serialized_proto);
74 CHECK(problem_proto.ParseFromString(serialized_proto));
75 }
76
77 LinearLeastSquaresProblem* problem = new LinearLeastSquaresProblem;
78 const SparseMatrixProto& A = problem_proto.a();
79
80 if (A.has_block_matrix()) {
81 problem->A.reset(new BlockSparseMatrix(A));
82 } else if (A.has_triplet_matrix()) {
83 problem->A.reset(new TripletSparseMatrix(A));
84 } else {
85 problem->A.reset(new CompressedRowSparseMatrix(A));
86 }
87
88 if (problem_proto.b_size() > 0) {
89 problem->b.reset(new double[problem_proto.b_size()]);
90 for (int i = 0; i < problem_proto.b_size(); ++i) {
91 problem->b[i] = problem_proto.b(i);
92 }
93 }
94
95 if (problem_proto.d_size() > 0) {
96 problem->D.reset(new double[problem_proto.d_size()]);
97 for (int i = 0; i < problem_proto.d_size(); ++i) {
98 problem->D[i] = problem_proto.d(i);
99 }
100 }
101
102 if (problem_proto.d_size() > 0) {
103 if (problem_proto.x_size() > 0) {
104 problem->x_D.reset(new double[problem_proto.x_size()]);
105 for (int i = 0; i < problem_proto.x_size(); ++i) {
106 problem->x_D[i] = problem_proto.x(i);
107 }
108 }
109 } else {
110 if (problem_proto.x_size() > 0) {
111 problem->x.reset(new double[problem_proto.x_size()]);
112 for (int i = 0; i < problem_proto.x_size(); ++i) {
113 problem->x[i] = problem_proto.x(i);
114 }
115 }
116 }
117
118 problem->num_eliminate_blocks = 0;
119 if (problem_proto.has_num_eliminate_blocks()) {
120 problem->num_eliminate_blocks = problem_proto.num_eliminate_blocks();
121 }
122
123 return problem;
124 }
125 #else
CreateLinearLeastSquaresProblemFromFile(const string & filename)126 LinearLeastSquaresProblem* CreateLinearLeastSquaresProblemFromFile(
127 const string& filename) {
128 LOG(FATAL)
129 << "Loading a least squares problem from disk requires "
130 << "Ceres to be built with Protocol Buffers support.";
131 return NULL;
132 }
133 #endif // CERES_NO_PROTOCOL_BUFFERS
134
135 /*
136 A = [1 2]
137 [3 4]
138 [6 -10]
139
140 b = [ 8
141 18
142 -18]
143
144 x = [2
145 3]
146
147 D = [1
148 2]
149
150 x_D = [1.78448275;
151 2.82327586;]
152 */
LinearLeastSquaresProblem0()153 LinearLeastSquaresProblem* LinearLeastSquaresProblem0() {
154 LinearLeastSquaresProblem* problem = new LinearLeastSquaresProblem;
155
156 TripletSparseMatrix* A = new TripletSparseMatrix(3, 2, 6);
157 problem->b.reset(new double[3]);
158 problem->D.reset(new double[2]);
159
160 problem->x.reset(new double[2]);
161 problem->x_D.reset(new double[2]);
162
163 int* Ai = A->mutable_rows();
164 int* Aj = A->mutable_cols();
165 double* Ax = A->mutable_values();
166
167 int counter = 0;
168 for (int i = 0; i < 3; ++i) {
169 for (int j = 0; j< 2; ++j) {
170 Ai[counter]=i;
171 Aj[counter]=j;
172 ++counter;
173 }
174 };
175
176 Ax[0] = 1.;
177 Ax[1] = 2.;
178 Ax[2] = 3.;
179 Ax[3] = 4.;
180 Ax[4] = 6;
181 Ax[5] = -10;
182 A->set_num_nonzeros(6);
183 problem->A.reset(A);
184
185 problem->b[0] = 8;
186 problem->b[1] = 18;
187 problem->b[2] = -18;
188
189 problem->x[0] = 2.0;
190 problem->x[1] = 3.0;
191
192 problem->D[0] = 1;
193 problem->D[1] = 2;
194
195 problem->x_D[0] = 1.78448275;
196 problem->x_D[1] = 2.82327586;
197 return problem;
198 }
199
200
201 /*
202 A = [1 0 | 2 0 0
203 3 0 | 0 4 0
204 0 5 | 0 0 6
205 0 7 | 8 0 0
206 0 9 | 1 0 0
207 0 0 | 1 1 1]
208
209 b = [0
210 1
211 2
212 3
213 4
214 5]
215
216 c = A'* b = [ 3
217 67
218 33
219 9
220 17]
221
222 A'A = [10 0 2 12 0
223 0 155 65 0 30
224 2 65 70 1 1
225 12 0 1 17 1
226 0 30 1 1 37]
227
228 S = [ 42.3419 -1.4000 -11.5806
229 -1.4000 2.6000 1.0000
230 11.5806 1.0000 31.1935]
231
232 r = [ 4.3032
233 5.4000
234 5.0323]
235
236 S\r = [ 0.2102
237 2.1367
238 0.1388]
239
240 A\b = [-2.3061
241 0.3172
242 0.2102
243 2.1367
244 0.1388]
245 */
246 // The following two functions create a TripletSparseMatrix and a
247 // BlockSparseMatrix version of this problem.
248
249 // TripletSparseMatrix version.
LinearLeastSquaresProblem1()250 LinearLeastSquaresProblem* LinearLeastSquaresProblem1() {
251 int num_rows = 6;
252 int num_cols = 5;
253
254 LinearLeastSquaresProblem* problem = new LinearLeastSquaresProblem;
255 TripletSparseMatrix* A = new TripletSparseMatrix(num_rows,
256 num_cols,
257 num_rows * num_cols);
258 problem->b.reset(new double[num_rows]);
259 problem->D.reset(new double[num_cols]);
260 problem->num_eliminate_blocks = 2;
261
262 int* rows = A->mutable_rows();
263 int* cols = A->mutable_cols();
264 double* values = A->mutable_values();
265
266 int nnz = 0;
267
268 // Row 1
269 {
270 rows[nnz] = 0;
271 cols[nnz] = 0;
272 values[nnz++] = 1;
273
274 rows[nnz] = 0;
275 cols[nnz] = 2;
276 values[nnz++] = 2;
277 }
278
279 // Row 2
280 {
281 rows[nnz] = 1;
282 cols[nnz] = 0;
283 values[nnz++] = 3;
284
285 rows[nnz] = 1;
286 cols[nnz] = 3;
287 values[nnz++] = 4;
288 }
289
290 // Row 3
291 {
292 rows[nnz] = 2;
293 cols[nnz] = 1;
294 values[nnz++] = 5;
295
296 rows[nnz] = 2;
297 cols[nnz] = 4;
298 values[nnz++] = 6;
299 }
300
301 // Row 4
302 {
303 rows[nnz] = 3;
304 cols[nnz] = 1;
305 values[nnz++] = 7;
306
307 rows[nnz] = 3;
308 cols[nnz] = 2;
309 values[nnz++] = 8;
310 }
311
312 // Row 5
313 {
314 rows[nnz] = 4;
315 cols[nnz] = 1;
316 values[nnz++] = 9;
317
318 rows[nnz] = 4;
319 cols[nnz] = 2;
320 values[nnz++] = 1;
321 }
322
323 // Row 6
324 {
325 rows[nnz] = 5;
326 cols[nnz] = 2;
327 values[nnz++] = 1;
328
329 rows[nnz] = 5;
330 cols[nnz] = 3;
331 values[nnz++] = 1;
332
333 rows[nnz] = 5;
334 cols[nnz] = 4;
335 values[nnz++] = 1;
336 }
337
338 A->set_num_nonzeros(nnz);
339 CHECK(A->IsValid());
340
341 problem->A.reset(A);
342
343 for (int i = 0; i < num_cols; ++i) {
344 problem->D.get()[i] = 1;
345 }
346
347 for (int i = 0; i < num_rows; ++i) {
348 problem->b.get()[i] = i;
349 }
350
351 return problem;
352 }
353
354 // BlockSparseMatrix version
LinearLeastSquaresProblem2()355 LinearLeastSquaresProblem* LinearLeastSquaresProblem2() {
356 int num_rows = 6;
357 int num_cols = 5;
358
359 LinearLeastSquaresProblem* problem = new LinearLeastSquaresProblem;
360
361 problem->b.reset(new double[num_rows]);
362 problem->D.reset(new double[num_cols]);
363 problem->num_eliminate_blocks = 2;
364
365 CompressedRowBlockStructure* bs = new CompressedRowBlockStructure;
366 scoped_array<double> values(new double[num_rows * num_cols]);
367
368 for (int c = 0; c < num_cols; ++c) {
369 bs->cols.push_back(Block());
370 bs->cols.back().size = 1;
371 bs->cols.back().position = c;
372 }
373
374 int nnz = 0;
375
376 // Row 1
377 {
378 values[nnz++] = 1;
379 values[nnz++] = 2;
380
381 bs->rows.push_back(CompressedRow());
382 CompressedRow& row = bs->rows.back();
383 row.block.size = 1;
384 row.block.position = 0;
385 row.cells.push_back(Cell(0, 0));
386 row.cells.push_back(Cell(2, 1));
387 }
388
389 // Row 2
390 {
391 values[nnz++] = 3;
392 values[nnz++] = 4;
393
394 bs->rows.push_back(CompressedRow());
395 CompressedRow& row = bs->rows.back();
396 row.block.size = 1;
397 row.block.position = 1;
398 row.cells.push_back(Cell(0, 2));
399 row.cells.push_back(Cell(3, 3));
400 }
401
402 // Row 3
403 {
404 values[nnz++] = 5;
405 values[nnz++] = 6;
406
407 bs->rows.push_back(CompressedRow());
408 CompressedRow& row = bs->rows.back();
409 row.block.size = 1;
410 row.block.position = 2;
411 row.cells.push_back(Cell(1, 4));
412 row.cells.push_back(Cell(4, 5));
413 }
414
415 // Row 4
416 {
417 values[nnz++] = 7;
418 values[nnz++] = 8;
419
420 bs->rows.push_back(CompressedRow());
421 CompressedRow& row = bs->rows.back();
422 row.block.size = 1;
423 row.block.position = 3;
424 row.cells.push_back(Cell(1, 6));
425 row.cells.push_back(Cell(2, 7));
426 }
427
428 // Row 5
429 {
430 values[nnz++] = 9;
431 values[nnz++] = 1;
432
433 bs->rows.push_back(CompressedRow());
434 CompressedRow& row = bs->rows.back();
435 row.block.size = 1;
436 row.block.position = 4;
437 row.cells.push_back(Cell(1, 8));
438 row.cells.push_back(Cell(2, 9));
439 }
440
441 // Row 6
442 {
443 values[nnz++] = 1;
444 values[nnz++] = 1;
445 values[nnz++] = 1;
446
447 bs->rows.push_back(CompressedRow());
448 CompressedRow& row = bs->rows.back();
449 row.block.size = 1;
450 row.block.position = 5;
451 row.cells.push_back(Cell(2, 10));
452 row.cells.push_back(Cell(3, 11));
453 row.cells.push_back(Cell(4, 12));
454 }
455
456 BlockSparseMatrix* A = new BlockSparseMatrix(bs);
457 memcpy(A->mutable_values(), values.get(), nnz * sizeof(*A->values()));
458
459 for (int i = 0; i < num_cols; ++i) {
460 problem->D.get()[i] = 1;
461 }
462
463 for (int i = 0; i < num_rows; ++i) {
464 problem->b.get()[i] = i;
465 }
466
467 problem->A.reset(A);
468
469 return problem;
470 }
471
472
473 /*
474 A = [1 0
475 3 0
476 0 5
477 0 7
478 0 9
479 0 0]
480
481 b = [0
482 1
483 2
484 3
485 4
486 5]
487 */
488 // BlockSparseMatrix version
LinearLeastSquaresProblem3()489 LinearLeastSquaresProblem* LinearLeastSquaresProblem3() {
490 int num_rows = 5;
491 int num_cols = 2;
492
493 LinearLeastSquaresProblem* problem = new LinearLeastSquaresProblem;
494
495 problem->b.reset(new double[num_rows]);
496 problem->D.reset(new double[num_cols]);
497 problem->num_eliminate_blocks = 2;
498
499 CompressedRowBlockStructure* bs = new CompressedRowBlockStructure;
500 scoped_array<double> values(new double[num_rows * num_cols]);
501
502 for (int c = 0; c < num_cols; ++c) {
503 bs->cols.push_back(Block());
504 bs->cols.back().size = 1;
505 bs->cols.back().position = c;
506 }
507
508 int nnz = 0;
509
510 // Row 1
511 {
512 values[nnz++] = 1;
513 bs->rows.push_back(CompressedRow());
514 CompressedRow& row = bs->rows.back();
515 row.block.size = 1;
516 row.block.position = 0;
517 row.cells.push_back(Cell(0, 0));
518 }
519
520 // Row 2
521 {
522 values[nnz++] = 3;
523 bs->rows.push_back(CompressedRow());
524 CompressedRow& row = bs->rows.back();
525 row.block.size = 1;
526 row.block.position = 1;
527 row.cells.push_back(Cell(0, 1));
528 }
529
530 // Row 3
531 {
532 values[nnz++] = 5;
533 bs->rows.push_back(CompressedRow());
534 CompressedRow& row = bs->rows.back();
535 row.block.size = 1;
536 row.block.position = 2;
537 row.cells.push_back(Cell(1, 2));
538 }
539
540 // Row 4
541 {
542 values[nnz++] = 7;
543 bs->rows.push_back(CompressedRow());
544 CompressedRow& row = bs->rows.back();
545 row.block.size = 1;
546 row.block.position = 3;
547 row.cells.push_back(Cell(1, 3));
548 }
549
550 // Row 5
551 {
552 values[nnz++] = 9;
553 bs->rows.push_back(CompressedRow());
554 CompressedRow& row = bs->rows.back();
555 row.block.size = 1;
556 row.block.position = 4;
557 row.cells.push_back(Cell(1, 4));
558 }
559
560 BlockSparseMatrix* A = new BlockSparseMatrix(bs);
561 memcpy(A->mutable_values(), values.get(), nnz * sizeof(*A->values()));
562
563 for (int i = 0; i < num_cols; ++i) {
564 problem->D.get()[i] = 1;
565 }
566
567 for (int i = 0; i < num_rows; ++i) {
568 problem->b.get()[i] = i;
569 }
570
571 problem->A.reset(A);
572
573 return problem;
574 }
575
DumpLinearLeastSquaresProblemToConsole(const string & directory,int iteration,const SparseMatrix * A,const double * D,const double * b,const double * x,int num_eliminate_blocks)576 bool DumpLinearLeastSquaresProblemToConsole(const string& directory,
577 int iteration,
578 const SparseMatrix* A,
579 const double* D,
580 const double* b,
581 const double* x,
582 int num_eliminate_blocks) {
583 CHECK_NOTNULL(A);
584 Matrix AA;
585 A->ToDenseMatrix(&AA);
586 LOG(INFO) << "A^T: \n" << AA.transpose();
587
588 if (D != NULL) {
589 LOG(INFO) << "A's appended diagonal:\n"
590 << ConstVectorRef(D, A->num_cols());
591 }
592
593 if (b != NULL) {
594 LOG(INFO) << "b: \n" << ConstVectorRef(b, A->num_rows());
595 }
596
597 if (x != NULL) {
598 LOG(INFO) << "x: \n" << ConstVectorRef(x, A->num_cols());
599 }
600 return true;
601 };
602
603 #ifndef CERES_NO_PROTOCOL_BUFFERS
DumpLinearLeastSquaresProblemToProtocolBuffer(const string & directory,int iteration,const SparseMatrix * A,const double * D,const double * b,const double * x,int num_eliminate_blocks)604 bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory,
605 int iteration,
606 const SparseMatrix* A,
607 const double* D,
608 const double* b,
609 const double* x,
610 int num_eliminate_blocks) {
611 CHECK_NOTNULL(A);
612 LinearLeastSquaresProblemProto lsqp;
613 A->ToProto(lsqp.mutable_a());
614
615 if (D != NULL) {
616 for (int i = 0; i < A->num_cols(); ++i) {
617 lsqp.add_d(D[i]);
618 }
619 }
620
621 if (b != NULL) {
622 for (int i = 0; i < A->num_rows(); ++i) {
623 lsqp.add_b(b[i]);
624 }
625 }
626
627 if (x != NULL) {
628 for (int i = 0; i < A->num_cols(); ++i) {
629 lsqp.add_x(x[i]);
630 }
631 }
632
633 lsqp.set_num_eliminate_blocks(num_eliminate_blocks);
634 string format_string = JoinPath(directory,
635 "lm_iteration_%03d.lsqp");
636 string filename =
637 StringPrintf(format_string.c_str(), iteration);
638 LOG(INFO) << "Dumping least squares problem for iteration " << iteration
639 << " to disk. File: " << filename;
640 WriteStringToFileOrDie(lsqp.SerializeAsString(), filename);
641 return true;
642 }
643 #else
DumpLinearLeastSquaresProblemToProtocolBuffer(const string & directory,int iteration,const SparseMatrix * A,const double * D,const double * b,const double * x,int num_eliminate_blocks)644 bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory,
645 int iteration,
646 const SparseMatrix* A,
647 const double* D,
648 const double* b,
649 const double* x,
650 int num_eliminate_blocks) {
651 LOG(ERROR) << "Dumping least squares problems is only "
652 << "supported when Ceres is compiled with "
653 << "protocol buffer support.";
654 return false;
655 }
656 #endif
657
WriteArrayToFileOrDie(const string & filename,const double * x,const int size)658 void WriteArrayToFileOrDie(const string& filename,
659 const double* x,
660 const int size) {
661 CHECK_NOTNULL(x);
662 VLOG(2) << "Writing array to: " << filename;
663 FILE* fptr = fopen(filename.c_str(), "w");
664 CHECK_NOTNULL(fptr);
665 for (int i = 0; i < size; ++i) {
666 fprintf(fptr, "%17f\n", x[i]);
667 }
668 fclose(fptr);
669 }
670
DumpLinearLeastSquaresProblemToTextFile(const string & directory,int iteration,const SparseMatrix * A,const double * D,const double * b,const double * x,int num_eliminate_blocks)671 bool DumpLinearLeastSquaresProblemToTextFile(const string& directory,
672 int iteration,
673 const SparseMatrix* A,
674 const double* D,
675 const double* b,
676 const double* x,
677 int num_eliminate_blocks) {
678 CHECK_NOTNULL(A);
679 string format_string = JoinPath(directory,
680 "lm_iteration_%03d");
681 string filename_prefix =
682 StringPrintf(format_string.c_str(), iteration);
683
684 LOG(INFO) << "writing to: " << filename_prefix << "*";
685
686 string matlab_script;
687 StringAppendF(&matlab_script,
688 "function lsqp = lm_iteration_%03d()\n", iteration);
689 StringAppendF(&matlab_script,
690 "lsqp.num_rows = %d;\n", A->num_rows());
691 StringAppendF(&matlab_script,
692 "lsqp.num_cols = %d;\n", A->num_cols());
693
694 {
695 string filename = filename_prefix + "_A.txt";
696 FILE* fptr = fopen(filename.c_str(), "w");
697 CHECK_NOTNULL(fptr);
698 A->ToTextFile(fptr);
699 fclose(fptr);
700 StringAppendF(&matlab_script,
701 "tmp = load('%s', '-ascii');\n", filename.c_str());
702 StringAppendF(
703 &matlab_script,
704 "lsqp.A = sparse(tmp(:, 1) + 1, tmp(:, 2) + 1, tmp(:, 3), %d, %d);\n",
705 A->num_rows(),
706 A->num_cols());
707 }
708
709
710 if (D != NULL) {
711 string filename = filename_prefix + "_D.txt";
712 WriteArrayToFileOrDie(filename, D, A->num_cols());
713 StringAppendF(&matlab_script,
714 "lsqp.D = load('%s', '-ascii');\n", filename.c_str());
715 }
716
717 if (b != NULL) {
718 string filename = filename_prefix + "_b.txt";
719 WriteArrayToFileOrDie(filename, b, A->num_rows());
720 StringAppendF(&matlab_script,
721 "lsqp.b = load('%s', '-ascii');\n", filename.c_str());
722 }
723
724 if (x != NULL) {
725 string filename = filename_prefix + "_x.txt";
726 WriteArrayToFileOrDie(filename, x, A->num_cols());
727 StringAppendF(&matlab_script,
728 "lsqp.x = load('%s', '-ascii');\n", filename.c_str());
729 }
730
731 string matlab_filename = filename_prefix + ".m";
732 WriteStringToFileOrDie(matlab_script, matlab_filename);
733 return true;
734 }
735
DumpLinearLeastSquaresProblem(const string & directory,int iteration,DumpFormatType dump_format_type,const SparseMatrix * A,const double * D,const double * b,const double * x,int num_eliminate_blocks)736 bool DumpLinearLeastSquaresProblem(const string& directory,
737 int iteration,
738 DumpFormatType dump_format_type,
739 const SparseMatrix* A,
740 const double* D,
741 const double* b,
742 const double* x,
743 int num_eliminate_blocks) {
744 switch (dump_format_type) {
745 case (CONSOLE):
746 return DumpLinearLeastSquaresProblemToConsole(directory,
747 iteration,
748 A, D, b, x,
749 num_eliminate_blocks);
750 case (PROTOBUF):
751 return DumpLinearLeastSquaresProblemToProtocolBuffer(
752 directory,
753 iteration,
754 A, D, b, x,
755 num_eliminate_blocks);
756 case (TEXTFILE):
757 return DumpLinearLeastSquaresProblemToTextFile(directory,
758 iteration,
759 A, D, b, x,
760 num_eliminate_blocks);
761 default:
762 LOG(FATAL) << "Unknown DumpFormatType " << dump_format_type;
763 };
764
765 return true;
766 }
767
768 } // namespace internal
769 } // namespace ceres
770