Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 1 | // This file is part of Eigen, a lightweight C++ template library |
| 2 | // for linear algebra. |
| 3 | // |
| 4 | // Copyright (C) 2009 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 | |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 10 | #define TEST_ENABLE_TEMPORARY_TRACKING |
| 11 | |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 12 | #include "main.h" |
| 13 | |
| 14 | using namespace std; |
| 15 | template<typename MatrixType> void permutationmatrices(const MatrixType& m) |
| 16 | { |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 17 | typedef typename MatrixType::Scalar Scalar; |
| 18 | enum { Rows = MatrixType::RowsAtCompileTime, Cols = MatrixType::ColsAtCompileTime, |
| 19 | Options = MatrixType::Options }; |
| 20 | typedef PermutationMatrix<Rows> LeftPermutationType; |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 21 | typedef Transpositions<Rows> LeftTranspositionsType; |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 22 | typedef Matrix<int, Rows, 1> LeftPermutationVectorType; |
| 23 | typedef Map<LeftPermutationType> MapLeftPerm; |
| 24 | typedef PermutationMatrix<Cols> RightPermutationType; |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 25 | typedef Transpositions<Cols> RightTranspositionsType; |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 26 | typedef Matrix<int, Cols, 1> RightPermutationVectorType; |
| 27 | typedef Map<RightPermutationType> MapRightPerm; |
| 28 | |
| 29 | Index rows = m.rows(); |
| 30 | Index cols = m.cols(); |
| 31 | |
| 32 | MatrixType m_original = MatrixType::Random(rows,cols); |
| 33 | LeftPermutationVectorType lv; |
| 34 | randomPermutationVector(lv, rows); |
| 35 | LeftPermutationType lp(lv); |
| 36 | RightPermutationVectorType rv; |
| 37 | randomPermutationVector(rv, cols); |
| 38 | RightPermutationType rp(rv); |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 39 | LeftTranspositionsType lt(lv); |
| 40 | RightTranspositionsType rt(rv); |
| 41 | MatrixType m_permuted = MatrixType::Random(rows,cols); |
| 42 | |
| 43 | VERIFY_EVALUATION_COUNT(m_permuted = lp * m_original * rp, 1); // 1 temp for sub expression "lp * m_original" |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 44 | |
| 45 | for (int i=0; i<rows; i++) |
| 46 | for (int j=0; j<cols; j++) |
| 47 | VERIFY_IS_APPROX(m_permuted(lv(i),j), m_original(i,rv(j))); |
| 48 | |
| 49 | Matrix<Scalar,Rows,Rows> lm(lp); |
| 50 | Matrix<Scalar,Cols,Cols> rm(rp); |
| 51 | |
| 52 | VERIFY_IS_APPROX(m_permuted, lm*m_original*rm); |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 53 | |
| 54 | m_permuted = m_original; |
| 55 | VERIFY_EVALUATION_COUNT(m_permuted = lp * m_permuted * rp, 1); |
| 56 | VERIFY_IS_APPROX(m_permuted, lm*m_original*rm); |
| 57 | |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 58 | VERIFY_IS_APPROX(lp.inverse()*m_permuted*rp.inverse(), m_original); |
| 59 | VERIFY_IS_APPROX(lv.asPermutation().inverse()*m_permuted*rv.asPermutation().inverse(), m_original); |
| 60 | VERIFY_IS_APPROX(MapLeftPerm(lv.data(),lv.size()).inverse()*m_permuted*MapRightPerm(rv.data(),rv.size()).inverse(), m_original); |
| 61 | |
| 62 | VERIFY((lp*lp.inverse()).toDenseMatrix().isIdentity()); |
| 63 | VERIFY((lv.asPermutation()*lv.asPermutation().inverse()).toDenseMatrix().isIdentity()); |
| 64 | VERIFY((MapLeftPerm(lv.data(),lv.size())*MapLeftPerm(lv.data(),lv.size()).inverse()).toDenseMatrix().isIdentity()); |
| 65 | |
| 66 | LeftPermutationVectorType lv2; |
| 67 | randomPermutationVector(lv2, rows); |
| 68 | LeftPermutationType lp2(lv2); |
| 69 | Matrix<Scalar,Rows,Rows> lm2(lp2); |
| 70 | VERIFY_IS_APPROX((lp*lp2).toDenseMatrix().template cast<Scalar>(), lm*lm2); |
| 71 | VERIFY_IS_APPROX((lv.asPermutation()*lv2.asPermutation()).toDenseMatrix().template cast<Scalar>(), lm*lm2); |
| 72 | VERIFY_IS_APPROX((MapLeftPerm(lv.data(),lv.size())*MapLeftPerm(lv2.data(),lv2.size())).toDenseMatrix().template cast<Scalar>(), lm*lm2); |
| 73 | |
| 74 | LeftPermutationType identityp; |
| 75 | identityp.setIdentity(rows); |
| 76 | VERIFY_IS_APPROX(m_original, identityp*m_original); |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 77 | |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 78 | // check inplace permutations |
| 79 | m_permuted = m_original; |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 80 | VERIFY_EVALUATION_COUNT(m_permuted.noalias()= lp.inverse() * m_permuted, 1); // 1 temp to allocate the mask |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 81 | VERIFY_IS_APPROX(m_permuted, lp.inverse()*m_original); |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 82 | |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 83 | m_permuted = m_original; |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 84 | VERIFY_EVALUATION_COUNT(m_permuted.noalias() = m_permuted * rp.inverse(), 1); // 1 temp to allocate the mask |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 85 | VERIFY_IS_APPROX(m_permuted, m_original*rp.inverse()); |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 86 | |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 87 | m_permuted = m_original; |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 88 | VERIFY_EVALUATION_COUNT(m_permuted.noalias() = lp * m_permuted, 1); // 1 temp to allocate the mask |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 89 | VERIFY_IS_APPROX(m_permuted, lp*m_original); |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 90 | |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 91 | m_permuted = m_original; |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 92 | VERIFY_EVALUATION_COUNT(m_permuted.noalias() = m_permuted * rp, 1); // 1 temp to allocate the mask |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 93 | VERIFY_IS_APPROX(m_permuted, m_original*rp); |
| 94 | |
| 95 | if(rows>1 && cols>1) |
| 96 | { |
| 97 | lp2 = lp; |
| 98 | Index i = internal::random<Index>(0, rows-1); |
| 99 | Index j; |
| 100 | do j = internal::random<Index>(0, rows-1); while(j==i); |
| 101 | lp2.applyTranspositionOnTheLeft(i, j); |
| 102 | lm = lp; |
| 103 | lm.row(i).swap(lm.row(j)); |
| 104 | VERIFY_IS_APPROX(lm, lp2.toDenseMatrix().template cast<Scalar>()); |
| 105 | |
| 106 | RightPermutationType rp2 = rp; |
| 107 | i = internal::random<Index>(0, cols-1); |
| 108 | do j = internal::random<Index>(0, cols-1); while(j==i); |
| 109 | rp2.applyTranspositionOnTheRight(i, j); |
| 110 | rm = rp; |
| 111 | rm.col(i).swap(rm.col(j)); |
| 112 | VERIFY_IS_APPROX(rm, rp2.toDenseMatrix().template cast<Scalar>()); |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 113 | } |
| 114 | |
| 115 | { |
| 116 | // simple compilation check |
| 117 | Matrix<Scalar, Cols, Cols> A = rp; |
| 118 | Matrix<Scalar, Cols, Cols> B = rp.transpose(); |
| 119 | VERIFY_IS_APPROX(A, B.transpose()); |
| 120 | } |
| 121 | |
| 122 | m_permuted = m_original; |
| 123 | lp = lt; |
| 124 | rp = rt; |
| 125 | VERIFY_EVALUATION_COUNT(m_permuted = lt * m_permuted * rt, 1); |
| 126 | VERIFY_IS_APPROX(m_permuted, lp*m_original*rp.transpose()); |
| 127 | |
| 128 | VERIFY_IS_APPROX(lt.inverse()*m_permuted*rt.inverse(), m_original); |
| 129 | } |
| 130 | |
| 131 | template<typename T> |
| 132 | void bug890() |
| 133 | { |
| 134 | typedef Matrix<T, Dynamic, Dynamic> MatrixType; |
| 135 | typedef Matrix<T, Dynamic, 1> VectorType; |
| 136 | typedef Stride<Dynamic,Dynamic> S; |
| 137 | typedef Map<MatrixType, Aligned, S> MapType; |
| 138 | typedef PermutationMatrix<Dynamic> Perm; |
| 139 | |
| 140 | VectorType v1(2), v2(2), op(4), rhs(2); |
| 141 | v1 << 666,667; |
| 142 | op << 1,0,0,1; |
| 143 | rhs << 42,42; |
| 144 | |
| 145 | Perm P(2); |
| 146 | P.indices() << 1, 0; |
| 147 | |
| 148 | MapType(v1.data(),2,1,S(1,1)) = P * MapType(rhs.data(),2,1,S(1,1)); |
| 149 | VERIFY_IS_APPROX(v1, (P * rhs).eval()); |
| 150 | |
| 151 | MapType(v1.data(),2,1,S(1,1)) = P.inverse() * MapType(rhs.data(),2,1,S(1,1)); |
| 152 | VERIFY_IS_APPROX(v1, (P.inverse() * rhs).eval()); |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 153 | } |
| 154 | |
| 155 | void test_permutationmatrices() |
| 156 | { |
| 157 | for(int i = 0; i < g_repeat; i++) { |
| 158 | CALL_SUBTEST_1( permutationmatrices(Matrix<float, 1, 1>()) ); |
| 159 | CALL_SUBTEST_2( permutationmatrices(Matrix3f()) ); |
| 160 | CALL_SUBTEST_3( permutationmatrices(Matrix<double,3,3,RowMajor>()) ); |
| 161 | CALL_SUBTEST_4( permutationmatrices(Matrix4d()) ); |
| 162 | CALL_SUBTEST_5( permutationmatrices(Matrix<double,40,60>()) ); |
| 163 | CALL_SUBTEST_6( permutationmatrices(Matrix<double,Dynamic,Dynamic,RowMajor>(20, 30)) ); |
| 164 | CALL_SUBTEST_7( permutationmatrices(MatrixXcf(15, 10)) ); |
| 165 | } |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 166 | CALL_SUBTEST_5( bug890<double>() ); |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 167 | } |