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