1 // Ceres Solver - A fast non-linear least squares minimizer
2 // Copyright 2015 Google Inc. All rights reserved.
3 // http://ceres-solver.org/
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
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.
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.
29 // Author: sameeragarwal@google.com (Sameer Agarwal)
31 #include "ceres/linear_least_squares_problems.h"
36 #include "ceres/block_sparse_matrix.h"
37 #include "ceres/block_structure.h"
38 #include "ceres/casts.h"
39 #include "ceres/file.h"
40 #include "ceres/internal/scoped_ptr.h"
41 #include "ceres/stringprintf.h"
42 #include "ceres/triplet_sparse_matrix.h"
43 #include "ceres/types.h"
44 #include "glog/logging.h"
51 LinearLeastSquaresProblem* CreateLinearLeastSquaresProblemFromId(int id) {
54 return LinearLeastSquaresProblem0();
56 return LinearLeastSquaresProblem1();
58 return LinearLeastSquaresProblem2();
60 return LinearLeastSquaresProblem3();
62 return LinearLeastSquaresProblem4();
64 LOG(FATAL) << "Unknown problem id requested " << id;
87 LinearLeastSquaresProblem* LinearLeastSquaresProblem0() {
88 LinearLeastSquaresProblem* problem = new LinearLeastSquaresProblem;
90 TripletSparseMatrix* A = new TripletSparseMatrix(3, 2, 6);
91 problem->b.reset(new double[3]);
92 problem->D.reset(new double[2]);
94 problem->x.reset(new double[2]);
95 problem->x_D.reset(new double[2]);
97 int* Ai = A->mutable_rows();
98 int* Aj = A->mutable_cols();
99 double* Ax = A->mutable_values();
102 for (int i = 0; i < 3; ++i) {
103 for (int j = 0; j< 2; ++j) {
116 A->set_num_nonzeros(6);
129 problem->x_D[0] = 1.78448275;
130 problem->x_D[1] = 2.82327586;
162 S = [ 42.3419 -1.4000 -11.5806
163 -1.4000 2.6000 1.0000
164 11.5806 1.0000 31.1935]
180 // The following two functions create a TripletSparseMatrix and a
181 // BlockSparseMatrix version of this problem.
183 // TripletSparseMatrix version.
184 LinearLeastSquaresProblem* LinearLeastSquaresProblem1() {
188 LinearLeastSquaresProblem* problem = new LinearLeastSquaresProblem;
189 TripletSparseMatrix* A = new TripletSparseMatrix(num_rows,
191 num_rows * num_cols);
192 problem->b.reset(new double[num_rows]);
193 problem->D.reset(new double[num_cols]);
194 problem->num_eliminate_blocks = 2;
196 int* rows = A->mutable_rows();
197 int* cols = A->mutable_cols();
198 double* values = A->mutable_values();
272 A->set_num_nonzeros(nnz);
277 for (int i = 0; i < num_cols; ++i) {
278 problem->D.get()[i] = 1;
281 for (int i = 0; i < num_rows; ++i) {
282 problem->b.get()[i] = i;
288 // BlockSparseMatrix version
289 LinearLeastSquaresProblem* LinearLeastSquaresProblem2() {
293 LinearLeastSquaresProblem* problem = new LinearLeastSquaresProblem;
295 problem->b.reset(new double[num_rows]);
296 problem->D.reset(new double[num_cols]);
297 problem->num_eliminate_blocks = 2;
299 CompressedRowBlockStructure* bs = new CompressedRowBlockStructure;
300 scoped_array<double> values(new double[num_rows * num_cols]);
302 for (int c = 0; c < num_cols; ++c) {
303 bs->cols.push_back(Block());
304 bs->cols.back().size = 1;
305 bs->cols.back().position = c;
315 bs->rows.push_back(CompressedRow());
316 CompressedRow& row = bs->rows.back();
318 row.block.position = 0;
319 row.cells.push_back(Cell(0, 0));
320 row.cells.push_back(Cell(2, 1));
328 bs->rows.push_back(CompressedRow());
329 CompressedRow& row = bs->rows.back();
331 row.block.position = 1;
332 row.cells.push_back(Cell(0, 2));
333 row.cells.push_back(Cell(3, 3));
341 bs->rows.push_back(CompressedRow());
342 CompressedRow& row = bs->rows.back();
344 row.block.position = 2;
345 row.cells.push_back(Cell(1, 4));
346 row.cells.push_back(Cell(4, 5));
354 bs->rows.push_back(CompressedRow());
355 CompressedRow& row = bs->rows.back();
357 row.block.position = 3;
358 row.cells.push_back(Cell(1, 6));
359 row.cells.push_back(Cell(2, 7));
367 bs->rows.push_back(CompressedRow());
368 CompressedRow& row = bs->rows.back();
370 row.block.position = 4;
371 row.cells.push_back(Cell(1, 8));
372 row.cells.push_back(Cell(2, 9));
381 bs->rows.push_back(CompressedRow());
382 CompressedRow& row = bs->rows.back();
384 row.block.position = 5;
385 row.cells.push_back(Cell(2, 10));
386 row.cells.push_back(Cell(3, 11));
387 row.cells.push_back(Cell(4, 12));
390 BlockSparseMatrix* A = new BlockSparseMatrix(bs);
391 memcpy(A->mutable_values(), values.get(), nnz * sizeof(*A->values()));
393 for (int i = 0; i < num_cols; ++i) {
394 problem->D.get()[i] = 1;
397 for (int i = 0; i < num_rows; ++i) {
398 problem->b.get()[i] = i;
422 // BlockSparseMatrix version
423 LinearLeastSquaresProblem* LinearLeastSquaresProblem3() {
427 LinearLeastSquaresProblem* problem = new LinearLeastSquaresProblem;
429 problem->b.reset(new double[num_rows]);
430 problem->D.reset(new double[num_cols]);
431 problem->num_eliminate_blocks = 2;
433 CompressedRowBlockStructure* bs = new CompressedRowBlockStructure;
434 scoped_array<double> values(new double[num_rows * num_cols]);
436 for (int c = 0; c < num_cols; ++c) {
437 bs->cols.push_back(Block());
438 bs->cols.back().size = 1;
439 bs->cols.back().position = c;
447 bs->rows.push_back(CompressedRow());
448 CompressedRow& row = bs->rows.back();
450 row.block.position = 0;
451 row.cells.push_back(Cell(0, 0));
457 bs->rows.push_back(CompressedRow());
458 CompressedRow& row = bs->rows.back();
460 row.block.position = 1;
461 row.cells.push_back(Cell(0, 1));
467 bs->rows.push_back(CompressedRow());
468 CompressedRow& row = bs->rows.back();
470 row.block.position = 2;
471 row.cells.push_back(Cell(1, 2));
477 bs->rows.push_back(CompressedRow());
478 CompressedRow& row = bs->rows.back();
480 row.block.position = 3;
481 row.cells.push_back(Cell(1, 3));
487 bs->rows.push_back(CompressedRow());
488 CompressedRow& row = bs->rows.back();
490 row.block.position = 4;
491 row.cells.push_back(Cell(1, 4));
494 BlockSparseMatrix* A = new BlockSparseMatrix(bs);
495 memcpy(A->mutable_values(), values.get(), nnz * sizeof(*A->values()));
497 for (int i = 0; i < num_cols; ++i) {
498 problem->D.get()[i] = 1;
501 for (int i = 0; i < num_rows; ++i) {
502 problem->b.get()[i] = i;
519 // BlockSparseMatrix version
521 // This problem has the unique property that it has two different
522 // sized f-blocks, but only one of them occurs in the rows involving
523 // the one e-block. So performing Schur elimination on this problem
524 // tests the Schur Eliminator's ability to handle non-e-block rows
525 // correctly when their structure does not conform to the static
526 // structure determined by DetectStructure.
528 // NOTE: This problem is too small and rank deficient to be solved without
529 // the diagonal regularization.
530 LinearLeastSquaresProblem* LinearLeastSquaresProblem4() {
534 LinearLeastSquaresProblem* problem = new LinearLeastSquaresProblem;
536 problem->b.reset(new double[num_rows]);
537 problem->D.reset(new double[num_cols]);
538 problem->num_eliminate_blocks = 1;
540 CompressedRowBlockStructure* bs = new CompressedRowBlockStructure;
541 scoped_array<double> values(new double[num_rows * num_cols]);
543 // Column block structure
544 bs->cols.push_back(Block());
545 bs->cols.back().size = 2;
546 bs->cols.back().position = 0;
548 bs->cols.push_back(Block());
549 bs->cols.back().size = 3;
550 bs->cols.back().position = 2;
552 bs->cols.push_back(Block());
553 bs->cols.back().size = 2;
554 bs->cols.back().position = 5;
560 bs->rows.push_back(CompressedRow());
561 CompressedRow& row = bs->rows.back();
563 row.block.position = 0;
565 row.cells.push_back(Cell(0, nnz));
571 row.cells.push_back(Cell(2, nnz));
580 bs->rows.push_back(CompressedRow());
581 CompressedRow& row = bs->rows.back();
583 row.block.position = 2;
585 row.cells.push_back(Cell(1, nnz));
590 row.cells.push_back(Cell(2, nnz));
595 BlockSparseMatrix* A = new BlockSparseMatrix(bs);
596 memcpy(A->mutable_values(), values.get(), nnz * sizeof(*A->values()));
598 for (int i = 0; i < num_cols; ++i) {
599 problem->D.get()[i] = (i + 1) * 100;
602 for (int i = 0; i < num_rows; ++i) {
603 problem->b.get()[i] = i;
611 bool DumpLinearLeastSquaresProblemToConsole(const SparseMatrix* A,
615 int num_eliminate_blocks) {
618 A->ToDenseMatrix(&AA);
619 LOG(INFO) << "A^T: \n" << AA.transpose();
622 LOG(INFO) << "A's appended diagonal:\n"
623 << ConstVectorRef(D, A->num_cols());
627 LOG(INFO) << "b: \n" << ConstVectorRef(b, A->num_rows());
631 LOG(INFO) << "x: \n" << ConstVectorRef(x, A->num_cols());
636 void WriteArrayToFileOrDie(const string& filename,
640 VLOG(2) << "Writing array to: " << filename;
641 FILE* fptr = fopen(filename.c_str(), "w");
643 for (int i = 0; i < size; ++i) {
644 fprintf(fptr, "%17f\n", x[i]);
649 bool DumpLinearLeastSquaresProblemToTextFile(const string& filename_base,
650 const SparseMatrix* A,
654 int num_eliminate_blocks) {
656 LOG(INFO) << "writing to: " << filename_base << "*";
658 string matlab_script;
659 StringAppendF(&matlab_script,
660 "function lsqp = load_trust_region_problem()\n");
661 StringAppendF(&matlab_script,
662 "lsqp.num_rows = %d;\n", A->num_rows());
663 StringAppendF(&matlab_script,
664 "lsqp.num_cols = %d;\n", A->num_cols());
667 string filename = filename_base + "_A.txt";
668 FILE* fptr = fopen(filename.c_str(), "w");
672 StringAppendF(&matlab_script,
673 "tmp = load('%s', '-ascii');\n", filename.c_str());
676 "lsqp.A = sparse(tmp(:, 1) + 1, tmp(:, 2) + 1, tmp(:, 3), %d, %d);\n",
683 string filename = filename_base + "_D.txt";
684 WriteArrayToFileOrDie(filename, D, A->num_cols());
685 StringAppendF(&matlab_script,
686 "lsqp.D = load('%s', '-ascii');\n", filename.c_str());
690 string filename = filename_base + "_b.txt";
691 WriteArrayToFileOrDie(filename, b, A->num_rows());
692 StringAppendF(&matlab_script,
693 "lsqp.b = load('%s', '-ascii');\n", filename.c_str());
697 string filename = filename_base + "_x.txt";
698 WriteArrayToFileOrDie(filename, x, A->num_cols());
699 StringAppendF(&matlab_script,
700 "lsqp.x = load('%s', '-ascii');\n", filename.c_str());
703 string matlab_filename = filename_base + ".m";
704 WriteStringToFileOrDie(matlab_script, matlab_filename);
709 bool DumpLinearLeastSquaresProblem(const string& filename_base,
710 DumpFormatType dump_format_type,
711 const SparseMatrix* A,
715 int num_eliminate_blocks) {
716 switch (dump_format_type) {
718 return DumpLinearLeastSquaresProblemToConsole(A, D, b, x,
719 num_eliminate_blocks);
721 return DumpLinearLeastSquaresProblemToTextFile(filename_base,
723 num_eliminate_blocks);
725 LOG(FATAL) << "Unknown DumpFormatType " << dump_format_type;
731 } // namespace internal