Home | History | Annotate | Download | only in ceres
      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 (at) google.com (Sameer Agarwal)
     30 
     31 #include "ceres/compressed_row_sparse_matrix.h"
     32 
     33 #include <algorithm>
     34 #include <vector>
     35 #include "ceres/crs_matrix.h"
     36 #include "ceres/internal/port.h"
     37 #include "ceres/triplet_sparse_matrix.h"
     38 #include "glog/logging.h"
     39 
     40 namespace ceres {
     41 namespace internal {
     42 namespace {
     43 
     44 // Helper functor used by the constructor for reordering the contents
     45 // of a TripletSparseMatrix. This comparator assumes thay there are no
     46 // duplicates in the pair of arrays rows and cols, i.e., there is no
     47 // indices i and j (not equal to each other) s.t.
     48 //
     49 //  rows[i] == rows[j] && cols[i] == cols[j]
     50 //
     51 // If this is the case, this functor will not be a StrictWeakOrdering.
     52 struct RowColLessThan {
     53   RowColLessThan(const int* rows, const int* cols)
     54       : rows(rows), cols(cols) {
     55   }
     56 
     57   bool operator()(const int x, const int y) const {
     58     if (rows[x] == rows[y]) {
     59       return (cols[x] < cols[y]);
     60     }
     61     return (rows[x] < rows[y]);
     62   }
     63 
     64   const int* rows;
     65   const int* cols;
     66 };
     67 
     68 }  // namespace
     69 
     70 // This constructor gives you a semi-initialized CompressedRowSparseMatrix.
     71 CompressedRowSparseMatrix::CompressedRowSparseMatrix(int num_rows,
     72                                                      int num_cols,
     73                                                      int max_num_nonzeros) {
     74   num_rows_ = num_rows;
     75   num_cols_ = num_cols;
     76   rows_.resize(num_rows + 1, 0);
     77   cols_.resize(max_num_nonzeros, 0);
     78   values_.resize(max_num_nonzeros, 0.0);
     79 
     80 
     81   VLOG(1) << "# of rows: " << num_rows_
     82           << " # of columns: " << num_cols_
     83           << " max_num_nonzeros: " << cols_.size()
     84           << ". Allocating " << (num_rows_ + 1) * sizeof(int) +  // NOLINT
     85       cols_.size() * sizeof(int) +  // NOLINT
     86       cols_.size() * sizeof(double);  // NOLINT
     87 }
     88 
     89 CompressedRowSparseMatrix::CompressedRowSparseMatrix(
     90     const TripletSparseMatrix& m) {
     91   num_rows_ = m.num_rows();
     92   num_cols_ = m.num_cols();
     93 
     94   rows_.resize(num_rows_ + 1, 0);
     95   cols_.resize(m.num_nonzeros(), 0);
     96   values_.resize(m.max_num_nonzeros(), 0.0);
     97 
     98   // index is the list of indices into the TripletSparseMatrix m.
     99   vector<int> index(m.num_nonzeros(), 0);
    100   for (int i = 0; i < m.num_nonzeros(); ++i) {
    101     index[i] = i;
    102   }
    103 
    104   // Sort index such that the entries of m are ordered by row and ties
    105   // are broken by column.
    106   sort(index.begin(), index.end(), RowColLessThan(m.rows(), m.cols()));
    107 
    108   VLOG(1) << "# of rows: " << num_rows_
    109           << " # of columns: " << num_cols_
    110           << " max_num_nonzeros: " << cols_.size()
    111           << ". Allocating "
    112           << ((num_rows_ + 1) * sizeof(int) +  // NOLINT
    113               cols_.size() * sizeof(int) +     // NOLINT
    114               cols_.size() * sizeof(double));  // NOLINT
    115 
    116   // Copy the contents of the cols and values array in the order given
    117   // by index and count the number of entries in each row.
    118   for (int i = 0; i < m.num_nonzeros(); ++i) {
    119     const int idx = index[i];
    120     ++rows_[m.rows()[idx] + 1];
    121     cols_[i] = m.cols()[idx];
    122     values_[i] = m.values()[idx];
    123   }
    124 
    125   // Find the cumulative sum of the row counts.
    126   for (int i = 1; i < num_rows_ + 1; ++i) {
    127     rows_[i] += rows_[i-1];
    128   }
    129 
    130   CHECK_EQ(num_nonzeros(), m.num_nonzeros());
    131 }
    132 
    133 CompressedRowSparseMatrix::CompressedRowSparseMatrix(const double* diagonal,
    134                                                      int num_rows) {
    135   CHECK_NOTNULL(diagonal);
    136 
    137   num_rows_ = num_rows;
    138   num_cols_ = num_rows;
    139   rows_.resize(num_rows + 1);
    140   cols_.resize(num_rows);
    141   values_.resize(num_rows);
    142 
    143   rows_[0] = 0;
    144   for (int i = 0; i < num_rows_; ++i) {
    145     cols_[i] = i;
    146     values_[i] = diagonal[i];
    147     rows_[i + 1] = i + 1;
    148   }
    149 
    150   CHECK_EQ(num_nonzeros(), num_rows);
    151 }
    152 
    153 CompressedRowSparseMatrix::~CompressedRowSparseMatrix() {
    154 }
    155 
    156 void CompressedRowSparseMatrix::SetZero() {
    157   fill(values_.begin(), values_.end(), 0);
    158 }
    159 
    160 void CompressedRowSparseMatrix::RightMultiply(const double* x,
    161                                               double* y) const {
    162   CHECK_NOTNULL(x);
    163   CHECK_NOTNULL(y);
    164 
    165   for (int r = 0; r < num_rows_; ++r) {
    166     for (int idx = rows_[r]; idx < rows_[r + 1]; ++idx) {
    167       y[r] += values_[idx] * x[cols_[idx]];
    168     }
    169   }
    170 }
    171 
    172 void CompressedRowSparseMatrix::LeftMultiply(const double* x, double* y) const {
    173   CHECK_NOTNULL(x);
    174   CHECK_NOTNULL(y);
    175 
    176   for (int r = 0; r < num_rows_; ++r) {
    177     for (int idx = rows_[r]; idx < rows_[r + 1]; ++idx) {
    178       y[cols_[idx]] += values_[idx] * x[r];
    179     }
    180   }
    181 }
    182 
    183 void CompressedRowSparseMatrix::SquaredColumnNorm(double* x) const {
    184   CHECK_NOTNULL(x);
    185 
    186   fill(x, x + num_cols_, 0.0);
    187   for (int idx = 0; idx < rows_[num_rows_]; ++idx) {
    188     x[cols_[idx]] += values_[idx] * values_[idx];
    189   }
    190 }
    191 
    192 void CompressedRowSparseMatrix::ScaleColumns(const double* scale) {
    193   CHECK_NOTNULL(scale);
    194 
    195   for (int idx = 0; idx < rows_[num_rows_]; ++idx) {
    196     values_[idx] *= scale[cols_[idx]];
    197   }
    198 }
    199 
    200 void CompressedRowSparseMatrix::ToDenseMatrix(Matrix* dense_matrix) const {
    201   CHECK_NOTNULL(dense_matrix);
    202   dense_matrix->resize(num_rows_, num_cols_);
    203   dense_matrix->setZero();
    204 
    205   for (int r = 0; r < num_rows_; ++r) {
    206     for (int idx = rows_[r]; idx < rows_[r + 1]; ++idx) {
    207       (*dense_matrix)(r, cols_[idx]) = values_[idx];
    208     }
    209   }
    210 }
    211 
    212 void CompressedRowSparseMatrix::DeleteRows(int delta_rows) {
    213   CHECK_GE(delta_rows, 0);
    214   CHECK_LE(delta_rows, num_rows_);
    215 
    216   num_rows_ -= delta_rows;
    217   rows_.resize(num_rows_ + 1);
    218 }
    219 
    220 void CompressedRowSparseMatrix::AppendRows(const CompressedRowSparseMatrix& m) {
    221   CHECK_EQ(m.num_cols(), num_cols_);
    222 
    223   if (cols_.size() < num_nonzeros() + m.num_nonzeros()) {
    224     cols_.resize(num_nonzeros() + m.num_nonzeros());
    225     values_.resize(num_nonzeros() + m.num_nonzeros());
    226   }
    227 
    228   // Copy the contents of m into this matrix.
    229   copy(m.cols(), m.cols() + m.num_nonzeros(), &cols_[num_nonzeros()]);
    230   copy(m.values(), m.values() + m.num_nonzeros(), &values_[num_nonzeros()]);
    231   rows_.resize(num_rows_ + m.num_rows() + 1);
    232   // new_rows = [rows_, m.row() + rows_[num_rows_]]
    233   fill(rows_.begin() + num_rows_,
    234        rows_.begin() + num_rows_ + m.num_rows() + 1,
    235        rows_[num_rows_]);
    236 
    237   for (int r = 0; r < m.num_rows() + 1; ++r) {
    238     rows_[num_rows_ + r] += m.rows()[r];
    239   }
    240 
    241   num_rows_ += m.num_rows();
    242 }
    243 
    244 void CompressedRowSparseMatrix::ToTextFile(FILE* file) const {
    245   CHECK_NOTNULL(file);
    246   for (int r = 0; r < num_rows_; ++r) {
    247     for (int idx = rows_[r]; idx < rows_[r + 1]; ++idx) {
    248       fprintf(file,
    249               "% 10d % 10d %17f\n",
    250               r,
    251               cols_[idx],
    252               values_[idx]);
    253     }
    254   }
    255 }
    256 
    257 void CompressedRowSparseMatrix::ToCRSMatrix(CRSMatrix* matrix) const {
    258   matrix->num_rows = num_rows_;
    259   matrix->num_cols = num_cols_;
    260   matrix->rows = rows_;
    261   matrix->cols = cols_;
    262   matrix->values = values_;
    263 
    264   // Trim.
    265   matrix->rows.resize(matrix->num_rows + 1);
    266   matrix->cols.resize(matrix->rows[matrix->num_rows]);
    267   matrix->values.resize(matrix->rows[matrix->num_rows]);
    268 }
    269 
    270 void CompressedRowSparseMatrix::SolveLowerTriangularInPlace(
    271     double* solution) const {
    272   for (int r = 0; r < num_rows_; ++r) {
    273     for (int idx = rows_[r]; idx < rows_[r + 1] - 1; ++idx) {
    274       solution[r] -= values_[idx] * solution[cols_[idx]];
    275     }
    276     solution[r] /=  values_[rows_[r + 1] - 1];
    277   }
    278 }
    279 
    280 void CompressedRowSparseMatrix::SolveLowerTriangularTransposeInPlace(
    281     double* solution) const {
    282   for (int r = num_rows_ - 1; r >= 0; --r) {
    283     solution[r] /= values_[rows_[r + 1] - 1];
    284     for (int idx = rows_[r + 1] - 2; idx >= rows_[r]; --idx) {
    285       solution[cols_[idx]] -= values_[idx] * solution[r];
    286     }
    287   }
    288 }
    289 
    290 CompressedRowSparseMatrix* CompressedRowSparseMatrix::CreateBlockDiagonalMatrix(
    291     const double* diagonal,
    292     const vector<int>& blocks) {
    293   int num_rows = 0;
    294   int num_nonzeros = 0;
    295   for (int i = 0; i < blocks.size(); ++i) {
    296     num_rows += blocks[i];
    297     num_nonzeros += blocks[i] * blocks[i];
    298   }
    299 
    300   CompressedRowSparseMatrix* matrix =
    301       new CompressedRowSparseMatrix(num_rows, num_rows, num_nonzeros);
    302 
    303   int* rows = matrix->mutable_rows();
    304   int* cols = matrix->mutable_cols();
    305   double* values = matrix->mutable_values();
    306   fill(values, values + num_nonzeros, 0.0);
    307 
    308   int idx_cursor = 0;
    309   int col_cursor = 0;
    310   for (int i = 0; i < blocks.size(); ++i) {
    311     const int block_size = blocks[i];
    312     for (int r = 0; r < block_size; ++r) {
    313       *(rows++) = idx_cursor;
    314       values[idx_cursor + r] = diagonal[col_cursor + r];
    315       for (int c = 0; c < block_size; ++c, ++idx_cursor) {
    316         *(cols++) = col_cursor + c;
    317       }
    318     }
    319     col_cursor += block_size;
    320   }
    321   *rows = idx_cursor;
    322 
    323   *matrix->mutable_row_blocks() = blocks;
    324   *matrix->mutable_col_blocks() = blocks;
    325 
    326   CHECK_EQ(idx_cursor, num_nonzeros);
    327   CHECK_EQ(col_cursor, num_rows);
    328   return matrix;
    329 }
    330 
    331 CompressedRowSparseMatrix* CompressedRowSparseMatrix::Transpose() const {
    332   CompressedRowSparseMatrix* transpose =
    333       new CompressedRowSparseMatrix(num_cols_, num_rows_, num_nonzeros());
    334 
    335   int* transpose_rows = transpose->mutable_rows();
    336   int* transpose_cols = transpose->mutable_cols();
    337   double* transpose_values = transpose->mutable_values();
    338 
    339   for (int idx = 0; idx < num_nonzeros(); ++idx) {
    340     ++transpose_rows[cols_[idx] + 1];
    341   }
    342 
    343   for (int i = 1; i < transpose->num_rows() + 1; ++i) {
    344     transpose_rows[i] += transpose_rows[i - 1];
    345   }
    346 
    347   for (int r = 0; r < num_rows(); ++r) {
    348     for (int idx = rows_[r]; idx < rows_[r + 1]; ++idx) {
    349       const int c = cols_[idx];
    350       const int transpose_idx = transpose_rows[c]++;
    351       transpose_cols[transpose_idx] = r;
    352       transpose_values[transpose_idx] = values_[idx];
    353     }
    354   }
    355 
    356   for (int i = transpose->num_rows() - 1; i > 0 ; --i) {
    357     transpose_rows[i] = transpose_rows[i - 1];
    358   }
    359   transpose_rows[0] = 0;
    360 
    361   return transpose;
    362 }
    363 
    364 
    365 }  // namespace internal
    366 }  // namespace ceres
    367