blob: b41d9918092bb915831def288222eef78f0676c5 [file] [log] [blame]
Keir Mierle8ebb0732012-04-30 23:09:08 -07001// Ceres Solver - A fast non-linear least squares minimizer
Keir Mierle7492b0d2015-03-17 22:30:16 -07002// Copyright 2015 Google Inc. All rights reserved.
3// http://ceres-solver.org/
Keir Mierle8ebb0732012-04-30 23:09:08 -07004//
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
Keir Mierle7c4e8a42018-03-30 16:16:59 -070033#include <memory>
Nikolaus Demmel7b8f6752020-09-20 21:45:24 +020034
Sameer Agarwal04899642022-08-10 09:55:43 -070035#include "ceres/crs_matrix.h"
Keir Mierle8ebb0732012-04-30 23:09:08 -070036#include "gtest/gtest.h"
Keir Mierle8ebb0732012-04-30 23:09:08 -070037
Sameer Agarwalcaf614a2022-04-21 17:41:10 -070038namespace ceres::internal {
Keir Mierle8ebb0732012-04-30 23:09:08 -070039
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
Sameer Agarwalc0149972012-09-18 13:55:18 -070070 EXPECT_DEATH_IF_SUPPORTED(m.Reserve(1), "Reallocation will cause data loss");
Keir Mierle8ebb0732012-04-30 23:09:08 -070071
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
102TEST(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
130TEST(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
ngoclinhngf8e5fba2018-09-28 23:56:57 +0700176TEST(TripletSparseMatrix, AssignmentOperatorSelfAssignment) {
177 TripletSparseMatrix orig(2, 5, 4);
178 orig.mutable_rows()[0] = 0;
179 orig.mutable_cols()[0] = 1;
180 orig.mutable_values()[0] = 2.5;
181
182 orig.mutable_rows()[1] = 1;
183 orig.mutable_cols()[1] = 4;
184 orig.mutable_values()[1] = 5.2;
185 orig.set_num_nonzeros(2);
186
187 // Who's on earth gonna do this?
188 orig = orig;
189
190 EXPECT_EQ(orig.num_rows(), 2);
191 EXPECT_EQ(orig.num_cols(), 5);
192 ASSERT_EQ(orig.num_nonzeros(), 2);
193 EXPECT_EQ(orig.max_num_nonzeros(), 4);
194
195 EXPECT_EQ(orig.rows()[0], 0);
196 EXPECT_EQ(orig.rows()[1], 1);
197
198 EXPECT_EQ(orig.cols()[0], 1);
199 EXPECT_EQ(orig.cols()[1], 4);
200
201 EXPECT_DOUBLE_EQ(orig.values()[0], 2.5);
202 EXPECT_DOUBLE_EQ(orig.values()[1], 5.2);
203}
204
Keir Mierle8ebb0732012-04-30 23:09:08 -0700205TEST(TripletSparseMatrix, AppendRows) {
206 // Build one matrix.
207 TripletSparseMatrix m(2, 5, 4);
208 m.mutable_rows()[0] = 0;
209 m.mutable_cols()[0] = 1;
210 m.mutable_values()[0] = 2.5;
211
212 m.mutable_rows()[1] = 1;
213 m.mutable_cols()[1] = 4;
214 m.mutable_values()[1] = 5.2;
215 m.set_num_nonzeros(2);
216
217 // Build another matrix.
218 TripletSparseMatrix a(10, 5, 4);
219 a.mutable_rows()[0] = 0;
220 a.mutable_cols()[0] = 1;
221 a.mutable_values()[0] = 3.5;
222
223 a.mutable_rows()[1] = 1;
224 a.mutable_cols()[1] = 4;
225 a.mutable_values()[1] = 6.2;
226
227 a.mutable_rows()[2] = 9;
228 a.mutable_cols()[2] = 5;
229 a.mutable_values()[2] = 1;
230 a.set_num_nonzeros(3);
231
232 // Glue the second matrix to the bottom of the first.
233 m.AppendRows(a);
234
235 EXPECT_EQ(m.num_rows(), 12);
236 EXPECT_EQ(m.num_cols(), 5);
237 ASSERT_EQ(m.num_nonzeros(), 5);
238
239 EXPECT_EQ(m.values()[0], 2.5);
240 EXPECT_EQ(m.values()[1], 5.2);
241 EXPECT_EQ(m.values()[2], 3.5);
242 EXPECT_EQ(m.values()[3], 6.2);
243 EXPECT_EQ(m.values()[4], 1);
244
245 EXPECT_EQ(m.rows()[0], 0);
246 EXPECT_EQ(m.rows()[1], 1);
247 EXPECT_EQ(m.rows()[2], 2);
248 EXPECT_EQ(m.rows()[3], 3);
249 EXPECT_EQ(m.rows()[4], 11);
250
251 EXPECT_EQ(m.cols()[0], 1);
252 EXPECT_EQ(m.cols()[1], 4);
253 EXPECT_EQ(m.cols()[2], 1);
254 EXPECT_EQ(m.cols()[3], 4);
255 EXPECT_EQ(m.cols()[4], 5);
256}
257
258TEST(TripletSparseMatrix, AppendCols) {
259 // Build one matrix.
260 TripletSparseMatrix m(2, 5, 4);
261 m.mutable_rows()[0] = 0;
262 m.mutable_cols()[0] = 1;
263 m.mutable_values()[0] = 2.5;
264
265 m.mutable_rows()[1] = 1;
266 m.mutable_cols()[1] = 4;
267 m.mutable_values()[1] = 5.2;
268 m.set_num_nonzeros(2);
269
270 // Build another matrix.
271 TripletSparseMatrix a(2, 15, 4);
272 a.mutable_rows()[0] = 0;
273 a.mutable_cols()[0] = 1;
274 a.mutable_values()[0] = 3.5;
275
276 a.mutable_rows()[1] = 1;
277 a.mutable_cols()[1] = 4;
278 a.mutable_values()[1] = 6.2;
279
280 a.mutable_rows()[2] = 0;
281 a.mutable_cols()[2] = 10;
282 a.mutable_values()[2] = 1;
283 a.set_num_nonzeros(3);
284
285 // Glue the second matrix to the left of the first.
286 m.AppendCols(a);
287
288 EXPECT_EQ(m.num_rows(), 2);
289 EXPECT_EQ(m.num_cols(), 20);
290 ASSERT_EQ(m.num_nonzeros(), 5);
291
292 EXPECT_EQ(m.values()[0], 2.5);
293 EXPECT_EQ(m.values()[1], 5.2);
294 EXPECT_EQ(m.values()[2], 3.5);
295 EXPECT_EQ(m.values()[3], 6.2);
296 EXPECT_EQ(m.values()[4], 1);
297
298 EXPECT_EQ(m.rows()[0], 0);
299 EXPECT_EQ(m.rows()[1], 1);
300 EXPECT_EQ(m.rows()[2], 0);
301 EXPECT_EQ(m.rows()[3], 1);
302 EXPECT_EQ(m.rows()[4], 0);
303
304 EXPECT_EQ(m.cols()[0], 1);
305 EXPECT_EQ(m.cols()[1], 4);
306 EXPECT_EQ(m.cols()[2], 6);
307 EXPECT_EQ(m.cols()[3], 9);
308 EXPECT_EQ(m.cols()[4], 15);
309}
310
311TEST(TripletSparseMatrix, CreateDiagonalMatrix) {
Keir Mierle7c4e8a42018-03-30 16:16:59 -0700312 std::unique_ptr<double[]> values(new double[10]);
Nikolaus Demmel7b8f6752020-09-20 21:45:24 +0200313 for (int i = 0; i < 10; ++i) values[i] = i;
Keir Mierle8ebb0732012-04-30 23:09:08 -0700314
Keir Mierle7c4e8a42018-03-30 16:16:59 -0700315 std::unique_ptr<TripletSparseMatrix> m(
Keir Mierle8ebb0732012-04-30 23:09:08 -0700316 TripletSparseMatrix::CreateSparseDiagonalMatrix(values.get(), 10));
317 EXPECT_EQ(m->num_rows(), 10);
318 EXPECT_EQ(m->num_cols(), 10);
319 ASSERT_EQ(m->num_nonzeros(), 10);
Nikolaus Demmel7b8f6752020-09-20 21:45:24 +0200320 for (int i = 0; i < 10; ++i) {
Keir Mierle8ebb0732012-04-30 23:09:08 -0700321 EXPECT_EQ(m->rows()[i], i);
322 EXPECT_EQ(m->cols()[i], i);
323 EXPECT_EQ(m->values()[i], i);
324 }
325}
326
327TEST(TripletSparseMatrix, Resize) {
328 TripletSparseMatrix m(10, 20, 200);
329 int nnz = 0;
330 for (int i = 0; i < 10; ++i) {
331 for (int j = 0; j < 20; ++j) {
332 m.mutable_rows()[nnz] = i;
333 m.mutable_cols()[nnz] = j;
Nikolaus Demmel7b8f6752020-09-20 21:45:24 +0200334 m.mutable_values()[nnz++] = i + j;
Keir Mierle8ebb0732012-04-30 23:09:08 -0700335 }
336 }
337 m.set_num_nonzeros(nnz);
338 m.Resize(5, 6);
339 EXPECT_EQ(m.num_rows(), 5);
340 EXPECT_EQ(m.num_cols(), 6);
341 ASSERT_EQ(m.num_nonzeros(), 30);
342 for (int i = 0; i < 30; ++i) {
343 EXPECT_EQ(m.values()[i], m.rows()[i] + m.cols()[i]);
344 }
345}
346
Joydeep Biswasc9d2ec82022-08-05 13:53:42 -0500347TEST(TripletSparseMatrix, ToCRSMatrix) {
348 // Test matrix:
349 // [1, 2, 0, 5, 6, 0,
350 // 3, 4, 0, 7, 8, 0,
351 // 0, 0, 9, 0, 0, 0]
352 TripletSparseMatrix m(3,
353 6,
354 {0, 0, 0, 0, 1, 1, 1, 1, 2},
355 {0, 1, 3, 4, 0, 1, 3, 4, 2},
356 {1, 2, 3, 4, 5, 6, 7, 8, 9});
357 CRSMatrix m_crs;
358 m.ToCRSMatrix(&m_crs);
359 EXPECT_EQ(m_crs.num_rows, 3);
360 EXPECT_EQ(m_crs.num_cols, 6);
361
362 EXPECT_EQ(m_crs.rows.size(), 4);
363 EXPECT_EQ(m_crs.rows[0], 0);
364 EXPECT_EQ(m_crs.rows[1], 4);
365 EXPECT_EQ(m_crs.rows[2], 8);
366 EXPECT_EQ(m_crs.rows[3], 9);
367
368 EXPECT_EQ(m_crs.cols.size(), 9);
369 EXPECT_EQ(m_crs.cols[0], 0);
370 EXPECT_EQ(m_crs.cols[1], 1);
371 EXPECT_EQ(m_crs.cols[2], 3);
372 EXPECT_EQ(m_crs.cols[3], 4);
373 EXPECT_EQ(m_crs.cols[4], 0);
374 EXPECT_EQ(m_crs.cols[5], 1);
375 EXPECT_EQ(m_crs.cols[6], 3);
376 EXPECT_EQ(m_crs.cols[7], 4);
377 EXPECT_EQ(m_crs.cols[8], 2);
378
379 EXPECT_EQ(m_crs.values.size(), 9);
380 for (int i = 0; i < 9; ++i) {
381 EXPECT_EQ(m_crs.values[i], i + 1);
382 }
383}
384
Sameer Agarwalcaf614a2022-04-21 17:41:10 -0700385} // namespace ceres::internal