• 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 // Copyright (C) 2009 Ricard Marxer <email@ricardmarxer.com>
6 //
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/.
10 
11 #include "main.h"
12 #include <iostream>
13 
14 using namespace std;
15 
reverse(const MatrixType & m)16 template<typename MatrixType> void reverse(const MatrixType& m)
17 {
18   typedef typename MatrixType::Scalar Scalar;
19   typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
20 
21   Index rows = m.rows();
22   Index cols = m.cols();
23 
24   // this test relies a lot on Random.h, and there's not much more that we can do
25   // to test it, hence I consider that we will have tested Random.h
26   MatrixType m1 = MatrixType::Random(rows, cols), m2;
27   VectorType v1 = VectorType::Random(rows);
28 
29   MatrixType m1_r = m1.reverse();
30   // Verify that MatrixBase::reverse() works
31   for ( int i = 0; i < rows; i++ ) {
32     for ( int j = 0; j < cols; j++ ) {
33       VERIFY_IS_APPROX(m1_r(i, j), m1(rows - 1 - i, cols - 1 - j));
34     }
35   }
36 
37   Reverse<MatrixType> m1_rd(m1);
38   // Verify that a Reverse default (in both directions) of an expression works
39   for ( int i = 0; i < rows; i++ ) {
40     for ( int j = 0; j < cols; j++ ) {
41       VERIFY_IS_APPROX(m1_rd(i, j), m1(rows - 1 - i, cols - 1 - j));
42     }
43   }
44 
45   Reverse<MatrixType, BothDirections> m1_rb(m1);
46   // Verify that a Reverse in both directions of an expression works
47   for ( int i = 0; i < rows; i++ ) {
48     for ( int j = 0; j < cols; j++ ) {
49       VERIFY_IS_APPROX(m1_rb(i, j), m1(rows - 1 - i, cols - 1 - j));
50     }
51   }
52 
53   Reverse<MatrixType, Vertical> m1_rv(m1);
54   // Verify that a Reverse in the vertical directions of an expression works
55   for ( int i = 0; i < rows; i++ ) {
56     for ( int j = 0; j < cols; j++ ) {
57       VERIFY_IS_APPROX(m1_rv(i, j), m1(rows - 1 - i, j));
58     }
59   }
60 
61   Reverse<MatrixType, Horizontal> m1_rh(m1);
62   // Verify that a Reverse in the horizontal directions of an expression works
63   for ( int i = 0; i < rows; i++ ) {
64     for ( int j = 0; j < cols; j++ ) {
65       VERIFY_IS_APPROX(m1_rh(i, j), m1(i, cols - 1 - j));
66     }
67   }
68 
69   VectorType v1_r = v1.reverse();
70   // Verify that a VectorType::reverse() of an expression works
71   for ( int i = 0; i < rows; i++ ) {
72     VERIFY_IS_APPROX(v1_r(i), v1(rows - 1 - i));
73   }
74 
75   MatrixType m1_cr = m1.colwise().reverse();
76   // Verify that PartialRedux::reverse() works (for colwise())
77   for ( int i = 0; i < rows; i++ ) {
78     for ( int j = 0; j < cols; j++ ) {
79       VERIFY_IS_APPROX(m1_cr(i, j), m1(rows - 1 - i, j));
80     }
81   }
82 
83   MatrixType m1_rr = m1.rowwise().reverse();
84   // Verify that PartialRedux::reverse() works (for rowwise())
85   for ( int i = 0; i < rows; i++ ) {
86     for ( int j = 0; j < cols; j++ ) {
87       VERIFY_IS_APPROX(m1_rr(i, j), m1(i, cols - 1 - j));
88     }
89   }
90 
91   Scalar x = internal::random<Scalar>();
92 
93   Index r = internal::random<Index>(0, rows-1),
94         c = internal::random<Index>(0, cols-1);
95 
96   m1.reverse()(r, c) = x;
97   VERIFY_IS_APPROX(x, m1(rows - 1 - r, cols - 1 - c));
98 
99   m2 = m1;
100   m2.reverseInPlace();
101   VERIFY_IS_APPROX(m2,m1.reverse().eval());
102 
103   m2 = m1;
104   m2.col(0).reverseInPlace();
105   VERIFY_IS_APPROX(m2.col(0),m1.col(0).reverse().eval());
106 
107   m2 = m1;
108   m2.row(0).reverseInPlace();
109   VERIFY_IS_APPROX(m2.row(0),m1.row(0).reverse().eval());
110 
111   m2 = m1;
112   m2.rowwise().reverseInPlace();
113   VERIFY_IS_APPROX(m2,m1.rowwise().reverse().eval());
114 
115   m2 = m1;
116   m2.colwise().reverseInPlace();
117   VERIFY_IS_APPROX(m2,m1.colwise().reverse().eval());
118 
119   m1.colwise().reverse()(r, c) = x;
120   VERIFY_IS_APPROX(x, m1(rows - 1 - r, c));
121 
122   m1.rowwise().reverse()(r, c) = x;
123   VERIFY_IS_APPROX(x, m1(r, cols - 1 - c));
124 }
125 
126 template<int>
array_reverse_extra()127 void array_reverse_extra()
128 {
129   Vector4f x; x << 1, 2, 3, 4;
130   Vector4f y; y << 4, 3, 2, 1;
131   VERIFY(x.reverse()[1] == 3);
132   VERIFY(x.reverse() == y);
133 }
134 
135 // Simpler version of reverseInPlace leveraging a bug
136 // in clang 6/7 with -O2 and AVX or AVX512 enabled.
137 // This simpler version ensure that the clang bug is not simply hidden
138 // through mis-inlining of reverseInPlace or other minor changes.
139 template<typename MatrixType>
140 EIGEN_DONT_INLINE
bug1684_job1(MatrixType & m1,MatrixType & m2)141 void bug1684_job1(MatrixType& m1, MatrixType& m2)
142 {
143   m2 = m1;
144   m2.col(0).swap(m2.col(3));
145   m2.col(1).swap(m2.col(2));
146 }
147 
148 template<typename MatrixType>
149 EIGEN_DONT_INLINE
bug1684_job2(MatrixType & m1,MatrixType & m2)150 void bug1684_job2(MatrixType& m1, MatrixType& m2)
151 {
152   m2 = m1; // load m1/m2 in AVX registers
153   m1.col(0) = m2.col(3); // perform 128 bits moves
154   m1.col(1) = m2.col(2);
155   m1.col(2) = m2.col(1);
156   m1.col(3) = m2.col(0);
157 }
158 
159 template<typename MatrixType>
160 EIGEN_DONT_INLINE
bug1684_job3(MatrixType & m1,MatrixType & m2)161 void bug1684_job3(MatrixType& m1, MatrixType& m2)
162 {
163   m2 = m1;
164   Vector4f tmp;
165   tmp = m2.col(0);
166   m2.col(0) = m2.col(3);
167   m2.col(3) = tmp;
168   tmp = m2.col(1);
169   m2.col(1) = m2.col(2);
170   m2.col(2) = tmp;
171 
172 }
173 
174 template<int>
bug1684()175 void bug1684()
176 {
177   Matrix4f m1 = Matrix4f::Random();
178   Matrix4f m2 = Matrix4f::Random();
179   bug1684_job1(m1,m2);
180   VERIFY_IS_APPROX(m2, m1.rowwise().reverse().eval());
181   bug1684_job2(m1,m2);
182   VERIFY_IS_APPROX(m2, m1.rowwise().reverse().eval());
183   // This one still fail after our swap's workaround,
184   // but I expect users not to implement their own swap.
185   // bug1684_job3(m1,m2);
186   // VERIFY_IS_APPROX(m2, m1.rowwise().reverse().eval());
187 }
188 
EIGEN_DECLARE_TEST(array_reverse)189 EIGEN_DECLARE_TEST(array_reverse)
190 {
191   for(int i = 0; i < g_repeat; i++) {
192     CALL_SUBTEST_1( reverse(Matrix<float, 1, 1>()) );
193     CALL_SUBTEST_2( reverse(Matrix2f()) );
194     CALL_SUBTEST_3( reverse(Matrix4f()) );
195     CALL_SUBTEST_4( reverse(Matrix4d()) );
196     CALL_SUBTEST_5( reverse(MatrixXcf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
197     CALL_SUBTEST_6( reverse(MatrixXi(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
198     CALL_SUBTEST_7( reverse(MatrixXcd(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
199     CALL_SUBTEST_8( reverse(Matrix<float, 100, 100>()) );
200     CALL_SUBTEST_9( reverse(Matrix<float,Dynamic,Dynamic,RowMajor>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
201     CALL_SUBTEST_3( bug1684<0>() );
202   }
203   CALL_SUBTEST_3( array_reverse_extra<0>() );
204 }
205