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/triplet_sparse_matrix.h"
     32 
     33 #include "gtest/gtest.h"
     34 #include "ceres/internal/scoped_ptr.h"
     35 
     36 namespace ceres {
     37 namespace internal {
     38 
     39 TEST(TripletSparseMatrix, DefaultConstructorReturnsEmptyObject) {
     40   TripletSparseMatrix m;
     41   EXPECT_EQ(m.num_rows(), 0);
     42   EXPECT_EQ(m.num_cols(), 0);
     43   EXPECT_EQ(m.num_nonzeros(), 0);
     44   EXPECT_EQ(m.max_num_nonzeros(), 0);
     45 }
     46 
     47 TEST(TripletSparseMatrix, SimpleConstructorAndBasicOperations) {
     48   // Build a matrix
     49   TripletSparseMatrix m(2, 5, 4);
     50   EXPECT_EQ(m.num_rows(), 2);
     51   EXPECT_EQ(m.num_cols(), 5);
     52   EXPECT_EQ(m.num_nonzeros(), 0);
     53   EXPECT_EQ(m.max_num_nonzeros(), 4);
     54 
     55   m.mutable_rows()[0] = 0;
     56   m.mutable_cols()[0] = 1;
     57   m.mutable_values()[0] = 2.5;
     58 
     59   m.mutable_rows()[1] = 1;
     60   m.mutable_cols()[1] = 4;
     61   m.mutable_values()[1] = 5.2;
     62   m.set_num_nonzeros(2);
     63 
     64   EXPECT_EQ(m.num_nonzeros(), 2);
     65 
     66   ASSERT_TRUE(m.AllTripletsWithinBounds());
     67 
     68   // We should never be able resize and lose data
     69   EXPECT_DEATH_IF_SUPPORTED(m.Reserve(1), "Reallocation will cause data loss");
     70 
     71   // We should be able to resize while preserving data
     72   m.Reserve(50);
     73   EXPECT_EQ(m.max_num_nonzeros(), 50);
     74 
     75   m.Reserve(3);
     76   EXPECT_EQ(m.max_num_nonzeros(), 50);  // The space is already reserved.
     77 
     78   EXPECT_EQ(m.rows()[0], 0);
     79   EXPECT_EQ(m.rows()[1], 1);
     80 
     81   EXPECT_EQ(m.cols()[0], 1);
     82   EXPECT_EQ(m.cols()[1], 4);
     83 
     84   EXPECT_DOUBLE_EQ(m.values()[0], 2.5);
     85   EXPECT_DOUBLE_EQ(m.values()[1], 5.2);
     86 
     87   // Bounds check should fail
     88   m.mutable_rows()[0] = 10;
     89   EXPECT_FALSE(m.AllTripletsWithinBounds());
     90 
     91   m.mutable_rows()[0] = 1;
     92   m.mutable_cols()[0] = 100;
     93   EXPECT_FALSE(m.AllTripletsWithinBounds());
     94 
     95   // Remove all data and then resize the data store
     96   m.SetZero();
     97   EXPECT_EQ(m.num_nonzeros(), 0);
     98   m.Reserve(1);
     99 }
    100 
    101 TEST(TripletSparseMatrix, CopyConstructor) {
    102   TripletSparseMatrix orig(2, 5, 4);
    103   orig.mutable_rows()[0] = 0;
    104   orig.mutable_cols()[0] = 1;
    105   orig.mutable_values()[0] = 2.5;
    106 
    107   orig.mutable_rows()[1] = 1;
    108   orig.mutable_cols()[1] = 4;
    109   orig.mutable_values()[1] = 5.2;
    110   orig.set_num_nonzeros(2);
    111 
    112   TripletSparseMatrix cpy(orig);
    113 
    114   EXPECT_EQ(cpy.num_rows(), 2);
    115   EXPECT_EQ(cpy.num_cols(), 5);
    116   ASSERT_EQ(cpy.num_nonzeros(), 2);
    117   EXPECT_EQ(cpy.max_num_nonzeros(), 4);
    118 
    119   EXPECT_EQ(cpy.rows()[0], 0);
    120   EXPECT_EQ(cpy.rows()[1], 1);
    121 
    122   EXPECT_EQ(cpy.cols()[0], 1);
    123   EXPECT_EQ(cpy.cols()[1], 4);
    124 
    125   EXPECT_DOUBLE_EQ(cpy.values()[0], 2.5);
    126   EXPECT_DOUBLE_EQ(cpy.values()[1], 5.2);
    127 }
    128 
    129 TEST(TripletSparseMatrix, AssignmentOperator) {
    130   TripletSparseMatrix orig(2, 5, 4);
    131   orig.mutable_rows()[0] = 0;
    132   orig.mutable_cols()[0] = 1;
    133   orig.mutable_values()[0] = 2.5;
    134 
    135   orig.mutable_rows()[1] = 1;
    136   orig.mutable_cols()[1] = 4;
    137   orig.mutable_values()[1] = 5.2;
    138   orig.set_num_nonzeros(2);
    139 
    140   TripletSparseMatrix cpy(3, 50, 40);
    141   cpy.mutable_rows()[0] = 0;
    142   cpy.mutable_cols()[0] = 10;
    143   cpy.mutable_values()[0] = 10.22;
    144 
    145   cpy.mutable_rows()[1] = 2;
    146   cpy.mutable_cols()[1] = 23;
    147   cpy.mutable_values()[1] = 34.45;
    148 
    149   cpy.mutable_rows()[0] = 0;
    150   cpy.mutable_cols()[0] = 10;
    151   cpy.mutable_values()[0] = 10.22;
    152 
    153   cpy.mutable_rows()[1] = 0;
    154   cpy.mutable_cols()[1] = 3;
    155   cpy.mutable_values()[1] = 4.4;
    156   cpy.set_num_nonzeros(3);
    157 
    158   cpy = orig;
    159 
    160   EXPECT_EQ(cpy.num_rows(), 2);
    161   EXPECT_EQ(cpy.num_cols(), 5);
    162   ASSERT_EQ(cpy.num_nonzeros(), 2);
    163   EXPECT_EQ(cpy.max_num_nonzeros(), 4);
    164 
    165   EXPECT_EQ(cpy.rows()[0], 0);
    166   EXPECT_EQ(cpy.rows()[1], 1);
    167 
    168   EXPECT_EQ(cpy.cols()[0], 1);
    169   EXPECT_EQ(cpy.cols()[1], 4);
    170 
    171   EXPECT_DOUBLE_EQ(cpy.values()[0], 2.5);
    172   EXPECT_DOUBLE_EQ(cpy.values()[1], 5.2);
    173 }
    174 
    175 TEST(TripletSparseMatrix, AppendRows) {
    176   // Build one matrix.
    177   TripletSparseMatrix m(2, 5, 4);
    178   m.mutable_rows()[0] = 0;
    179   m.mutable_cols()[0] = 1;
    180   m.mutable_values()[0] = 2.5;
    181 
    182   m.mutable_rows()[1] = 1;
    183   m.mutable_cols()[1] = 4;
    184   m.mutable_values()[1] = 5.2;
    185   m.set_num_nonzeros(2);
    186 
    187   // Build another matrix.
    188   TripletSparseMatrix a(10, 5, 4);
    189   a.mutable_rows()[0] = 0;
    190   a.mutable_cols()[0] = 1;
    191   a.mutable_values()[0] = 3.5;
    192 
    193   a.mutable_rows()[1] = 1;
    194   a.mutable_cols()[1] = 4;
    195   a.mutable_values()[1] = 6.2;
    196 
    197   a.mutable_rows()[2] = 9;
    198   a.mutable_cols()[2] = 5;
    199   a.mutable_values()[2] = 1;
    200   a.set_num_nonzeros(3);
    201 
    202   // Glue the second matrix to the bottom of the first.
    203   m.AppendRows(a);
    204 
    205   EXPECT_EQ(m.num_rows(), 12);
    206   EXPECT_EQ(m.num_cols(), 5);
    207   ASSERT_EQ(m.num_nonzeros(), 5);
    208 
    209   EXPECT_EQ(m.values()[0], 2.5);
    210   EXPECT_EQ(m.values()[1], 5.2);
    211   EXPECT_EQ(m.values()[2], 3.5);
    212   EXPECT_EQ(m.values()[3], 6.2);
    213   EXPECT_EQ(m.values()[4], 1);
    214 
    215   EXPECT_EQ(m.rows()[0], 0);
    216   EXPECT_EQ(m.rows()[1], 1);
    217   EXPECT_EQ(m.rows()[2], 2);
    218   EXPECT_EQ(m.rows()[3], 3);
    219   EXPECT_EQ(m.rows()[4], 11);
    220 
    221   EXPECT_EQ(m.cols()[0], 1);
    222   EXPECT_EQ(m.cols()[1], 4);
    223   EXPECT_EQ(m.cols()[2], 1);
    224   EXPECT_EQ(m.cols()[3], 4);
    225   EXPECT_EQ(m.cols()[4], 5);
    226 }
    227 
    228 TEST(TripletSparseMatrix, AppendCols) {
    229   // Build one matrix.
    230   TripletSparseMatrix m(2, 5, 4);
    231   m.mutable_rows()[0] = 0;
    232   m.mutable_cols()[0] = 1;
    233   m.mutable_values()[0] = 2.5;
    234 
    235   m.mutable_rows()[1] = 1;
    236   m.mutable_cols()[1] = 4;
    237   m.mutable_values()[1] = 5.2;
    238   m.set_num_nonzeros(2);
    239 
    240   // Build another matrix.
    241   TripletSparseMatrix a(2, 15, 4);
    242   a.mutable_rows()[0] = 0;
    243   a.mutable_cols()[0] = 1;
    244   a.mutable_values()[0] = 3.5;
    245 
    246   a.mutable_rows()[1] = 1;
    247   a.mutable_cols()[1] = 4;
    248   a.mutable_values()[1] = 6.2;
    249 
    250   a.mutable_rows()[2] = 0;
    251   a.mutable_cols()[2] = 10;
    252   a.mutable_values()[2] = 1;
    253   a.set_num_nonzeros(3);
    254 
    255   // Glue the second matrix to the left of the first.
    256   m.AppendCols(a);
    257 
    258   EXPECT_EQ(m.num_rows(), 2);
    259   EXPECT_EQ(m.num_cols(), 20);
    260   ASSERT_EQ(m.num_nonzeros(), 5);
    261 
    262   EXPECT_EQ(m.values()[0], 2.5);
    263   EXPECT_EQ(m.values()[1], 5.2);
    264   EXPECT_EQ(m.values()[2], 3.5);
    265   EXPECT_EQ(m.values()[3], 6.2);
    266   EXPECT_EQ(m.values()[4], 1);
    267 
    268   EXPECT_EQ(m.rows()[0], 0);
    269   EXPECT_EQ(m.rows()[1], 1);
    270   EXPECT_EQ(m.rows()[2], 0);
    271   EXPECT_EQ(m.rows()[3], 1);
    272   EXPECT_EQ(m.rows()[4], 0);
    273 
    274   EXPECT_EQ(m.cols()[0], 1);
    275   EXPECT_EQ(m.cols()[1], 4);
    276   EXPECT_EQ(m.cols()[2], 6);
    277   EXPECT_EQ(m.cols()[3], 9);
    278   EXPECT_EQ(m.cols()[4], 15);
    279 }
    280 
    281 TEST(TripletSparseMatrix, CreateDiagonalMatrix) {
    282   scoped_array<double> values(new double[10]);
    283   for (int i = 0; i < 10; ++i)
    284     values[i] = i;
    285 
    286   scoped_ptr<TripletSparseMatrix> m(
    287       TripletSparseMatrix::CreateSparseDiagonalMatrix(values.get(), 10));
    288   EXPECT_EQ(m->num_rows(), 10);
    289   EXPECT_EQ(m->num_cols(), 10);
    290   ASSERT_EQ(m->num_nonzeros(), 10);
    291   for (int i = 0; i < 10 ; ++i) {
    292     EXPECT_EQ(m->rows()[i], i);
    293     EXPECT_EQ(m->cols()[i], i);
    294     EXPECT_EQ(m->values()[i], i);
    295   }
    296 }
    297 
    298 TEST(TripletSparseMatrix, Resize) {
    299   TripletSparseMatrix m(10, 20, 200);
    300   int nnz = 0;
    301   for (int i = 0; i < 10; ++i) {
    302     for (int j = 0; j < 20; ++j) {
    303       m.mutable_rows()[nnz] = i;
    304       m.mutable_cols()[nnz] = j;
    305       m.mutable_values()[nnz++] = i+j;
    306     }
    307   }
    308   m.set_num_nonzeros(nnz);
    309   m.Resize(5, 6);
    310   EXPECT_EQ(m.num_rows(), 5);
    311   EXPECT_EQ(m.num_cols(), 6);
    312   ASSERT_EQ(m.num_nonzeros(), 30);
    313   for (int i = 0; i < 30; ++i) {
    314     EXPECT_EQ(m.values()[i], m.rows()[i] + m.cols()[i]);
    315   }
    316 }
    317 
    318 }  // namespace internal
    319 }  // namespace ceres
    320