1 // This file is part of Eigen, a lightweight C++ template library
4 // Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
6 // This Source Code Form is subject to the terms of the Mozilla
7 // Public License v. 2.0. If a copy of the MPL was not distributed
8 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
12 template<typename MatrixType
> void product_extra(const MatrixType
& m
)
14 typedef typename
MatrixType::Index Index
;
15 typedef typename
MatrixType::Scalar Scalar
;
16 typedef Matrix
<Scalar
, 1, Dynamic
> RowVectorType
;
17 typedef Matrix
<Scalar
, Dynamic
, 1> ColVectorType
;
18 typedef Matrix
<Scalar
, Dynamic
, Dynamic
,
19 MatrixType::Flags
&RowMajorBit
> OtherMajorMatrixType
;
21 Index rows
= m
.rows();
22 Index cols
= m
.cols();
24 MatrixType m1
= MatrixType::Random(rows
, cols
),
25 m2
= MatrixType::Random(rows
, cols
),
27 mzero
= MatrixType::Zero(rows
, cols
),
28 identity
= MatrixType::Identity(rows
, rows
),
29 square
= MatrixType::Random(rows
, rows
),
30 res
= MatrixType::Random(rows
, rows
),
31 square2
= MatrixType::Random(cols
, cols
),
32 res2
= MatrixType::Random(cols
, cols
);
33 RowVectorType v1
= RowVectorType::Random(rows
), vrres(rows
);
34 ColVectorType vc2
= ColVectorType::Random(cols
), vcres(cols
);
35 OtherMajorMatrixType tm1
= m1
;
37 Scalar s1
= internal::random
<Scalar
>(),
38 s2
= internal::random
<Scalar
>(),
39 s3
= internal::random
<Scalar
>();
41 VERIFY_IS_APPROX(m3
.noalias() = m1
* m2
.adjoint(), m1
* m2
.adjoint().eval());
42 VERIFY_IS_APPROX(m3
.noalias() = m1
.adjoint() * square
.adjoint(), m1
.adjoint().eval() * square
.adjoint().eval());
43 VERIFY_IS_APPROX(m3
.noalias() = m1
.adjoint() * m2
, m1
.adjoint().eval() * m2
);
44 VERIFY_IS_APPROX(m3
.noalias() = (s1
* m1
.adjoint()) * m2
, (s1
* m1
.adjoint()).eval() * m2
);
45 VERIFY_IS_APPROX(m3
.noalias() = ((s1
* m1
).adjoint()) * m2
, (numext::conj(s1
) * m1
.adjoint()).eval() * m2
);
46 VERIFY_IS_APPROX(m3
.noalias() = (- m1
.adjoint() * s1
) * (s3
* m2
), (- m1
.adjoint() * s1
).eval() * (s3
* m2
).eval());
47 VERIFY_IS_APPROX(m3
.noalias() = (s2
* m1
.adjoint() * s1
) * m2
, (s2
* m1
.adjoint() * s1
).eval() * m2
);
48 VERIFY_IS_APPROX(m3
.noalias() = (-m1
*s2
) * s1
*m2
.adjoint(), (-m1
*s2
).eval() * (s1
*m2
.adjoint()).eval());
50 // a very tricky case where a scale factor has to be automatically conjugated:
51 VERIFY_IS_APPROX( m1
.adjoint() * (s1
*m2
).conjugate(), (m1
.adjoint()).eval() * ((s1
*m2
).conjugate()).eval());
54 // test all possible conjugate combinations for the four matrix-vector product cases:
56 VERIFY_IS_APPROX((-m1
.conjugate() * s2
) * (s1
* vc2
),
57 (-m1
.conjugate()*s2
).eval() * (s1
* vc2
).eval());
58 VERIFY_IS_APPROX((-m1
* s2
) * (s1
* vc2
.conjugate()),
59 (-m1
*s2
).eval() * (s1
* vc2
.conjugate()).eval());
60 VERIFY_IS_APPROX((-m1
.conjugate() * s2
) * (s1
* vc2
.conjugate()),
61 (-m1
.conjugate()*s2
).eval() * (s1
* vc2
.conjugate()).eval());
63 VERIFY_IS_APPROX((s1
* vc2
.transpose()) * (-m1
.adjoint() * s2
),
64 (s1
* vc2
.transpose()).eval() * (-m1
.adjoint()*s2
).eval());
65 VERIFY_IS_APPROX((s1
* vc2
.adjoint()) * (-m1
.transpose() * s2
),
66 (s1
* vc2
.adjoint()).eval() * (-m1
.transpose()*s2
).eval());
67 VERIFY_IS_APPROX((s1
* vc2
.adjoint()) * (-m1
.adjoint() * s2
),
68 (s1
* vc2
.adjoint()).eval() * (-m1
.adjoint()*s2
).eval());
70 VERIFY_IS_APPROX((-m1
.adjoint() * s2
) * (s1
* v1
.transpose()),
71 (-m1
.adjoint()*s2
).eval() * (s1
* v1
.transpose()).eval());
72 VERIFY_IS_APPROX((-m1
.transpose() * s2
) * (s1
* v1
.adjoint()),
73 (-m1
.transpose()*s2
).eval() * (s1
* v1
.adjoint()).eval());
74 VERIFY_IS_APPROX((-m1
.adjoint() * s2
) * (s1
* v1
.adjoint()),
75 (-m1
.adjoint()*s2
).eval() * (s1
* v1
.adjoint()).eval());
77 VERIFY_IS_APPROX((s1
* v1
) * (-m1
.conjugate() * s2
),
78 (s1
* v1
).eval() * (-m1
.conjugate()*s2
).eval());
79 VERIFY_IS_APPROX((s1
* v1
.conjugate()) * (-m1
* s2
),
80 (s1
* v1
.conjugate()).eval() * (-m1
*s2
).eval());
81 VERIFY_IS_APPROX((s1
* v1
.conjugate()) * (-m1
.conjugate() * s2
),
82 (s1
* v1
.conjugate()).eval() * (-m1
.conjugate()*s2
).eval());
84 VERIFY_IS_APPROX((-m1
.adjoint() * s2
) * (s1
* v1
.adjoint()),
85 (-m1
.adjoint()*s2
).eval() * (s1
* v1
.adjoint()).eval());
87 // test the vector-matrix product with non aligned starts
88 Index i
= internal::random
<Index
>(0,m1
.rows()-2);
89 Index j
= internal::random
<Index
>(0,m1
.cols()-2);
90 Index r
= internal::random
<Index
>(1,m1
.rows()-i
);
91 Index c
= internal::random
<Index
>(1,m1
.cols()-j
);
92 Index i2
= internal::random
<Index
>(0,m1
.rows()-1);
93 Index j2
= internal::random
<Index
>(0,m1
.cols()-1);
95 VERIFY_IS_APPROX(m1
.col(j2
).adjoint() * m1
.block(0,j
,m1
.rows(),c
), m1
.col(j2
).adjoint().eval() * m1
.block(0,j
,m1
.rows(),c
).eval());
96 VERIFY_IS_APPROX(m1
.block(i
,0,r
,m1
.cols()) * m1
.row(i2
).adjoint(), m1
.block(i
,0,r
,m1
.cols()).eval() * m1
.row(i2
).adjoint().eval());
99 MatrixType tmp
= m1
* m1
.adjoint() * s1
;
100 VERIFY_IS_APPROX(tmp
, m1
* m1
.adjoint() * s1
);
102 // regression test for bug 1343, assignment to arrays
103 Array
<Scalar
,Dynamic
,1> a1
= m1
* vc2
;
104 VERIFY_IS_APPROX(a1
.matrix(),m1
*vc2
);
105 Array
<Scalar
,Dynamic
,1> a2
= s1
* (m1
* vc2
);
106 VERIFY_IS_APPROX(a2
.matrix(),s1
*m1
*vc2
);
107 Array
<Scalar
,1,Dynamic
> a3
= v1
* m1
;
108 VERIFY_IS_APPROX(a3
.matrix(),v1
*m1
);
109 Array
<Scalar
,Dynamic
,Dynamic
> a4
= m1
* m2
.adjoint();
110 VERIFY_IS_APPROX(a4
.matrix(),m1
*m2
.adjoint());
113 // Regression test for bug reported at http://forum.kde.org/viewtopic.php?f=74&t=96947
114 void mat_mat_scalar_scalar_product()
116 Eigen::Matrix2Xd
dNdxy(2, 3);
117 dNdxy
<< -0.5, 0.5, 0,
119 double det
= 6.0, wt
= 0.5;
120 VERIFY_IS_APPROX(dNdxy
.transpose()*dNdxy
*det
*wt
, det
*wt
*dNdxy
.transpose()*dNdxy
);
123 template <typename MatrixType
>
124 void zero_sized_objects(const MatrixType
& m
)
126 typedef typename
MatrixType::Scalar Scalar
;
127 const int PacketSize
= internal::packet_traits
<Scalar
>::size
;
128 const int PacketSize1
= PacketSize
>1 ? PacketSize
-1 : 1;
129 Index rows
= m
.rows();
130 Index cols
= m
.cols();
133 MatrixType res
, a(rows
,0), b(0,cols
);
134 VERIFY_IS_APPROX( (res
=a
*b
), MatrixType::Zero(rows
,cols
) );
135 VERIFY_IS_APPROX( (res
=a
*a
.transpose()), MatrixType::Zero(rows
,rows
) );
136 VERIFY_IS_APPROX( (res
=b
.transpose()*b
), MatrixType::Zero(cols
,cols
) );
137 VERIFY_IS_APPROX( (res
=b
.transpose()*a
.transpose()), MatrixType::Zero(cols
,rows
) );
141 MatrixType res
, a(rows
,cols
), b(cols
,0);
143 VERIFY(res
.rows()==rows
&& res
.cols()==0);
146 VERIFY(res
.rows()==0 && res
.cols()==cols
);
150 Matrix
<Scalar
,PacketSize
,0> a
;
151 Matrix
<Scalar
,0,1> b
;
152 Matrix
<Scalar
,PacketSize
,1> res
;
153 VERIFY_IS_APPROX( (res
=a
*b
), MatrixType::Zero(PacketSize
,1) );
154 VERIFY_IS_APPROX( (res
=a
.lazyProduct(b
)), MatrixType::Zero(PacketSize
,1) );
158 Matrix
<Scalar
,PacketSize1
,0> a
;
159 Matrix
<Scalar
,0,1> b
;
160 Matrix
<Scalar
,PacketSize1
,1> res
;
161 VERIFY_IS_APPROX( (res
=a
*b
), MatrixType::Zero(PacketSize1
,1) );
162 VERIFY_IS_APPROX( (res
=a
.lazyProduct(b
)), MatrixType::Zero(PacketSize1
,1) );
166 Matrix
<Scalar
,PacketSize
,Dynamic
> a(PacketSize
,0);
167 Matrix
<Scalar
,Dynamic
,1> b(0,1);
168 Matrix
<Scalar
,PacketSize
,1> res
;
169 VERIFY_IS_APPROX( (res
=a
*b
), MatrixType::Zero(PacketSize
,1) );
170 VERIFY_IS_APPROX( (res
=a
.lazyProduct(b
)), MatrixType::Zero(PacketSize
,1) );
174 Matrix
<Scalar
,PacketSize1
,Dynamic
> a(PacketSize1
,0);
175 Matrix
<Scalar
,Dynamic
,1> b(0,1);
176 Matrix
<Scalar
,PacketSize1
,1> res
;
177 VERIFY_IS_APPROX( (res
=a
*b
), MatrixType::Zero(PacketSize1
,1) );
178 VERIFY_IS_APPROX( (res
=a
.lazyProduct(b
)), MatrixType::Zero(PacketSize1
,1) );
187 // a product of the form lhs*rhs with
190 // rows = 1, cols = 4
191 // RowsAtCompileTime = 1, ColsAtCompileTime = -1
192 // MaxRowsAtCompileTime = 1, MaxColsAtCompileTime = 5
195 // rows = 4, cols = 0
196 // RowsAtCompileTime = -1, ColsAtCompileTime = -1
197 // MaxRowsAtCompileTime = 5, MaxColsAtCompileTime = 1
199 // was failing on a runtime assertion, because it had been mis-compiled as a dot product because Product.h was using the
200 // max-sizes to detect size 1 indicating vectors, and that didn't account for 0-sized object with max-size 1.
202 Matrix
<float,1,Dynamic
,RowMajor
,1,5> a(1,4);
203 Matrix
<float,Dynamic
,Dynamic
,ColMajor
,5,1> b(4,0);
207 template<int> void bug_817()
209 ArrayXXf B
= ArrayXXf::Random(10,10), C
;
210 VectorXf x
= VectorXf::Random(10);
211 C
= (x
.transpose()*B
.matrix());
212 B
= (x
.transpose()*B
.matrix());
213 VERIFY_IS_APPROX(B
,C
);
217 void unaligned_objects()
219 // Regression test for the bug reported here:
220 // http://forum.kde.org/viewtopic.php?f=74&t=107541
221 // Recall the matrix*vector kernel avoid unaligned loads by loading two packets and then reassemble then.
222 // There was a mistake in the computation of the valid range for fully unaligned objects: in some rare cases,
223 // memory was read outside the allocated matrix memory. Though the values were not used, this might raise segfault.
224 for(int m
=450;m
<460;++m
)
226 for(int n
=8;n
<12;++n
)
229 VectorXf
v1(n
), r1(500);
230 RowVectorXf
v2(m
), r2(16);
235 for(int o
=0; o
<4; ++o
)
237 r1
.segment(o
,m
).noalias() = M
* v1
;
238 VERIFY_IS_APPROX(r1
.segment(o
,m
), M
* MatrixXf(v1
));
239 r2
.segment(o
,n
).noalias() = v2
* M
;
240 VERIFY_IS_APPROX(r2
.segment(o
,n
), MatrixXf(v2
) * M
);
248 Index
test_compute_block_size(Index m
, Index n
, Index k
)
250 Index
mc(m
), nc(n
), kc(k
);
251 internal::computeProductBlockingSizes
<T
,T
>(kc
, mc
, nc
);
256 Index
compute_block_size()
259 ret
+= test_compute_block_size
<T
>(0,1,1);
260 ret
+= test_compute_block_size
<T
>(1,0,1);
261 ret
+= test_compute_block_size
<T
>(1,1,0);
262 ret
+= test_compute_block_size
<T
>(0,0,1);
263 ret
+= test_compute_block_size
<T
>(0,1,0);
264 ret
+= test_compute_block_size
<T
>(1,0,0);
265 ret
+= test_compute_block_size
<T
>(0,0,0);
270 void aliasing_with_resize()
272 Index m
= internal::random
<Index
>(10,50);
273 Index n
= internal::random
<Index
>(10,50);
274 MatrixXd A
, B
, C(m
,n
), D(m
,m
);
279 double s
= internal::random
<double>(1,10);
282 B
= A
* A
.transpose();
283 A
= A
* A
.transpose();
284 VERIFY_IS_APPROX(A
,B
);
287 B
= (A
* A
.transpose())/s
;
288 A
= (A
* A
.transpose())/s
;
289 VERIFY_IS_APPROX(A
,B
);
292 B
= (A
* A
.transpose()) + D
;
293 A
= (A
* A
.transpose()) + D
;
294 VERIFY_IS_APPROX(A
,B
);
297 B
= D
+ (A
* A
.transpose());
298 A
= D
+ (A
* A
.transpose());
299 VERIFY_IS_APPROX(A
,B
);
302 B
= s
* (A
* A
.transpose());
303 A
= s
* (A
* A
.transpose());
304 VERIFY_IS_APPROX(A
,B
);
310 VERIFY_IS_APPROX(a
,b
);
318 VectorXd v
= VectorXd::Random(n
);
319 r
= v
* RowVectorXd::Ones(n
);
320 VERIFY_IS_APPROX(r
, v
.rowwise().replicate(n
));
321 r
= VectorXd::Ones(n
) * v
.transpose();
322 VERIFY_IS_APPROX(r
, v
.rowwise().replicate(n
).transpose());
324 Matrix4d ones44
= Matrix4d::Ones();
325 Matrix4d m44
= Matrix4d::Ones() * Matrix4d::Ones();
326 VERIFY_IS_APPROX(m44
,Matrix4d::Constant(4));
327 VERIFY_IS_APPROX(m44
.noalias()=ones44
*Matrix4d::Ones(), Matrix4d::Constant(4));
328 VERIFY_IS_APPROX(m44
.noalias()=ones44
.transpose()*Matrix4d::Ones(), Matrix4d::Constant(4));
329 VERIFY_IS_APPROX(m44
.noalias()=Matrix4d::Ones()*ones44
, Matrix4d::Constant(4));
330 VERIFY_IS_APPROX(m44
.noalias()=Matrix4d::Ones()*ones44
.transpose(), Matrix4d::Constant(4));
332 typedef Matrix
<double,4,4,RowMajor
> RMatrix4d
;
333 RMatrix4d r44
= Matrix4d::Ones() * Matrix4d::Ones();
334 VERIFY_IS_APPROX(r44
,Matrix4d::Constant(4));
335 VERIFY_IS_APPROX(r44
.noalias()=ones44
*Matrix4d::Ones(), Matrix4d::Constant(4));
336 VERIFY_IS_APPROX(r44
.noalias()=ones44
.transpose()*Matrix4d::Ones(), Matrix4d::Constant(4));
337 VERIFY_IS_APPROX(r44
.noalias()=Matrix4d::Ones()*ones44
, Matrix4d::Constant(4));
338 VERIFY_IS_APPROX(r44
.noalias()=Matrix4d::Ones()*ones44
.transpose(), Matrix4d::Constant(4));
339 VERIFY_IS_APPROX(r44
.noalias()=ones44
*RMatrix4d::Ones(), Matrix4d::Constant(4));
340 VERIFY_IS_APPROX(r44
.noalias()=ones44
.transpose()*RMatrix4d::Ones(), Matrix4d::Constant(4));
341 VERIFY_IS_APPROX(r44
.noalias()=RMatrix4d::Ones()*ones44
, Matrix4d::Constant(4));
342 VERIFY_IS_APPROX(r44
.noalias()=RMatrix4d::Ones()*ones44
.transpose(), Matrix4d::Constant(4));
347 VERIFY_IS_APPROX(r44
.noalias() += m44
.row(0).transpose() * RowVector4d::Ones(), ones44
);
349 VERIFY_IS_APPROX(r44
.noalias() += m44
.col(0) * RowVector4d::Ones(), ones44
);
351 VERIFY_IS_APPROX(r44
.noalias() += Vector4d::Ones() * m44
.row(0), ones44
);
353 VERIFY_IS_APPROX(r44
.noalias() += Vector4d::Ones() * m44
.col(0).transpose(), ones44
);
356 void test_product_extra()
358 for(int i
= 0; i
< g_repeat
; i
++) {
359 CALL_SUBTEST_1( product_extra(MatrixXf(internal::random
<int>(1,EIGEN_TEST_MAX_SIZE
), internal::random
<int>(1,EIGEN_TEST_MAX_SIZE
))) );
360 CALL_SUBTEST_2( product_extra(MatrixXd(internal::random
<int>(1,EIGEN_TEST_MAX_SIZE
), internal::random
<int>(1,EIGEN_TEST_MAX_SIZE
))) );
361 CALL_SUBTEST_2( mat_mat_scalar_scalar_product() );
362 CALL_SUBTEST_3( product_extra(MatrixXcf(internal::random
<int>(1,EIGEN_TEST_MAX_SIZE
/2), internal::random
<int>(1,EIGEN_TEST_MAX_SIZE
/2))) );
363 CALL_SUBTEST_4( product_extra(MatrixXcd(internal::random
<int>(1,EIGEN_TEST_MAX_SIZE
/2), internal::random
<int>(1,EIGEN_TEST_MAX_SIZE
/2))) );
364 CALL_SUBTEST_1( zero_sized_objects(MatrixXf(internal::random
<int>(1,EIGEN_TEST_MAX_SIZE
), internal::random
<int>(1,EIGEN_TEST_MAX_SIZE
))) );
366 CALL_SUBTEST_5( bug_127
<0>() );
367 CALL_SUBTEST_5( bug_817
<0>() );
368 CALL_SUBTEST_5( bug_1308
<0>() );
369 CALL_SUBTEST_6( unaligned_objects
<0>() );
370 CALL_SUBTEST_7( compute_block_size
<float>() );
371 CALL_SUBTEST_7( compute_block_size
<double>() );
372 CALL_SUBTEST_7( compute_block_size
<std::complex<double> >() );
373 CALL_SUBTEST_8( aliasing_with_resize
<void>() );