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