• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
5 //
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/.
9 
10 #define EIGEN_NO_STATIC_ASSERT
11 #include "product.h"
12 #include <Eigen/LU>
13 
14 // regression test for bug 447
15 template<int>
product1x1()16 void product1x1()
17 {
18   Matrix<float,1,3> matAstatic;
19   Matrix<float,3,1> matBstatic;
20   matAstatic.setRandom();
21   matBstatic.setRandom();
22   VERIFY_IS_APPROX( (matAstatic * matBstatic).coeff(0,0),
23                     matAstatic.cwiseProduct(matBstatic.transpose()).sum() );
24 
25   MatrixXf matAdynamic(1,3);
26   MatrixXf matBdynamic(3,1);
27   matAdynamic.setRandom();
28   matBdynamic.setRandom();
29   VERIFY_IS_APPROX( (matAdynamic * matBdynamic).coeff(0,0),
30                     matAdynamic.cwiseProduct(matBdynamic.transpose()).sum() );
31 }
32 
33 template<typename TC, typename TA, typename TB>
ref_prod(TC & C,const TA & A,const TB & B)34 const TC& ref_prod(TC &C, const TA &A, const TB &B)
35 {
36   for(Index i=0;i<C.rows();++i)
37     for(Index j=0;j<C.cols();++j)
38       for(Index k=0;k<A.cols();++k)
39         C.coeffRef(i,j) += A.coeff(i,k) * B.coeff(k,j);
40   return C;
41 }
42 
43 template<typename T, int Rows, int Cols, int Depth, int OC, int OA, int OB>
44 typename internal::enable_if<! ( (Rows ==1&&Depth!=1&&OA==ColMajor)
45                               || (Depth==1&&Rows !=1&&OA==RowMajor)
46                               || (Cols ==1&&Depth!=1&&OB==RowMajor)
47                               || (Depth==1&&Cols !=1&&OB==ColMajor)
48                               || (Rows ==1&&Cols !=1&&OC==ColMajor)
49                               || (Cols ==1&&Rows !=1&&OC==RowMajor)),void>::type
test_lazy_single(int rows,int cols,int depth)50 test_lazy_single(int rows, int cols, int depth)
51 {
52   Matrix<T,Rows,Depth,OA> A(rows,depth); A.setRandom();
53   Matrix<T,Depth,Cols,OB> B(depth,cols); B.setRandom();
54   Matrix<T,Rows,Cols,OC>  C(rows,cols);  C.setRandom();
55   Matrix<T,Rows,Cols,OC>  D(C);
56   VERIFY_IS_APPROX(C+=A.lazyProduct(B), ref_prod(D,A,B));
57 }
58 
59 template<typename T, int Rows, int Cols, int Depth, int OC, int OA, int OB>
60 typename internal::enable_if<  ( (Rows ==1&&Depth!=1&&OA==ColMajor)
61                               || (Depth==1&&Rows !=1&&OA==RowMajor)
62                               || (Cols ==1&&Depth!=1&&OB==RowMajor)
63                               || (Depth==1&&Cols !=1&&OB==ColMajor)
64                               || (Rows ==1&&Cols !=1&&OC==ColMajor)
65                               || (Cols ==1&&Rows !=1&&OC==RowMajor)),void>::type
test_lazy_single(int,int,int)66 test_lazy_single(int, int, int)
67 {
68 }
69 
70 template<typename T, int Rows, int Cols, int Depth>
test_lazy_all_layout(int rows=Rows,int cols=Cols,int depth=Depth)71 void test_lazy_all_layout(int rows=Rows, int cols=Cols, int depth=Depth)
72 {
73   CALL_SUBTEST(( test_lazy_single<T,Rows,Cols,Depth,ColMajor,ColMajor,ColMajor>(rows,cols,depth) ));
74   CALL_SUBTEST(( test_lazy_single<T,Rows,Cols,Depth,RowMajor,ColMajor,ColMajor>(rows,cols,depth) ));
75   CALL_SUBTEST(( test_lazy_single<T,Rows,Cols,Depth,ColMajor,RowMajor,ColMajor>(rows,cols,depth) ));
76   CALL_SUBTEST(( test_lazy_single<T,Rows,Cols,Depth,RowMajor,RowMajor,ColMajor>(rows,cols,depth) ));
77   CALL_SUBTEST(( test_lazy_single<T,Rows,Cols,Depth,ColMajor,ColMajor,RowMajor>(rows,cols,depth) ));
78   CALL_SUBTEST(( test_lazy_single<T,Rows,Cols,Depth,RowMajor,ColMajor,RowMajor>(rows,cols,depth) ));
79   CALL_SUBTEST(( test_lazy_single<T,Rows,Cols,Depth,ColMajor,RowMajor,RowMajor>(rows,cols,depth) ));
80   CALL_SUBTEST(( test_lazy_single<T,Rows,Cols,Depth,RowMajor,RowMajor,RowMajor>(rows,cols,depth) ));
81 }
82 
83 template<typename T>
test_lazy_l1()84 void test_lazy_l1()
85 {
86   int rows = internal::random<int>(1,12);
87   int cols = internal::random<int>(1,12);
88   int depth = internal::random<int>(1,12);
89 
90   // Inner
91   CALL_SUBTEST(( test_lazy_all_layout<T,1,1,1>() ));
92   CALL_SUBTEST(( test_lazy_all_layout<T,1,1,2>() ));
93   CALL_SUBTEST(( test_lazy_all_layout<T,1,1,3>() ));
94   CALL_SUBTEST(( test_lazy_all_layout<T,1,1,8>() ));
95   CALL_SUBTEST(( test_lazy_all_layout<T,1,1,9>() ));
96   CALL_SUBTEST(( test_lazy_all_layout<T,1,1,-1>(1,1,depth) ));
97 
98   // Outer
99   CALL_SUBTEST(( test_lazy_all_layout<T,2,1,1>() ));
100   CALL_SUBTEST(( test_lazy_all_layout<T,1,2,1>() ));
101   CALL_SUBTEST(( test_lazy_all_layout<T,2,2,1>() ));
102   CALL_SUBTEST(( test_lazy_all_layout<T,3,3,1>() ));
103   CALL_SUBTEST(( test_lazy_all_layout<T,4,4,1>() ));
104   CALL_SUBTEST(( test_lazy_all_layout<T,4,8,1>() ));
105   CALL_SUBTEST(( test_lazy_all_layout<T,4,-1,1>(4,cols) ));
106   CALL_SUBTEST(( test_lazy_all_layout<T,7,-1,1>(7,cols) ));
107   CALL_SUBTEST(( test_lazy_all_layout<T,-1,8,1>(rows) ));
108   CALL_SUBTEST(( test_lazy_all_layout<T,-1,3,1>(rows) ));
109   CALL_SUBTEST(( test_lazy_all_layout<T,-1,-1,1>(rows,cols) ));
110 }
111 
112 template<typename T>
test_lazy_l2()113 void test_lazy_l2()
114 {
115   int rows = internal::random<int>(1,12);
116   int cols = internal::random<int>(1,12);
117   int depth = internal::random<int>(1,12);
118 
119   // mat-vec
120   CALL_SUBTEST(( test_lazy_all_layout<T,2,1,2>() ));
121   CALL_SUBTEST(( test_lazy_all_layout<T,2,1,4>() ));
122   CALL_SUBTEST(( test_lazy_all_layout<T,4,1,2>() ));
123   CALL_SUBTEST(( test_lazy_all_layout<T,4,1,4>() ));
124   CALL_SUBTEST(( test_lazy_all_layout<T,5,1,4>() ));
125   CALL_SUBTEST(( test_lazy_all_layout<T,4,1,5>() ));
126   CALL_SUBTEST(( test_lazy_all_layout<T,4,1,6>() ));
127   CALL_SUBTEST(( test_lazy_all_layout<T,6,1,4>() ));
128   CALL_SUBTEST(( test_lazy_all_layout<T,8,1,8>() ));
129   CALL_SUBTEST(( test_lazy_all_layout<T,-1,1,4>(rows) ));
130   CALL_SUBTEST(( test_lazy_all_layout<T,4,1,-1>(4,1,depth) ));
131   CALL_SUBTEST(( test_lazy_all_layout<T,-1,1,-1>(rows,1,depth) ));
132 
133   // vec-mat
134   CALL_SUBTEST(( test_lazy_all_layout<T,1,2,2>() ));
135   CALL_SUBTEST(( test_lazy_all_layout<T,1,2,4>() ));
136   CALL_SUBTEST(( test_lazy_all_layout<T,1,4,2>() ));
137   CALL_SUBTEST(( test_lazy_all_layout<T,1,4,4>() ));
138   CALL_SUBTEST(( test_lazy_all_layout<T,1,5,4>() ));
139   CALL_SUBTEST(( test_lazy_all_layout<T,1,4,5>() ));
140   CALL_SUBTEST(( test_lazy_all_layout<T,1,4,6>() ));
141   CALL_SUBTEST(( test_lazy_all_layout<T,1,6,4>() ));
142   CALL_SUBTEST(( test_lazy_all_layout<T,1,8,8>() ));
143   CALL_SUBTEST(( test_lazy_all_layout<T,1,-1, 4>(1,cols) ));
144   CALL_SUBTEST(( test_lazy_all_layout<T,1, 4,-1>(1,4,depth) ));
145   CALL_SUBTEST(( test_lazy_all_layout<T,1,-1,-1>(1,cols,depth) ));
146 }
147 
148 template<typename T>
test_lazy_l3()149 void test_lazy_l3()
150 {
151   int rows = internal::random<int>(1,12);
152   int cols = internal::random<int>(1,12);
153   int depth = internal::random<int>(1,12);
154   // mat-mat
155   CALL_SUBTEST(( test_lazy_all_layout<T,2,4,2>() ));
156   CALL_SUBTEST(( test_lazy_all_layout<T,2,6,4>() ));
157   CALL_SUBTEST(( test_lazy_all_layout<T,4,3,2>() ));
158   CALL_SUBTEST(( test_lazy_all_layout<T,4,8,4>() ));
159   CALL_SUBTEST(( test_lazy_all_layout<T,5,6,4>() ));
160   CALL_SUBTEST(( test_lazy_all_layout<T,4,2,5>() ));
161   CALL_SUBTEST(( test_lazy_all_layout<T,4,7,6>() ));
162   CALL_SUBTEST(( test_lazy_all_layout<T,6,8,4>() ));
163   CALL_SUBTEST(( test_lazy_all_layout<T,8,3,8>() ));
164   CALL_SUBTEST(( test_lazy_all_layout<T,-1,6,4>(rows) ));
165   CALL_SUBTEST(( test_lazy_all_layout<T,4,3,-1>(4,3,depth) ));
166   CALL_SUBTEST(( test_lazy_all_layout<T,-1,6,-1>(rows,6,depth) ));
167   CALL_SUBTEST(( test_lazy_all_layout<T,8,2,2>() ));
168   CALL_SUBTEST(( test_lazy_all_layout<T,5,2,4>() ));
169   CALL_SUBTEST(( test_lazy_all_layout<T,4,4,2>() ));
170   CALL_SUBTEST(( test_lazy_all_layout<T,8,4,4>() ));
171   CALL_SUBTEST(( test_lazy_all_layout<T,6,5,4>() ));
172   CALL_SUBTEST(( test_lazy_all_layout<T,4,4,5>() ));
173   CALL_SUBTEST(( test_lazy_all_layout<T,3,4,6>() ));
174   CALL_SUBTEST(( test_lazy_all_layout<T,2,6,4>() ));
175   CALL_SUBTEST(( test_lazy_all_layout<T,7,8,8>() ));
176   CALL_SUBTEST(( test_lazy_all_layout<T,8,-1, 4>(8,cols) ));
177   CALL_SUBTEST(( test_lazy_all_layout<T,3, 4,-1>(3,4,depth) ));
178   CALL_SUBTEST(( test_lazy_all_layout<T,4,-1,-1>(4,cols,depth) ));
179 }
180 
181 template<typename T,int N,int M,int K>
test_linear_but_not_vectorizable()182 void test_linear_but_not_vectorizable()
183 {
184   // Check tricky cases for which the result of the product is a vector and thus must exhibit the LinearBit flag,
185   // but is not vectorizable along the linear dimension.
186   Index n = N==Dynamic ? internal::random<Index>(1,32) : N;
187   Index m = M==Dynamic ? internal::random<Index>(1,32) : M;
188   Index k = K==Dynamic ? internal::random<Index>(1,32) : K;
189 
190   {
191     Matrix<T,N,M+1> A; A.setRandom(n,m+1);
192     Matrix<T,M*2,K> B; B.setRandom(m*2,k);
193     Matrix<T,1,K> C;
194     Matrix<T,1,K> R;
195 
196     C.noalias() = A.template topLeftCorner<1,M>() * (B.template topRows<M>()+B.template bottomRows<M>());
197     R.noalias() = A.template topLeftCorner<1,M>() * (B.template topRows<M>()+B.template bottomRows<M>()).eval();
198     VERIFY_IS_APPROX(C,R);
199   }
200 
201   {
202     Matrix<T,M+1,N,RowMajor> A; A.setRandom(m+1,n);
203     Matrix<T,K,M*2,RowMajor> B; B.setRandom(k,m*2);
204     Matrix<T,K,1> C;
205     Matrix<T,K,1> R;
206 
207     C.noalias() = (B.template leftCols<M>()+B.template rightCols<M>())        * A.template topLeftCorner<M,1>();
208     R.noalias() = (B.template leftCols<M>()+B.template rightCols<M>()).eval() * A.template topLeftCorner<M,1>();
209     VERIFY_IS_APPROX(C,R);
210   }
211 }
212 
213 template<int Rows>
bug_1311()214 void bug_1311()
215 {
216   Matrix< double, Rows, 2 > A;  A.setRandom();
217   Vector2d b = Vector2d::Random() ;
218   Matrix<double,Rows,1> res;
219   res.noalias() = 1. * (A * b);
220   VERIFY_IS_APPROX(res, A*b);
221   res.noalias() = 1.*A * b;
222   VERIFY_IS_APPROX(res, A*b);
223   res.noalias() = (1.*A).lazyProduct(b);
224   VERIFY_IS_APPROX(res, A*b);
225   res.noalias() = (1.*A).lazyProduct(1.*b);
226   VERIFY_IS_APPROX(res, A*b);
227   res.noalias() = (A).lazyProduct(1.*b);
228   VERIFY_IS_APPROX(res, A*b);
229 }
230 
test_product_small()231 void test_product_small()
232 {
233   for(int i = 0; i < g_repeat; i++) {
234     CALL_SUBTEST_1( product(Matrix<float, 3, 2>()) );
235     CALL_SUBTEST_2( product(Matrix<int, 3, 17>()) );
236     CALL_SUBTEST_8( product(Matrix<double, 3, 17>()) );
237     CALL_SUBTEST_3( product(Matrix3d()) );
238     CALL_SUBTEST_4( product(Matrix4d()) );
239     CALL_SUBTEST_5( product(Matrix4f()) );
240     CALL_SUBTEST_6( product1x1<0>() );
241 
242     CALL_SUBTEST_11( test_lazy_l1<float>() );
243     CALL_SUBTEST_12( test_lazy_l2<float>() );
244     CALL_SUBTEST_13( test_lazy_l3<float>() );
245 
246     CALL_SUBTEST_21( test_lazy_l1<double>() );
247     CALL_SUBTEST_22( test_lazy_l2<double>() );
248     CALL_SUBTEST_23( test_lazy_l3<double>() );
249 
250     CALL_SUBTEST_31( test_lazy_l1<std::complex<float> >() );
251     CALL_SUBTEST_32( test_lazy_l2<std::complex<float> >() );
252     CALL_SUBTEST_33( test_lazy_l3<std::complex<float> >() );
253 
254     CALL_SUBTEST_41( test_lazy_l1<std::complex<double> >() );
255     CALL_SUBTEST_42( test_lazy_l2<std::complex<double> >() );
256     CALL_SUBTEST_43( test_lazy_l3<std::complex<double> >() );
257 
258     CALL_SUBTEST_7(( test_linear_but_not_vectorizable<float,2,1,Dynamic>() ));
259     CALL_SUBTEST_7(( test_linear_but_not_vectorizable<float,3,1,Dynamic>() ));
260     CALL_SUBTEST_7(( test_linear_but_not_vectorizable<float,2,1,16>() ));
261 
262     CALL_SUBTEST_6( bug_1311<3>() );
263     CALL_SUBTEST_6( bug_1311<5>() );
264   }
265 
266 #ifdef EIGEN_TEST_PART_6
267   {
268     // test compilation of (outer_product) * vector
269     Vector3f v = Vector3f::Random();
270     VERIFY_IS_APPROX( (v * v.transpose()) * v, (v * v.transpose()).eval() * v);
271   }
272 
273   {
274     // regression test for pull-request #93
275     Eigen::Matrix<double, 1, 1> A;  A.setRandom();
276     Eigen::Matrix<double, 18, 1> B; B.setRandom();
277     Eigen::Matrix<double, 1, 18> C; C.setRandom();
278     VERIFY_IS_APPROX(B * A.inverse(), B * A.inverse()[0]);
279     VERIFY_IS_APPROX(A.inverse() * C, A.inverse()[0] * C);
280   }
281 
282   {
283     Eigen::Matrix<double, 10, 10> A, B, C;
284     A.setRandom();
285     C = A;
286     for(int k=0; k<79; ++k)
287       C = C * A;
288     B.noalias() = (((A*A)*(A*A))*((A*A)*(A*A))*((A*A)*(A*A))*((A*A)*(A*A))*((A*A)*(A*A)) * ((A*A)*(A*A))*((A*A)*(A*A))*((A*A)*(A*A))*((A*A)*(A*A))*((A*A)*(A*A)))
289                 * (((A*A)*(A*A))*((A*A)*(A*A))*((A*A)*(A*A))*((A*A)*(A*A))*((A*A)*(A*A)) * ((A*A)*(A*A))*((A*A)*(A*A))*((A*A)*(A*A))*((A*A)*(A*A))*((A*A)*(A*A)));
290     VERIFY_IS_APPROX(B,C);
291   }
292 #endif
293 }
294