1 // This file is part of Eigen, a lightweight C++ template library
4 // Copyright (C) 2010-2011 Jitse Niesen <jitse@maths.leeds.ac.uk>
5 // Copyright (C) 2016 Gael Guennebaud <gael.guennebaud@inria.fr>
7 // This Source Code Form is subject to the terms of the Mozilla
8 // Public License v. 2.0. If a copy of the MPL was not distributed
9 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
13 template<typename MatrixType
>
14 bool equalsIdentity(const MatrixType
& A
)
16 typedef typename
MatrixType::Scalar Scalar
;
17 Scalar zero
= static_cast<Scalar
>(0);
19 bool offDiagOK
= true;
20 for (Index i
= 0; i
< A
.rows(); ++i
) {
21 for (Index j
= i
+1; j
< A
.cols(); ++j
) {
22 offDiagOK
= offDiagOK
&& (A(i
,j
) == zero
);
25 for (Index i
= 0; i
< A
.rows(); ++i
) {
26 for (Index j
= 0; j
< (std::min
)(i
, A
.cols()); ++j
) {
27 offDiagOK
= offDiagOK
&& (A(i
,j
) == zero
);
31 bool diagOK
= (A
.diagonal().array() == 1).all();
32 return offDiagOK
&& diagOK
;
36 template<typename VectorType
>
37 void check_extremity_accuracy(const VectorType
&v
, const typename
VectorType::Scalar
&low
, const typename
VectorType::Scalar
&high
)
39 typedef typename
VectorType::Scalar Scalar
;
40 typedef typename
VectorType::RealScalar RealScalar
;
42 RealScalar prec
= internal::is_same
<RealScalar
,float>::value
? NumTraits
<RealScalar
>::dummy_precision()*10 : NumTraits
<RealScalar
>::dummy_precision()/10;
43 Index size
= v
.size();
48 for (int i
=0; i
<size
; ++i
)
52 Scalar ref
= (low
*RealScalar(size
-i
-1))/RealScalar(size
-1) + (high
*RealScalar(i
))/RealScalar(size
-1);
55 if(!internal::isApprox(v(i
), ref
, prec
))
56 std::cout
<< v(i
) << " != " << ref
<< " ; relative error: " << std::abs((v(i
)-ref
)/ref
) << " ; required precision: " << prec
<< " ; range: " << low
<< "," << high
<< " ; i: " << i
<< "\n";
57 VERIFY(internal::isApprox(v(i
), (low
*RealScalar(size
-i
-1))/RealScalar(size
-1) + (high
*RealScalar(i
))/RealScalar(size
-1), prec
));
63 template<typename VectorType
>
64 void testVectorType(const VectorType
& base
)
66 typedef typename
VectorType::Scalar Scalar
;
67 typedef typename
VectorType::RealScalar RealScalar
;
69 const Index size
= base
.size();
71 Scalar high
= internal::random
<Scalar
>(-500,500);
72 Scalar low
= (size
== 1 ? high
: internal::random
<Scalar
>(-500,500));
73 if (low
>high
) std::swap(low
,high
);
76 if(internal::random
<float>(0.f
,1.f
)<0.05f
)
78 // check abs(low) >> abs(high)
79 else if(size
>2 && std::numeric_limits
<RealScalar
>::max_exponent10
>0 && internal::random
<float>(0.f
,1.f
)<0.1f
)
80 low
= -internal::random
<Scalar
>(1,2) * RealScalar(std::pow(RealScalar(10),std::numeric_limits
<RealScalar
>::max_exponent10
/2));
82 const Scalar step
= ((size
== 1) ? 1 : (high
-low
)/(size
-1));
84 // check whether the result yields what we expect it to do
86 m
.setLinSpaced(size
,low
,high
);
88 if(!NumTraits
<Scalar
>::IsInteger
)
91 for (int i
=0; i
<size
; ++i
)
93 VERIFY_IS_APPROX(m
,n
);
95 CALL_SUBTEST( check_extremity_accuracy(m
, low
, high
) );
98 if((!NumTraits
<Scalar
>::IsInteger
) || ((high
-low
)>=size
&& (Index(high
-low
)%(size
-1))==0) || (Index(high
-low
+1)<size
&& (size
%Index(high
-low
+1))==0))
101 if((!NumTraits
<Scalar
>::IsInteger
) || (high
-low
>=size
))
102 for (int i
=0; i
<size
; ++i
)
103 n(i
) = size
==1 ? low
: (low
+ ((high
-low
)*Scalar(i
))/(size
-1));
105 for (int i
=0; i
<size
; ++i
)
106 n(i
) = size
==1 ? low
: low
+ Scalar((double(high
-low
+1)*double(i
))/double(size
));
107 VERIFY_IS_APPROX(m
,n
);
109 // random access version
110 m
= VectorType::LinSpaced(size
,low
,high
);
111 VERIFY_IS_APPROX(m
,n
);
112 VERIFY( internal::isApprox(m(m
.size()-1),high
) );
113 VERIFY( size
==1 || internal::isApprox(m(0),low
) );
114 VERIFY_IS_EQUAL(m(m
.size()-1) , high
);
115 if(!NumTraits
<Scalar
>::IsInteger
)
116 CALL_SUBTEST( check_extremity_accuracy(m
, low
, high
) );
119 VERIFY( m(m
.size()-1) <= high
);
120 VERIFY( (m
.array() <= high
).all() );
121 VERIFY( (m
.array() >= low
).all() );
124 VERIFY( m(m
.size()-1) >= low
);
127 VERIFY( internal::isApprox(m(0),low
) );
128 VERIFY_IS_EQUAL(m(0) , low
);
131 // check whether everything works with row and col major vectors
132 Matrix
<Scalar
,Dynamic
,1> row_vector(size
);
133 Matrix
<Scalar
,1,Dynamic
> col_vector(size
);
134 row_vector
.setLinSpaced(size
,low
,high
);
135 col_vector
.setLinSpaced(size
,low
,high
);
136 // when using the extended precision (e.g., FPU) the relative error might exceed 1 bit
137 // when computing the squared sum in isApprox, thus the 2x factor.
138 VERIFY( row_vector
.isApprox(col_vector
.transpose(), Scalar(2)*NumTraits
<Scalar
>::epsilon()));
140 Matrix
<Scalar
,Dynamic
,1> size_changer(size
+50);
141 size_changer
.setLinSpaced(size
,low
,high
);
142 VERIFY( size_changer
.size() == size
);
144 typedef Matrix
<Scalar
,1,1> ScalarMatrix
;
146 scalar
.setLinSpaced(1,low
,high
);
147 VERIFY_IS_APPROX( scalar
, ScalarMatrix::Constant(high
) );
148 VERIFY_IS_APPROX( ScalarMatrix::LinSpaced(1,low
,high
), ScalarMatrix::Constant(high
) );
150 // regression test for bug 526 (linear vectorized transversal)
151 if (size
> 1 && (!NumTraits
<Scalar
>::IsInteger
)) {
152 m
.tail(size
-1).setLinSpaced(low
, high
);
153 VERIFY_IS_APPROX(m(size
-1), high
);
156 // regression test for bug 1383 (LinSpaced with empty size/range)
158 Index n0
= VectorType::SizeAtCompileTime
==Dynamic
? 0 : VectorType::SizeAtCompileTime
;
159 low
= internal::random
<Scalar
>();
160 m
= VectorType::LinSpaced(n0
,low
,low
-1);
161 VERIFY(m
.size()==n0
);
163 if(VectorType::SizeAtCompileTime
==Dynamic
)
165 VERIFY_IS_EQUAL(VectorType::LinSpaced(n0
,0,Scalar(n0
-1)).sum(),Scalar(0));
166 VERIFY_IS_EQUAL(VectorType::LinSpaced(n0
,low
,low
-1).sum(),Scalar(0));
169 m
.setLinSpaced(n0
,0,Scalar(n0
-1));
170 VERIFY(m
.size()==n0
);
171 m
.setLinSpaced(n0
,low
,low
-1);
172 VERIFY(m
.size()==n0
);
175 VERIFY_IS_APPROX(VectorType::LinSpaced(size
,low
,low
),VectorType::Constant(size
,low
));
176 m
.setLinSpaced(size
,low
,low
);
177 VERIFY_IS_APPROX(m
,VectorType::Constant(size
,low
));
179 if(NumTraits
<Scalar
>::IsInteger
)
181 VERIFY_IS_APPROX( VectorType::LinSpaced(size
,low
,Scalar(low
+size
-1)), VectorType::LinSpaced(size
,Scalar(low
+size
-1),low
).reverse() );
183 if(VectorType::SizeAtCompileTime
==Dynamic
)
185 // Check negative multiplicator path:
186 for(Index k
=1; k
<5; ++k
)
187 VERIFY_IS_APPROX( VectorType::LinSpaced(size
,low
,Scalar(low
+(size
-1)*k
)), VectorType::LinSpaced(size
,Scalar(low
+(size
-1)*k
),low
).reverse() );
188 // Check negative divisor path:
189 for(Index k
=1; k
<5; ++k
)
190 VERIFY_IS_APPROX( VectorType::LinSpaced(size
*k
,low
,Scalar(low
+size
-1)), VectorType::LinSpaced(size
*k
,Scalar(low
+size
-1),low
).reverse() );
196 template<typename MatrixType
>
197 void testMatrixType(const MatrixType
& m
)
200 const Index rows
= m
.rows();
201 const Index cols
= m
.cols();
202 typedef typename
MatrixType::Scalar Scalar
;
203 typedef typename
MatrixType::RealScalar RealScalar
;
207 s1
= internal::random
<Scalar
>();
208 } while(abs(s1
)<RealScalar(1e-5) && (!NumTraits
<Scalar
>::IsInteger
));
211 A
.setIdentity(rows
, cols
);
212 VERIFY(equalsIdentity(A
));
213 VERIFY(equalsIdentity(MatrixType::Identity(rows
, cols
)));
216 A
= MatrixType::Constant(rows
,cols
,s1
);
217 Index i
= internal::random
<Index
>(0,rows
-1);
218 Index j
= internal::random
<Index
>(0,cols
-1);
219 VERIFY_IS_APPROX( MatrixType::Constant(rows
,cols
,s1
)(i
,j
), s1
);
220 VERIFY_IS_APPROX( MatrixType::Constant(rows
,cols
,s1
).coeff(i
,j
), s1
);
221 VERIFY_IS_APPROX( A(i
,j
), s1
);
226 CALL_SUBTEST_1( testMatrixType(Matrix2d()) );
227 CALL_SUBTEST_2( testMatrixType(MatrixXcf(internal::random
<int>(1,300),internal::random
<int>(1,300))) );
228 CALL_SUBTEST_3( testMatrixType(MatrixXf(internal::random
<int>(1,300),internal::random
<int>(1,300))) );
230 for(int i
= 0; i
< g_repeat
*10; i
++) {
231 CALL_SUBTEST_4( testVectorType(VectorXd(internal::random
<int>(1,30000))) );
232 CALL_SUBTEST_5( testVectorType(Vector4d()) ); // regression test for bug 232
233 CALL_SUBTEST_6( testVectorType(Vector3d()) );
234 CALL_SUBTEST_7( testVectorType(VectorXf(internal::random
<int>(1,30000))) );
235 CALL_SUBTEST_8( testVectorType(Vector3f()) );
236 CALL_SUBTEST_8( testVectorType(Vector4f()) );
237 CALL_SUBTEST_8( testVectorType(Matrix
<float,8,1>()) );
238 CALL_SUBTEST_8( testVectorType(Matrix
<float,1,1>()) );
240 CALL_SUBTEST_9( testVectorType(VectorXi(internal::random
<int>(1,10))) );
241 CALL_SUBTEST_9( testVectorType(VectorXi(internal::random
<int>(9,300))) );
242 CALL_SUBTEST_9( testVectorType(Matrix
<int,1,1>()) );
245 #ifdef EIGEN_TEST_PART_6
246 // Assignment of a RowVectorXd to a MatrixXd (regression test for bug #79).
247 VERIFY( (MatrixXd(RowVectorXd::LinSpaced(3, 0, 1)) - RowVector3d(0, 0.5, 1)).norm() < std::numeric_limits
<double>::epsilon() );
250 #ifdef EIGEN_TEST_PART_9
251 // Check possible overflow issue
254 ArrayXi
a1(n
), a2(n
);
255 a1
.setLinSpaced(n
, 0, n
-1);
256 for(int i
=0; i
<n
; ++i
)
258 VERIFY_IS_APPROX(a1
,a2
);
262 #ifdef EIGEN_TEST_PART_10
263 // check some internal logic
264 VERIFY(( internal::has_nullary_operator
<internal::scalar_constant_op
<double> >::value
));
265 VERIFY(( !internal::has_unary_operator
<internal::scalar_constant_op
<double> >::value
));
266 VERIFY(( !internal::has_binary_operator
<internal::scalar_constant_op
<double> >::value
));
267 VERIFY(( internal::functor_has_linear_access
<internal::scalar_constant_op
<double> >::ret
));
269 VERIFY(( !internal::has_nullary_operator
<internal::scalar_identity_op
<double> >::value
));
270 VERIFY(( !internal::has_unary_operator
<internal::scalar_identity_op
<double> >::value
));
271 VERIFY(( internal::has_binary_operator
<internal::scalar_identity_op
<double> >::value
));
272 VERIFY(( !internal::functor_has_linear_access
<internal::scalar_identity_op
<double> >::ret
));
274 VERIFY(( !internal::has_nullary_operator
<internal::linspaced_op
<float,float> >::value
));
275 VERIFY(( internal::has_unary_operator
<internal::linspaced_op
<float,float> >::value
));
276 VERIFY(( !internal::has_binary_operator
<internal::linspaced_op
<float,float> >::value
));
277 VERIFY(( internal::functor_has_linear_access
<internal::linspaced_op
<float,float> >::ret
));
279 // Regression unit test for a weird MSVC bug.
280 // Search "nullary_wrapper_workaround_msvc" in CoreEvaluators.h for the details.
281 // See also traits<Ref>::match.
283 MatrixXf A
= MatrixXf::Random(3,3);
284 Ref
<const MatrixXf
> R
= 2.0*A
;
285 VERIFY_IS_APPROX(R
, A
+A
);
287 Ref
<const MatrixXf
> R1
= MatrixXf::Random(3,3)+A
;
289 VectorXi V
= VectorXi::Random(3);
290 Ref
<const VectorXi
> R2
= VectorXi::LinSpaced(3,1,3)+V
;
291 VERIFY_IS_APPROX(R2
, V
+Vector3i(1,2,3));
293 VERIFY(( internal::has_nullary_operator
<internal::scalar_constant_op
<float> >::value
));
294 VERIFY(( !internal::has_unary_operator
<internal::scalar_constant_op
<float> >::value
));
295 VERIFY(( !internal::has_binary_operator
<internal::scalar_constant_op
<float> >::value
));
296 VERIFY(( internal::functor_has_linear_access
<internal::scalar_constant_op
<float> >::ret
));
298 VERIFY(( !internal::has_nullary_operator
<internal::linspaced_op
<int,int> >::value
));
299 VERIFY(( internal::has_unary_operator
<internal::linspaced_op
<int,int> >::value
));
300 VERIFY(( !internal::has_binary_operator
<internal::linspaced_op
<int,int> >::value
));
301 VERIFY(( internal::functor_has_linear_access
<internal::linspaced_op
<int,int> >::ret
));