2009-02-12 23:18:59 +08:00
// This file is part of Eigen, a lightweight C++ template library
2009-05-23 02:25:33 +08:00
// for linear algebra.
2009-02-12 23:18:59 +08:00
//
// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
2015-10-09 21:28:09 +08:00
// Copyright (C) 2015 Gael Guennebaud <gael.guennebaud@inria.fr>
2009-02-12 23:18:59 +08:00
//
2012-07-14 02:42:47 +08:00
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
2009-02-12 23:18:59 +08:00
2015-10-09 19:29:39 +08:00
# define TEST_ENABLE_TEMPORARY_TRACKING
2017-08-22 21:59:08 +08:00
# define EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD 8
// ^^ see bug 1449
2015-10-09 19:29:39 +08:00
2009-02-12 23:18:59 +08:00
# include "main.h"
template < typename MatrixType > void matrixRedux ( const MatrixType & m )
{
typedef typename MatrixType : : Scalar Scalar ;
2010-02-04 02:20:25 +08:00
typedef typename MatrixType : : RealScalar RealScalar ;
2009-02-12 23:18:59 +08:00
2010-06-20 23:37:56 +08:00
Index rows = m . rows ( ) ;
Index cols = m . cols ( ) ;
2009-02-12 23:18:59 +08:00
MatrixType m1 = MatrixType : : Random ( rows , cols ) ;
2011-08-21 07:51:15 +08:00
// The entries of m1 are uniformly distributed in [0,1], so m1.prod() is very small. This may lead to test
2015-10-28 04:37:03 +08:00
// failures if we underflow into denormals. Thus, we scale so that entries are close to 1.
2013-07-11 05:48:26 +08:00
MatrixType m1_for_prod = MatrixType : : Ones ( rows , cols ) + RealScalar ( 0.2 ) * m1 ;
2011-08-21 07:51:15 +08:00
2018-10-11 04:23:52 +08:00
Matrix < Scalar , MatrixType : : RowsAtCompileTime , MatrixType : : RowsAtCompileTime > m2 ( rows , rows ) ;
m2 . setRandom ( ) ;
2009-02-12 23:18:59 +08:00
VERIFY_IS_MUCH_SMALLER_THAN ( MatrixType : : Zero ( rows , cols ) . sum ( ) , Scalar ( 1 ) ) ;
VERIFY_IS_APPROX ( MatrixType : : Ones ( rows , cols ) . sum ( ) , Scalar ( float ( rows * cols ) ) ) ; // the float() here to shut up excessive MSVC warning about int->complex conversion being lossy
2013-06-11 05:40:56 +08:00
Scalar s ( 0 ) , p ( 1 ) , minc ( numext : : real ( m1 . coeff ( 0 ) ) ) , maxc ( numext : : real ( m1 . coeff ( 0 ) ) ) ;
2009-02-12 23:18:59 +08:00
for ( int j = 0 ; j < cols ; j + + )
for ( int i = 0 ; i < rows ; i + + )
{
s + = m1 ( i , j ) ;
2011-08-21 07:51:15 +08:00
p * = m1_for_prod ( i , j ) ;
2013-06-11 05:40:56 +08:00
minc = ( std : : min ) ( numext : : real ( minc ) , numext : : real ( m1 ( i , j ) ) ) ;
maxc = ( std : : max ) ( numext : : real ( maxc ) , numext : : real ( m1 ( i , j ) ) ) ;
2009-02-12 23:18:59 +08:00
}
2010-02-04 02:20:25 +08:00
const Scalar mean = s / Scalar ( RealScalar ( rows * cols ) ) ;
2010-01-29 19:12:02 +08:00
2009-02-12 23:18:59 +08:00
VERIFY_IS_APPROX ( m1 . sum ( ) , s ) ;
2010-01-29 19:12:02 +08:00
VERIFY_IS_APPROX ( m1 . mean ( ) , mean ) ;
2011-08-21 07:51:15 +08:00
VERIFY_IS_APPROX ( m1_for_prod . prod ( ) , p ) ;
2013-06-11 05:40:56 +08:00
VERIFY_IS_APPROX ( m1 . real ( ) . minCoeff ( ) , numext : : real ( minc ) ) ;
VERIFY_IS_APPROX ( m1 . real ( ) . maxCoeff ( ) , numext : : real ( maxc ) ) ;
2018-10-11 04:23:52 +08:00
// test that partial reduction works if nested expressions is forced to evaluate early
VERIFY_IS_APPROX ( ( m1 . matrix ( ) * m1 . matrix ( ) . transpose ( ) ) . cwiseProduct ( m2 . matrix ( ) ) . rowwise ( ) . sum ( ) . sum ( ) ,
( m1 . matrix ( ) * m1 . matrix ( ) . transpose ( ) ) . eval ( ) . cwiseProduct ( m2 . matrix ( ) ) . rowwise ( ) . sum ( ) . sum ( ) ) ;
2010-05-14 05:34:04 +08:00
2010-06-21 00:59:15 +08:00
// test slice vectorization assuming assign is ok
2010-10-25 22:15:22 +08:00
Index r0 = internal : : random < Index > ( 0 , rows - 1 ) ;
Index c0 = internal : : random < Index > ( 0 , cols - 1 ) ;
Index r1 = internal : : random < Index > ( r0 + 1 , rows ) - r0 ;
Index c1 = internal : : random < Index > ( c0 + 1 , cols ) - c0 ;
2010-05-14 05:34:04 +08:00
VERIFY_IS_APPROX ( m1 . block ( r0 , c0 , r1 , c1 ) . sum ( ) , m1 . block ( r0 , c0 , r1 , c1 ) . eval ( ) . sum ( ) ) ;
VERIFY_IS_APPROX ( m1 . block ( r0 , c0 , r1 , c1 ) . mean ( ) , m1 . block ( r0 , c0 , r1 , c1 ) . eval ( ) . mean ( ) ) ;
2011-08-21 07:51:15 +08:00
VERIFY_IS_APPROX ( m1_for_prod . block ( r0 , c0 , r1 , c1 ) . prod ( ) , m1_for_prod . block ( r0 , c0 , r1 , c1 ) . eval ( ) . prod ( ) ) ;
2010-05-14 05:34:04 +08:00
VERIFY_IS_APPROX ( m1 . block ( r0 , c0 , r1 , c1 ) . real ( ) . minCoeff ( ) , m1 . block ( r0 , c0 , r1 , c1 ) . real ( ) . eval ( ) . minCoeff ( ) ) ;
VERIFY_IS_APPROX ( m1 . block ( r0 , c0 , r1 , c1 ) . real ( ) . maxCoeff ( ) , m1 . block ( r0 , c0 , r1 , c1 ) . real ( ) . eval ( ) . maxCoeff ( ) ) ;
2015-10-22 02:58:33 +08:00
// regression for bug 1090
const int R1 = MatrixType : : RowsAtCompileTime > = 2 ? MatrixType : : RowsAtCompileTime / 2 : 6 ;
const int C1 = MatrixType : : ColsAtCompileTime > = 2 ? MatrixType : : ColsAtCompileTime / 2 : 6 ;
if ( R1 < = rows - r0 & & C1 < = cols - c0 )
{
VERIFY_IS_APPROX ( ( m1 . template block < R1 , C1 > ( r0 , c0 ) . sum ( ) ) , m1 . block ( r0 , c0 , R1 , C1 ) . sum ( ) ) ;
}
2010-07-16 20:02:20 +08:00
// test empty objects
VERIFY_IS_APPROX ( m1 . block ( r0 , c0 , 0 , 0 ) . sum ( ) , Scalar ( 0 ) ) ;
VERIFY_IS_APPROX ( m1 . block ( r0 , c0 , 0 , 0 ) . prod ( ) , Scalar ( 1 ) ) ;
2015-10-09 19:29:39 +08:00
// test nesting complex expression
2017-02-19 17:32:54 +08:00
VERIFY_EVALUATION_COUNT ( ( m1 . matrix ( ) * m1 . matrix ( ) . transpose ( ) ) . sum ( ) , ( MatrixType : : IsVectorAtCompileTime & & MatrixType : : SizeAtCompileTime ! = 1 ? 0 : 1 ) ) ;
VERIFY_EVALUATION_COUNT ( ( ( m1 . matrix ( ) * m1 . matrix ( ) . transpose ( ) ) + m2 ) . sum ( ) , ( MatrixType : : IsVectorAtCompileTime & & MatrixType : : SizeAtCompileTime ! = 1 ? 0 : 1 ) ) ;
2009-02-12 23:18:59 +08:00
}
template < typename VectorType > void vectorRedux ( const VectorType & w )
{
2012-11-06 22:25:50 +08:00
using std : : abs ;
2009-02-12 23:18:59 +08:00
typedef typename VectorType : : Scalar Scalar ;
typedef typename NumTraits < Scalar > : : Real RealScalar ;
2010-06-21 02:16:45 +08:00
Index size = w . size ( ) ;
2009-02-12 23:18:59 +08:00
VectorType v = VectorType : : Random ( size ) ;
2011-08-21 07:51:15 +08:00
VectorType v_for_prod = VectorType : : Ones ( size ) + Scalar ( 0.2 ) * v ; // see comment above declaration of m1_for_prod
2009-02-12 23:18:59 +08:00
for ( int i = 1 ; i < size ; i + + )
{
Scalar s ( 0 ) , p ( 1 ) ;
2013-06-11 05:40:56 +08:00
RealScalar minc ( numext : : real ( v . coeff ( 0 ) ) ) , maxc ( numext : : real ( v . coeff ( 0 ) ) ) ;
2009-02-12 23:18:59 +08:00
for ( int j = 0 ; j < i ; j + + )
{
s + = v [ j ] ;
2011-08-21 07:51:15 +08:00
p * = v_for_prod [ j ] ;
2013-06-11 05:40:56 +08:00
minc = ( std : : min ) ( minc , numext : : real ( v [ j ] ) ) ;
maxc = ( std : : max ) ( maxc , numext : : real ( v [ j ] ) ) ;
2009-02-12 23:18:59 +08:00
}
2012-11-06 22:25:50 +08:00
VERIFY_IS_MUCH_SMALLER_THAN ( abs ( s - v . head ( i ) . sum ( ) ) , Scalar ( 1 ) ) ;
2011-08-21 07:51:15 +08:00
VERIFY_IS_APPROX ( p , v_for_prod . head ( i ) . prod ( ) ) ;
2010-01-05 10:24:43 +08:00
VERIFY_IS_APPROX ( minc , v . real ( ) . head ( i ) . minCoeff ( ) ) ;
VERIFY_IS_APPROX ( maxc , v . real ( ) . head ( i ) . maxCoeff ( ) ) ;
2009-02-12 23:18:59 +08:00
}
for ( int i = 0 ; i < size - 1 ; i + + )
{
Scalar s ( 0 ) , p ( 1 ) ;
2013-06-11 05:40:56 +08:00
RealScalar minc ( numext : : real ( v . coeff ( i ) ) ) , maxc ( numext : : real ( v . coeff ( i ) ) ) ;
2009-02-12 23:18:59 +08:00
for ( int j = i ; j < size ; j + + )
{
s + = v [ j ] ;
2011-08-21 07:51:15 +08:00
p * = v_for_prod [ j ] ;
2013-06-11 05:40:56 +08:00
minc = ( std : : min ) ( minc , numext : : real ( v [ j ] ) ) ;
maxc = ( std : : max ) ( maxc , numext : : real ( v [ j ] ) ) ;
2009-02-12 23:18:59 +08:00
}
2012-11-06 22:25:50 +08:00
VERIFY_IS_MUCH_SMALLER_THAN ( abs ( s - v . tail ( size - i ) . sum ( ) ) , Scalar ( 1 ) ) ;
2011-08-21 07:51:15 +08:00
VERIFY_IS_APPROX ( p , v_for_prod . tail ( size - i ) . prod ( ) ) ;
2010-01-05 10:24:43 +08:00
VERIFY_IS_APPROX ( minc , v . real ( ) . tail ( size - i ) . minCoeff ( ) ) ;
VERIFY_IS_APPROX ( maxc , v . real ( ) . tail ( size - i ) . maxCoeff ( ) ) ;
2009-02-12 23:18:59 +08:00
}
for ( int i = 0 ; i < size / 2 ; i + + )
{
Scalar s ( 0 ) , p ( 1 ) ;
2013-06-11 05:40:56 +08:00
RealScalar minc ( numext : : real ( v . coeff ( i ) ) ) , maxc ( numext : : real ( v . coeff ( i ) ) ) ;
2009-02-12 23:18:59 +08:00
for ( int j = i ; j < size - i ; j + + )
{
s + = v [ j ] ;
2011-08-21 07:51:15 +08:00
p * = v_for_prod [ j ] ;
2013-06-11 05:40:56 +08:00
minc = ( std : : min ) ( minc , numext : : real ( v [ j ] ) ) ;
maxc = ( std : : max ) ( maxc , numext : : real ( v [ j ] ) ) ;
2009-02-12 23:18:59 +08:00
}
2012-11-06 22:25:50 +08:00
VERIFY_IS_MUCH_SMALLER_THAN ( abs ( s - v . segment ( i , size - 2 * i ) . sum ( ) ) , Scalar ( 1 ) ) ;
2011-08-21 07:51:15 +08:00
VERIFY_IS_APPROX ( p , v_for_prod . segment ( i , size - 2 * i ) . prod ( ) ) ;
2009-02-12 23:18:59 +08:00
VERIFY_IS_APPROX ( minc , v . real ( ) . segment ( i , size - 2 * i ) . minCoeff ( ) ) ;
VERIFY_IS_APPROX ( maxc , v . real ( ) . segment ( i , size - 2 * i ) . maxCoeff ( ) ) ;
}
2010-07-16 20:02:20 +08:00
// test empty objects
VERIFY_IS_APPROX ( v . head ( 0 ) . sum ( ) , Scalar ( 0 ) ) ;
VERIFY_IS_APPROX ( v . tail ( 0 ) . prod ( ) , Scalar ( 1 ) ) ;
VERIFY_RAISES_ASSERT ( v . head ( 0 ) . mean ( ) ) ;
VERIFY_RAISES_ASSERT ( v . head ( 0 ) . minCoeff ( ) ) ;
VERIFY_RAISES_ASSERT ( v . head ( 0 ) . maxCoeff ( ) ) ;
2009-02-12 23:18:59 +08:00
}
2018-07-17 20:46:15 +08:00
EIGEN_DECLARE_TEST ( redux )
2009-02-12 23:18:59 +08:00
{
2011-07-12 20:41:00 +08:00
// the max size cannot be too large, otherwise reduxion operations obviously generate large errors.
2011-08-19 20:18:05 +08:00
int maxsize = ( std : : min ) ( 100 , EIGEN_TEST_MAX_SIZE ) ;
2013-06-25 17:42:04 +08:00
TEST_SET_BUT_UNUSED_VARIABLE ( maxsize ) ;
2009-02-12 23:18:59 +08:00
for ( int i = 0 ; i < g_repeat ; i + + ) {
2009-10-29 06:19:29 +08:00
CALL_SUBTEST_1 ( matrixRedux ( Matrix < float , 1 , 1 > ( ) ) ) ;
2010-01-29 19:12:02 +08:00
CALL_SUBTEST_1 ( matrixRedux ( Array < float , 1 , 1 > ( ) ) ) ;
2009-10-29 06:19:29 +08:00
CALL_SUBTEST_2 ( matrixRedux ( Matrix2f ( ) ) ) ;
2010-01-29 19:12:02 +08:00
CALL_SUBTEST_2 ( matrixRedux ( Array2f ( ) ) ) ;
2017-02-19 17:32:54 +08:00
CALL_SUBTEST_2 ( matrixRedux ( Array22f ( ) ) ) ;
2009-10-29 06:19:29 +08:00
CALL_SUBTEST_3 ( matrixRedux ( Matrix4d ( ) ) ) ;
2010-01-29 19:12:02 +08:00
CALL_SUBTEST_3 ( matrixRedux ( Array4d ( ) ) ) ;
2017-02-19 17:32:54 +08:00
CALL_SUBTEST_3 ( matrixRedux ( Array44d ( ) ) ) ;
2011-07-12 20:41:00 +08:00
CALL_SUBTEST_4 ( matrixRedux ( MatrixXcf ( internal : : random < int > ( 1 , maxsize ) , internal : : random < int > ( 1 , maxsize ) ) ) ) ;
CALL_SUBTEST_4 ( matrixRedux ( ArrayXXcf ( internal : : random < int > ( 1 , maxsize ) , internal : : random < int > ( 1 , maxsize ) ) ) ) ;
CALL_SUBTEST_5 ( matrixRedux ( MatrixXd ( internal : : random < int > ( 1 , maxsize ) , internal : : random < int > ( 1 , maxsize ) ) ) ) ;
CALL_SUBTEST_5 ( matrixRedux ( ArrayXXd ( internal : : random < int > ( 1 , maxsize ) , internal : : random < int > ( 1 , maxsize ) ) ) ) ;
CALL_SUBTEST_6 ( matrixRedux ( MatrixXi ( internal : : random < int > ( 1 , maxsize ) , internal : : random < int > ( 1 , maxsize ) ) ) ) ;
CALL_SUBTEST_6 ( matrixRedux ( ArrayXXi ( internal : : random < int > ( 1 , maxsize ) , internal : : random < int > ( 1 , maxsize ) ) ) ) ;
2009-02-12 23:18:59 +08:00
}
for ( int i = 0 ; i < g_repeat ; i + + ) {
2009-10-29 06:19:29 +08:00
CALL_SUBTEST_7 ( vectorRedux ( Vector4f ( ) ) ) ;
2010-01-29 19:12:02 +08:00
CALL_SUBTEST_7 ( vectorRedux ( Array4f ( ) ) ) ;
2011-07-12 20:41:00 +08:00
CALL_SUBTEST_5 ( vectorRedux ( VectorXd ( internal : : random < int > ( 1 , maxsize ) ) ) ) ;
CALL_SUBTEST_5 ( vectorRedux ( ArrayXd ( internal : : random < int > ( 1 , maxsize ) ) ) ) ;
CALL_SUBTEST_8 ( vectorRedux ( VectorXf ( internal : : random < int > ( 1 , maxsize ) ) ) ) ;
CALL_SUBTEST_8 ( vectorRedux ( ArrayXf ( internal : : random < int > ( 1 , maxsize ) ) ) ) ;
2009-02-12 23:18:59 +08:00
}
}