Line |
Branch |
Exec |
Source |
1 |
|
|
// |
2 |
|
|
// Copyright (c) 2024 INRIA |
3 |
|
|
// |
4 |
|
|
|
5 |
|
|
#include <iostream> |
6 |
|
|
|
7 |
|
|
#include <pinocchio/math/tridiagonal-matrix.hpp> |
8 |
|
|
|
9 |
|
|
#include <boost/variant.hpp> // to avoid C99 warnings |
10 |
|
|
|
11 |
|
|
#include <boost/test/unit_test.hpp> |
12 |
|
|
#include <boost/utility/binary.hpp> |
13 |
|
|
|
14 |
|
|
BOOST_AUTO_TEST_SUITE(BOOST_TEST_MODULE) |
15 |
|
|
|
16 |
|
|
using namespace pinocchio; |
17 |
|
|
|
18 |
|
✗ |
BOOST_AUTO_TEST_CASE(test_zero) |
19 |
|
|
{ |
20 |
|
✗ |
const Eigen::DenseIndex mat_size = 20; |
21 |
|
✗ |
TridiagonalSymmetricMatrixTpl<double> tridiagonal_matrix(mat_size); |
22 |
|
|
|
23 |
|
✗ |
tridiagonal_matrix.setZero(); |
24 |
|
✗ |
BOOST_CHECK(tridiagonal_matrix.isZero(0)); |
25 |
|
✗ |
BOOST_CHECK(tridiagonal_matrix.isDiagonal(0)); |
26 |
|
✗ |
BOOST_CHECK(tridiagonal_matrix.matrix().isZero(0)); |
27 |
|
|
} |
28 |
|
|
|
29 |
|
✗ |
BOOST_AUTO_TEST_CASE(test_identity) |
30 |
|
|
{ |
31 |
|
✗ |
const Eigen::DenseIndex mat_size = 20; |
32 |
|
✗ |
TridiagonalSymmetricMatrixTpl<double> tridiagonal_matrix(mat_size); |
33 |
|
|
typedef TridiagonalSymmetricMatrixTpl<double>::PlainMatrixType PlainMatrixType; |
34 |
|
|
|
35 |
|
✗ |
tridiagonal_matrix.setIdentity(); |
36 |
|
✗ |
BOOST_CHECK(tridiagonal_matrix.isIdentity(0)); |
37 |
|
✗ |
BOOST_CHECK(tridiagonal_matrix.isDiagonal(0)); |
38 |
|
|
|
39 |
|
✗ |
BOOST_CHECK(tridiagonal_matrix.rows() == mat_size); |
40 |
|
✗ |
BOOST_CHECK(tridiagonal_matrix.cols() == mat_size); |
41 |
|
✗ |
BOOST_CHECK(tridiagonal_matrix.diagonal().size() == mat_size); |
42 |
|
✗ |
BOOST_CHECK(tridiagonal_matrix.subDiagonal().size() == mat_size - 1); |
43 |
|
|
|
44 |
|
✗ |
BOOST_CHECK(tridiagonal_matrix.diagonal().isOnes(0)); |
45 |
|
✗ |
BOOST_CHECK(tridiagonal_matrix.subDiagonal().isZero(0)); |
46 |
|
✗ |
BOOST_CHECK(tridiagonal_matrix.matrix().isIdentity(0)); |
47 |
|
|
|
48 |
|
|
// Fill matrix |
49 |
|
|
{ |
50 |
|
✗ |
PlainMatrixType mat(mat_size, mat_size); |
51 |
|
✗ |
mat = tridiagonal_matrix; |
52 |
|
|
|
53 |
|
✗ |
BOOST_CHECK(mat.isIdentity(0)); |
54 |
|
|
} |
55 |
|
|
|
56 |
|
|
// Matrix multiplication left and right |
57 |
|
✗ |
for (int k = 0; k < 1000; ++k) |
58 |
|
|
{ |
59 |
|
✗ |
PlainMatrixType mat = PlainMatrixType::Random(mat_size, mat_size); |
60 |
|
|
|
61 |
|
✗ |
PlainMatrixType plain(mat_size, mat_size); |
62 |
|
✗ |
plain = tridiagonal_matrix; |
63 |
|
|
|
64 |
|
✗ |
PlainMatrixType res_apply_on_the_right = tridiagonal_matrix * mat; |
65 |
|
✗ |
PlainMatrixType res_apply_on_the_right_ref = plain * mat; |
66 |
|
✗ |
BOOST_CHECK(res_apply_on_the_right.isApprox(res_apply_on_the_right_ref)); |
67 |
|
|
|
68 |
|
✗ |
PlainMatrixType res_apply_on_the_left = mat * tridiagonal_matrix; |
69 |
|
✗ |
PlainMatrixType res_apply_on_the_left_ref = mat * plain; |
70 |
|
✗ |
BOOST_CHECK(res_apply_on_the_left.isApprox(res_apply_on_the_left_ref)); |
71 |
|
|
} |
72 |
|
|
} |
73 |
|
|
|
74 |
|
✗ |
BOOST_AUTO_TEST_CASE(test_random) |
75 |
|
|
{ |
76 |
|
✗ |
const Eigen::DenseIndex mat_size = 20; |
77 |
|
✗ |
TridiagonalSymmetricMatrixTpl<double> tridiagonal_matrix(mat_size); |
78 |
|
|
typedef TridiagonalSymmetricMatrixTpl<double>::PlainMatrixType PlainMatrixType; |
79 |
|
|
|
80 |
|
✗ |
tridiagonal_matrix.setRandom(); |
81 |
|
|
|
82 |
|
✗ |
BOOST_CHECK(tridiagonal_matrix.rows() == mat_size); |
83 |
|
✗ |
BOOST_CHECK(tridiagonal_matrix.cols() == mat_size); |
84 |
|
✗ |
BOOST_CHECK(tridiagonal_matrix.diagonal().size() == mat_size); |
85 |
|
✗ |
BOOST_CHECK(tridiagonal_matrix.subDiagonal().size() == mat_size - 1); |
86 |
|
|
|
87 |
|
|
// Fill matrix |
88 |
|
|
{ |
89 |
|
✗ |
PlainMatrixType mat(mat_size, mat_size); |
90 |
|
✗ |
mat = tridiagonal_matrix; |
91 |
|
|
|
92 |
|
✗ |
BOOST_CHECK(mat.diagonal() == tridiagonal_matrix.diagonal()); |
93 |
|
✗ |
BOOST_CHECK(mat.diagonal<-1>() == tridiagonal_matrix.subDiagonal()); |
94 |
|
✗ |
BOOST_CHECK(mat.diagonal<+1>().conjugate() == tridiagonal_matrix.subDiagonal().conjugate()); |
95 |
|
|
} |
96 |
|
|
|
97 |
|
|
// Matrix multiplication |
98 |
|
✗ |
for (int k = 0; k < 1000; ++k) |
99 |
|
|
{ |
100 |
|
✗ |
PlainMatrixType rhs_mat = PlainMatrixType::Random(mat_size, mat_size); |
101 |
|
|
|
102 |
|
✗ |
PlainMatrixType plain(mat_size, mat_size); |
103 |
|
✗ |
plain = tridiagonal_matrix; |
104 |
|
|
|
105 |
|
✗ |
PlainMatrixType res = tridiagonal_matrix * rhs_mat; |
106 |
|
|
|
107 |
|
✗ |
PlainMatrixType res_ref = plain * rhs_mat; |
108 |
|
✗ |
BOOST_CHECK(res.isApprox(res_ref)); |
109 |
|
✗ |
BOOST_CHECK((tridiagonal_matrix * PlainMatrixType::Identity(mat_size, mat_size)) |
110 |
|
|
.isApprox(tridiagonal_matrix.matrix())); |
111 |
|
|
} |
112 |
|
|
} |
113 |
|
|
|
114 |
|
✗ |
BOOST_AUTO_TEST_CASE(test_inverse) |
115 |
|
|
{ |
116 |
|
|
typedef TridiagonalSymmetricMatrixTpl<double> TridiagonalSymmetricMatrixd; |
117 |
|
✗ |
const Eigen::DenseIndex mat_size = 10; |
118 |
|
✗ |
TridiagonalSymmetricMatrixTpl<double> tridiagonal_matrix(mat_size); |
119 |
|
|
typedef TridiagonalSymmetricMatrixTpl<double>::PlainMatrixType PlainMatrixType; |
120 |
|
|
|
121 |
|
✗ |
tridiagonal_matrix.setRandom(); |
122 |
|
|
|
123 |
|
✗ |
PlainMatrixType plain_mat(mat_size, mat_size); |
124 |
|
✗ |
plain_mat = tridiagonal_matrix; |
125 |
|
✗ |
const PlainMatrixType plain_mat_inverse = plain_mat.inverse(); |
126 |
|
|
|
127 |
|
|
const TridiagonalSymmetricMatrixInverse<TridiagonalSymmetricMatrixd> & |
128 |
|
✗ |
tridiagonal_matrix_inverse = tridiagonal_matrix.inverse(); |
129 |
|
|
|
130 |
|
✗ |
BOOST_CHECK(tridiagonal_matrix_inverse.rows() == tridiagonal_matrix.rows()); |
131 |
|
✗ |
BOOST_CHECK(tridiagonal_matrix_inverse.cols() == tridiagonal_matrix.cols()); |
132 |
|
|
|
133 |
|
✗ |
const auto & tridiagonal_matrix_ref = tridiagonal_matrix_inverse.inverse(); |
134 |
|
✗ |
BOOST_CHECK(&tridiagonal_matrix_ref == &tridiagonal_matrix); |
135 |
|
|
|
136 |
|
✗ |
const PlainMatrixType tridiagonal_matrix_inverse_plain = tridiagonal_matrix_inverse; |
137 |
|
✗ |
BOOST_CHECK(tridiagonal_matrix_inverse_plain.isApprox(plain_mat_inverse)); |
138 |
|
|
|
139 |
|
|
// Matrix multiplication |
140 |
|
✗ |
for (int k = 0; k < 1; ++k) |
141 |
|
|
{ |
142 |
|
✗ |
PlainMatrixType rhs_mat = PlainMatrixType::Random(mat_size, mat_size); |
143 |
|
|
|
144 |
|
✗ |
PlainMatrixType res(mat_size, mat_size); |
145 |
|
✗ |
res = tridiagonal_matrix_ref * rhs_mat; |
146 |
|
|
|
147 |
|
✗ |
BOOST_CHECK(res.isApprox((plain_mat * rhs_mat).eval())); |
148 |
|
|
|
149 |
|
✗ |
res = tridiagonal_matrix_inverse * rhs_mat; |
150 |
|
✗ |
const PlainMatrixType res_ref = plain_mat_inverse * rhs_mat; |
151 |
|
|
|
152 |
|
✗ |
BOOST_CHECK(res.isApprox(res_ref)); |
153 |
|
|
} |
154 |
|
|
|
155 |
|
|
// Test diagonal |
156 |
|
|
{ |
157 |
|
✗ |
Eigen::MatrixXd sub_diagonal_matrix = Eigen::MatrixXd::Zero(mat_size, mat_size); |
158 |
|
✗ |
sub_diagonal_matrix.diagonal<1>().setRandom(); |
159 |
|
✗ |
sub_diagonal_matrix.diagonal().setRandom(); |
160 |
|
✗ |
sub_diagonal_matrix.diagonal<-1>().setRandom(); |
161 |
|
|
|
162 |
|
✗ |
const Eigen::MatrixXd test_mat = Eigen::MatrixXd::Random(mat_size, mat_size); |
163 |
|
✗ |
const Eigen::MatrixXd res_ref = sub_diagonal_matrix * test_mat; |
164 |
|
|
|
165 |
|
✗ |
Eigen::MatrixXd res(mat_size, mat_size); // res.setZero(); |
166 |
|
✗ |
res.noalias() = sub_diagonal_matrix.diagonal().asDiagonal() * test_mat; |
167 |
|
✗ |
res.topRows(mat_size - 1) += |
168 |
|
✗ |
sub_diagonal_matrix.diagonal<1>().asDiagonal() * test_mat.bottomRows(mat_size - 1); |
169 |
|
✗ |
res.bottomRows(mat_size - 1) += |
170 |
|
✗ |
sub_diagonal_matrix.diagonal<-1>().asDiagonal() * test_mat.topRows(mat_size - 1); |
171 |
|
✗ |
BOOST_CHECK(res.isApprox(res_ref)); |
172 |
|
|
} |
173 |
|
|
} |
174 |
|
|
|
175 |
|
|
BOOST_AUTO_TEST_SUITE_END() |
176 |
|
|
|