Imported Upstream version ceres 1.13.0
[platform/upstream/ceres-solver.git] / internal / ceres / small_blas_test.cc
1 // Ceres Solver - A fast non-linear least squares minimizer
2 // Copyright 2015 Google Inc. All rights reserved.
3 // http://ceres-solver.org/
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: keir@google.com (Keir Mierle)
30
31 #include "ceres/small_blas.h"
32
33 #include <limits>
34 #include "gtest/gtest.h"
35 #include "ceres/internal/eigen.h"
36
37 namespace ceres {
38 namespace internal {
39
40 const double kTolerance = 3.0 * std::numeric_limits<double>::epsilon();
41
42 TEST(BLAS, MatrixMatrixMultiply) {
43   const int kRowA = 3;
44   const int kColA = 5;
45   Matrix A(kRowA, kColA);
46   A.setOnes();
47
48   const int kRowB = 5;
49   const int kColB = 7;
50   Matrix B(kRowB, kColB);
51   B.setOnes();
52
53   for (int row_stride_c = kRowA; row_stride_c < 3 * kRowA; ++row_stride_c) {
54     for (int col_stride_c = kColB; col_stride_c < 3 * kColB; ++col_stride_c) {
55       Matrix C(row_stride_c, col_stride_c);
56       C.setOnes();
57
58       Matrix C_plus = C;
59       Matrix C_minus = C;
60       Matrix C_assign = C;
61
62       Matrix C_plus_ref = C;
63       Matrix C_minus_ref = C;
64       Matrix C_assign_ref = C;
65       for (int start_row_c = 0; start_row_c + kRowA < row_stride_c; ++start_row_c) {
66         for (int start_col_c = 0; start_col_c + kColB < col_stride_c; ++start_col_c) {
67           C_plus_ref.block(start_row_c, start_col_c, kRowA, kColB) +=
68               A * B;
69
70           MatrixMatrixMultiply<kRowA, kColA, kRowB, kColB, 1>(
71               A.data(), kRowA, kColA,
72               B.data(), kRowB, kColB,
73               C_plus.data(), start_row_c, start_col_c, row_stride_c, col_stride_c);
74
75           EXPECT_NEAR((C_plus_ref - C_plus).norm(), 0.0, kTolerance)
76               << "C += A * B \n"
77               << "row_stride_c : " << row_stride_c << "\n"
78               << "col_stride_c : " << col_stride_c << "\n"
79               << "start_row_c  : " << start_row_c << "\n"
80               << "start_col_c  : " << start_col_c << "\n"
81               << "Cref : \n" << C_plus_ref << "\n"
82               << "C: \n" << C_plus;
83
84
85           C_minus_ref.block(start_row_c, start_col_c, kRowA, kColB) -=
86               A * B;
87
88           MatrixMatrixMultiply<kRowA, kColA, kRowB, kColB, -1>(
89               A.data(), kRowA, kColA,
90               B.data(), kRowB, kColB,
91               C_minus.data(), start_row_c, start_col_c, row_stride_c, col_stride_c);
92
93            EXPECT_NEAR((C_minus_ref - C_minus).norm(), 0.0, kTolerance)
94               << "C -= A * B \n"
95               << "row_stride_c : " << row_stride_c << "\n"
96               << "col_stride_c : " << col_stride_c << "\n"
97               << "start_row_c  : " << start_row_c << "\n"
98               << "start_col_c  : " << start_col_c << "\n"
99               << "Cref : \n" << C_minus_ref << "\n"
100               << "C: \n" << C_minus;
101
102           C_assign_ref.block(start_row_c, start_col_c, kRowA, kColB) =
103               A * B;
104
105           MatrixMatrixMultiply<kRowA, kColA, kRowB, kColB, 0>(
106               A.data(), kRowA, kColA,
107               B.data(), kRowB, kColB,
108               C_assign.data(), start_row_c, start_col_c, row_stride_c, col_stride_c);
109
110           EXPECT_NEAR((C_assign_ref - C_assign).norm(), 0.0, kTolerance)
111               << "C = A * B \n"
112               << "row_stride_c : " << row_stride_c << "\n"
113               << "col_stride_c : " << col_stride_c << "\n"
114               << "start_row_c  : " << start_row_c << "\n"
115               << "start_col_c  : " << start_col_c << "\n"
116               << "Cref : \n" << C_assign_ref << "\n"
117               << "C: \n" << C_assign;
118         }
119       }
120     }
121   }
122 }
123
124 TEST(BLAS, MatrixTransposeMatrixMultiply) {
125   const int kRowA = 5;
126   const int kColA = 3;
127   Matrix A(kRowA, kColA);
128   A.setOnes();
129
130   const int kRowB = 5;
131   const int kColB = 7;
132   Matrix B(kRowB, kColB);
133   B.setOnes();
134
135   for (int row_stride_c = kColA; row_stride_c < 3 * kColA; ++row_stride_c) {
136     for (int col_stride_c = kColB; col_stride_c <  3 * kColB; ++col_stride_c) {
137       Matrix C(row_stride_c, col_stride_c);
138       C.setOnes();
139
140       Matrix C_plus = C;
141       Matrix C_minus = C;
142       Matrix C_assign = C;
143
144       Matrix C_plus_ref = C;
145       Matrix C_minus_ref = C;
146       Matrix C_assign_ref = C;
147       for (int start_row_c = 0; start_row_c + kColA < row_stride_c; ++start_row_c) {
148         for (int start_col_c = 0; start_col_c + kColB < col_stride_c; ++start_col_c) {
149           C_plus_ref.block(start_row_c, start_col_c, kColA, kColB) +=
150               A.transpose() * B;
151
152           MatrixTransposeMatrixMultiply<kRowA, kColA, kRowB, kColB, 1>(
153               A.data(), kRowA, kColA,
154               B.data(), kRowB, kColB,
155               C_plus.data(), start_row_c, start_col_c, row_stride_c, col_stride_c);
156
157           EXPECT_NEAR((C_plus_ref - C_plus).norm(), 0.0, kTolerance)
158               << "C += A' * B \n"
159               << "row_stride_c : " << row_stride_c << "\n"
160               << "col_stride_c : " << col_stride_c << "\n"
161               << "start_row_c  : " << start_row_c << "\n"
162               << "start_col_c  : " << start_col_c << "\n"
163               << "Cref : \n" << C_plus_ref << "\n"
164               << "C: \n" << C_plus;
165
166           C_minus_ref.block(start_row_c, start_col_c, kColA, kColB) -=
167               A.transpose() * B;
168
169           MatrixTransposeMatrixMultiply<kRowA, kColA, kRowB, kColB, -1>(
170               A.data(), kRowA, kColA,
171               B.data(), kRowB, kColB,
172               C_minus.data(), start_row_c, start_col_c, row_stride_c, col_stride_c);
173
174           EXPECT_NEAR((C_minus_ref - C_minus).norm(), 0.0, kTolerance)
175               << "C -= A' * B \n"
176               << "row_stride_c : " << row_stride_c << "\n"
177               << "col_stride_c : " << col_stride_c << "\n"
178               << "start_row_c  : " << start_row_c << "\n"
179               << "start_col_c  : " << start_col_c << "\n"
180               << "Cref : \n" << C_minus_ref << "\n"
181               << "C: \n" << C_minus;
182
183           C_assign_ref.block(start_row_c, start_col_c, kColA, kColB) =
184               A.transpose() * B;
185
186           MatrixTransposeMatrixMultiply<kRowA, kColA, kRowB, kColB, 0>(
187               A.data(), kRowA, kColA,
188               B.data(), kRowB, kColB,
189               C_assign.data(), start_row_c, start_col_c, row_stride_c, col_stride_c);
190
191           EXPECT_NEAR((C_assign_ref - C_assign).norm(), 0.0, kTolerance)
192               << "C = A' * B \n"
193               << "row_stride_c : " << row_stride_c << "\n"
194               << "col_stride_c : " << col_stride_c << "\n"
195               << "start_row_c  : " << start_row_c << "\n"
196               << "start_col_c  : " << start_col_c << "\n"
197               << "Cref : \n" << C_assign_ref << "\n"
198               << "C: \n" << C_assign;
199         }
200       }
201     }
202   }
203 }
204
205 TEST(BLAS, MatrixVectorMultiply) {
206   const int kRowA = 5;
207   const int kColA = 3;
208   Matrix A(kRowA, kColA);
209   A.setOnes();
210
211   Vector b(kColA);
212   b.setOnes();
213
214   Vector c(kRowA);
215   c.setOnes();
216
217   Vector c_plus = c;
218   Vector c_minus = c;
219   Vector c_assign = c;
220
221   Vector c_plus_ref = c;
222   Vector c_minus_ref = c;
223   Vector c_assign_ref = c;
224
225   c_plus_ref += A * b;
226   MatrixVectorMultiply<kRowA, kColA, 1>(A.data(), kRowA, kColA,
227                                         b.data(),
228                                         c_plus.data());
229   EXPECT_NEAR((c_plus_ref - c_plus).norm(), 0.0, kTolerance)
230       << "c += A * b \n"
231       << "c_ref : \n" << c_plus_ref << "\n"
232       << "c: \n" << c_plus;
233
234   c_minus_ref -= A * b;
235   MatrixVectorMultiply<kRowA, kColA, -1>(A.data(), kRowA, kColA,
236                                                  b.data(),
237                                                  c_minus.data());
238   EXPECT_NEAR((c_minus_ref - c_minus).norm(), 0.0, kTolerance)
239       << "c += A * b \n"
240       << "c_ref : \n" << c_minus_ref << "\n"
241       << "c: \n" << c_minus;
242
243   c_assign_ref = A * b;
244   MatrixVectorMultiply<kRowA, kColA, 0>(A.data(), kRowA, kColA,
245                                                   b.data(),
246                                                   c_assign.data());
247   EXPECT_NEAR((c_assign_ref - c_assign).norm(), 0.0, kTolerance)
248       << "c += A * b \n"
249       << "c_ref : \n" << c_assign_ref << "\n"
250       << "c: \n" << c_assign;
251 }
252
253 TEST(BLAS, MatrixTransposeVectorMultiply) {
254   const int kRowA = 5;
255   const int kColA = 3;
256   Matrix A(kRowA, kColA);
257   A.setRandom();
258
259   Vector b(kRowA);
260   b.setRandom();
261
262   Vector c(kColA);
263   c.setOnes();
264
265   Vector c_plus = c;
266   Vector c_minus = c;
267   Vector c_assign = c;
268
269   Vector c_plus_ref = c;
270   Vector c_minus_ref = c;
271   Vector c_assign_ref = c;
272
273   c_plus_ref += A.transpose() * b;
274   MatrixTransposeVectorMultiply<kRowA, kColA, 1>(A.data(), kRowA, kColA,
275                                                  b.data(),
276                                                  c_plus.data());
277   EXPECT_NEAR((c_plus_ref - c_plus).norm(), 0.0, kTolerance)
278       << "c += A' * b \n"
279       << "c_ref : \n" << c_plus_ref << "\n"
280       << "c: \n" << c_plus;
281
282   c_minus_ref -= A.transpose() * b;
283   MatrixTransposeVectorMultiply<kRowA, kColA, -1>(A.data(), kRowA, kColA,
284                                                   b.data(),
285                                                   c_minus.data());
286   EXPECT_NEAR((c_minus_ref - c_minus).norm(), 0.0, kTolerance)
287       << "c += A' * b \n"
288       << "c_ref : \n" << c_minus_ref << "\n"
289       << "c: \n" << c_minus;
290
291   c_assign_ref = A.transpose() * b;
292   MatrixTransposeVectorMultiply<kRowA, kColA, 0>(A.data(), kRowA, kColA,
293                                                   b.data(),
294                                                   c_assign.data());
295   EXPECT_NEAR((c_assign_ref - c_assign).norm(), 0.0, kTolerance)
296       << "c += A' * b \n"
297       << "c_ref : \n" << c_assign_ref << "\n"
298       << "c: \n" << c_assign;
299 }
300
301 }  // namespace internal
302 }  // namespace ceres