/*========================================================================= Program: Visualization Toolkit Module: vtkMathPrivate.hxx Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ /** * @class vtkMathPrivate * @brief Internal toolkit used in some vtkMath methods. * * vtkMathPrivate provides meta-classes helpers that are used in some vtkMath * methods. * @sa * vtkMath * vtkMatrixUtilities */ #ifndef vtkMathPrivate_hxx #define vtkMathPrivate_hxx #include "vtkCommonCoreModule.h" //required for correct implementation #include "vtkMatrixUtilities.h" #include namespace vtkMathPrivate { static constexpr int VTK_MATH_PRIVATE_PACK_SIZE = 4; //============================================================================= // This class computes the dot product between row RowT of matrix M1 // and column ColT of matrix M2. // The template parameter IdxT is on index ahead from computation. // Template parameters LayoutT1 and LayoutT2 respectively reindex // input matrices M1 and M2 according to MatrixLayout enumeration // M1 (or M1^T if LayoutT1 == vtkMatrixUtilities::Layout::Transpose) is a matrix of RowsT x // MidDimT M2 (or M2^T if LayoutT2 == vtkMatrixUtilities::Layout::Transpose) is a matrix of MidDimT // x ColsDimT template class ContractRowWithCol { public: template static ScalarT Compute(const MatrixT1& M1, const MatrixT2& M2) { return ContractRowWithCol::Compute(M1, M2) + ContractRowWithCol::Compute(M1, M2); } private: static constexpr bool ROW_OUT_OF_BOUNDS = RowT >= 0 && RowT < RowsT; static_assert(ROW_OUT_OF_BOUNDS, "RowT is out of bounds"); static constexpr bool COL_OUT_OF_BOUNDS = ColT >= 0 && ColT < ColsT; static_assert(COL_OUT_OF_BOUNDS, "ColT is out of bounds"); static constexpr int Shift = (MidDimT - IdxT) / VTK_MATH_PRIVATE_PACK_SIZE ? VTK_MATH_PRIVATE_PACK_SIZE : MidDimT - IdxT - 1; }; //============================================================================= // Specialization for when there are 4 components left to compute template class ContractRowWithCol { public: template static ScalarT Compute(const MatrixT1& M1, const MatrixT2& M2) { using Wrap1 = vtkMatrixUtilities::Wrapper; using Wrap2 = vtkMatrixUtilities::Wrapper; return Wrap1::template Get(M1) * Wrap2::template Get(M2) + Wrap1::template Get(M1) * Wrap2::template Get(M2) + Wrap1::template Get(M1) * Wrap2::template Get(M2) + Wrap1::template Get(M1) * Wrap2::template Get(M2); } private: static constexpr bool ROW_OUT_OF_BOUNDS = RowT >= 0 && RowT < RowsT; static_assert(ROW_OUT_OF_BOUNDS, "RowT is out of bounds"); static constexpr bool COL_OUT_OF_BOUNDS = ColT >= 0 && ColT < ColsT; static_assert(COL_OUT_OF_BOUNDS, "ColT is out of bounds"); }; //============================================================================= // Specialization for when there are 3 components left to compute template class ContractRowWithCol { public: template static ScalarT Compute(const MatrixT1& M1, const MatrixT2& M2) { using Wrap1 = vtkMatrixUtilities::Wrapper; using Wrap2 = vtkMatrixUtilities::Wrapper; return Wrap1::template Get(M1) * Wrap2::template Get(M2) + Wrap1::template Get(M1) * Wrap2::template Get(M2) + Wrap1::template Get(M1) * Wrap2::template Get(M2); } private: static constexpr bool ROW_OUT_OF_BOUNDS = RowT >= 0 && RowT < RowsT; static_assert(ROW_OUT_OF_BOUNDS, "RowT is out of bounds"); static constexpr bool COL_OUT_OF_BOUNDS = ColT >= 0 && ColT < ColsT; static_assert(COL_OUT_OF_BOUNDS, "ColT is out of bounds"); }; //============================================================================= // Specialization for when there are 2 components left to compute template class ContractRowWithCol { public: template static ScalarT Compute(const MatrixT1& M1, const MatrixT2& M2) { using Wrap1 = vtkMatrixUtilities::Wrapper; using Wrap2 = vtkMatrixUtilities::Wrapper; return Wrap1::template Get(M1) * Wrap2::template Get(M2) + Wrap1::template Get(M1) * Wrap2::template Get(M2); } private: static constexpr bool ROW_OUT_OF_BOUNDS = RowT >= 0 && RowT < RowsT; static_assert(ROW_OUT_OF_BOUNDS, "RowT is out of bounds"); static constexpr bool COL_OUT_OF_BOUNDS = ColT >= 0 && ColT < ColsT; static_assert(COL_OUT_OF_BOUNDS, "ColT is out of bounds"); }; //============================================================================= // Specialization for when there is 1 component left to compute template class ContractRowWithCol { public: template static ScalarT Compute(const MatrixT1& M1, const MatrixT2& M2) { using Wrap1 = vtkMatrixUtilities::Wrapper; using Wrap2 = vtkMatrixUtilities::Wrapper; return Wrap1::template Get(M1) * Wrap2::template Get(M2); } private: static constexpr bool ROW_OUT_OF_BOUNDS = RowT >= 0 && RowT < RowsT; static_assert(ROW_OUT_OF_BOUNDS, "RowT is out of bounds"); static constexpr bool COL_OUT_OF_BOUNDS = ColT >= 0 && ColT < ColsT; static_assert(COL_OUT_OF_BOUNDS, "ColT is out of bounds"); }; //============================================================================= // This class handles row and col contraction when at least one of the 2 input // matrices are diagonal template class DiagContractRowWithCol; //============================================================================= // Specialization for when M1 is diagonal template class DiagContractRowWithCol { public: template static ScalarT Compute(const MatrixT1& M1, const MatrixT2& M2) { return M1[RowT] * M2[Mapper2::template GetIndex()]; } private: static constexpr bool ROW_OUT_OF_BOUNDS = RowT >= 0 && RowT < RowsT; static_assert(ROW_OUT_OF_BOUNDS, "RowT is out of bounds"); static constexpr bool COL_OUT_OF_BOUNDS = ColT >= 0 && ColT < ColsT; static_assert(COL_OUT_OF_BOUNDS, "ColT is out of bounds"); using Mapper2 = vtkMatrixUtilities::Mapper; }; //============================================================================= // Specialization for when M2 is diagonal template class DiagContractRowWithCol { public: template static ScalarT Compute(const MatrixT1& M1, const MatrixT2& M2) { return M1[Mapper1::template GetIndex()] * M2[ColT]; } private: static constexpr bool ROW_OUT_OF_BOUNDS = RowT >= 0 && RowT < RowsT; static_assert(ROW_OUT_OF_BOUNDS, "RowT is out of bounds"); static constexpr bool COL_OUT_OF_BOUNDS = ColT >= 0 && ColT < ColsT; static_assert(COL_OUT_OF_BOUNDS, "ColT is out of bounds"); using Mapper1 = vtkMatrixUtilities::Mapper; }; //============================================================================= // This class returns zero. Is is used for rectangular diagonal matrices, when // lines / rows are filled with zeros. template class NullContractRowWithCol { public: template static ScalarT Compute(const MatrixT1&, const MatrixT2&) { return ScalarT(0); } }; //============================================================================= // Helper class to choose between regular contraction class vs diagonal // handling contraction class. // By default, Type is an instance of ContractRowWithCol template struct ContractRowWithColSwitch { typedef ContractRowWithCol Type; static constexpr bool NO_INPUT_MATRIX_CAN_BE_DIAGONAL = !std::is_same::value && !std::is_same::value; static_assert(NO_INPUT_MATRIX_CAN_BE_DIAGONAL, "LayoutT1 and LayoutT2 cannot equal vtkMatrixUtilities::Layout::Diag in this setup"); }; //============================================================================= // Specialization for diagonal matrices. // Rectangular diagonal matrices are handled using NullContractRowWithCol. template struct ContractRowWithColSwitch { static constexpr bool IsDiagonal1 = std::is_same::value; static constexpr bool IsDiagonal2 = std::is_same::value; // If on of the diagonal matrix is rectangular and we are out of the diagonal // length, all remaining values are null. static constexpr bool UseNullContractRowWithCol = (IsDiagonal1 && RowT >= MidDimT) || (IsDiagonal2 && ColT >= MidDimT); typedef typename std::conditional, DiagContractRowWithCol>::type Type; static constexpr bool NEEDS_AT_LEAST_ONE_DIAGONAL_INPUT_MATRIX = IsDiagonal1 || IsDiagonal2; static_assert(NEEDS_AT_LEAST_ONE_DIAGONAL_INPUT_MATRIX, "LayoutT1 or LayoutT2 must equal vtkMatrixUtilities::Layout::Diag in this setup"); }; namespace detail { //============================================================================= // Class in charge for actually multiplying 2 matrices. // This method is called by MultiplyMatrix::Compute for chunks of size // VTK_MATH_PRIVATE_PACK_SIZE at most, specified in ColPackSizeT. // This class mostly consists on explicitly onfold computation for those chunks. template class MultiplyMatrix; //============================================================================= // Specialization for a chunk of size 4 template class MultiplyMatrix { public: template static void Compute(const MatrixT1& M1, const MatrixT2& M2, MatrixT3& M3) { using Scalar = typename vtkMatrixUtilities::ScalarTypeExtractor::value_type; using Wrap3 = vtkMatrixUtilities::Wrapper; Wrap3::template Get(M3) = ContractRowWithColSwitch::Type::Compute(M1, M2); Wrap3::template Get(M3) = ContractRowWithColSwitch::Type::Compute(M1, M2); Wrap3::template Get(M3) = ContractRowWithColSwitch::Type::Compute(M1, M2); Wrap3::template Get(M3) = ContractRowWithColSwitch::Type::Compute(M1, M2); } private: static constexpr bool ROW_OUT_OF_BOUNDS = RowT < RowsT && RowT >= 0; static_assert(ROW_OUT_OF_BOUNDS, "RowT is out of bounds"); static constexpr bool COL_OUT_OF_BOUNDS = ColT + 3 < ColsT && ColT >= 0; static_assert(COL_OUT_OF_BOUNDS, "ColT is out of bounds"); static constexpr bool OneMatrixIsDiagonal = std::is_same::value || std::is_same::value; }; //============================================================================= // Specialization for a chunk of size 3 template class MultiplyMatrix { public: template static void Compute(const MatrixT1& M1, const MatrixT2& M2, MatrixT3& M3) { using Scalar = typename vtkMatrixUtilities::ScalarTypeExtractor::value_type; using Wrap3 = vtkMatrixUtilities::Wrapper; Wrap3::template Get(M3) = ContractRowWithColSwitch::Type::Compute(M1, M2); Wrap3::template Get(M3) = ContractRowWithColSwitch::Type::Compute(M1, M2); Wrap3::template Get(M3) = ContractRowWithColSwitch::Type::Compute(M1, M2); } private: static constexpr bool ROW_OUT_OF_BOUNDS = RowT < RowsT && RowT >= 0; static_assert(ROW_OUT_OF_BOUNDS, "RowT is out of bounds"); static constexpr bool COL_OUT_OF_BOUNDS = ColT + 2 < ColsT && ColT >= 0; static_assert(COL_OUT_OF_BOUNDS, "ColT is out of bounds"); static constexpr bool OneMatrixIsDiagonal = std::is_same::value || std::is_same::value; }; //============================================================================= // Specialization for a chunk of size 2 template class MultiplyMatrix { public: template static void Compute(const MatrixT1& M1, const MatrixT2& M2, MatrixT3& M3) { using Scalar = typename vtkMatrixUtilities::ScalarTypeExtractor::value_type; using Wrap3 = vtkMatrixUtilities::Wrapper; Wrap3::template Get(M3) = ContractRowWithColSwitch::Type::Compute(M1, M2); Wrap3::template Get(M3) = ContractRowWithColSwitch::Type::Compute(M1, M2); } private: static constexpr bool ROW_OUT_OF_BOUNDS = RowT < RowsT && RowT >= 0; static_assert(ROW_OUT_OF_BOUNDS, "RowT is out of bounds"); static constexpr bool COL_OUT_OF_BOUNDS = ColT + 1 < ColsT && ColT >= 0; static_assert(COL_OUT_OF_BOUNDS, "ColT is out of bounds"); static constexpr bool OneMatrixIsDiagonal = std::is_same::value || std::is_same::value; }; //============================================================================= // Specialization for a chunk of size 1 template class MultiplyMatrix { public: template static void Compute(const MatrixT1& M1, const MatrixT2& M2, MatrixT3& M3) { using Scalar = typename vtkMatrixUtilities::ScalarTypeExtractor::value_type; using Wrap3 = vtkMatrixUtilities::Wrapper; Wrap3::template Get(M3) = ContractRowWithColSwitch::Type::Compute(M1, M2); } private: static constexpr bool ROW_OUT_OF_BOUNDS = RowT < RowsT && RowT >= 0; static_assert(ROW_OUT_OF_BOUNDS, "RowT is out of bounds"); static constexpr bool COL_OUT_OF_BOUNDS = ColT < ColsT && ColT >= 0; static_assert(COL_OUT_OF_BOUNDS, "ColT is out of bounds"); static constexpr bool OneMatrixIsDiagonal = std::is_same::value || std::is_same::value; }; //============================================================================= // Specialization when both input matrices are diagonal for a chunk of size 4 template class MultiplyMatrix { public: template static void Compute(const MatrixT1& M1, const MatrixT2& M2, MatrixT3& M3) { M3[IdxT] = M1[IdxT] * M2[IdxT]; M3[IdxT + 1] = M1[IdxT + 1] * M2[IdxT + 1]; M3[IdxT + 2] = M1[IdxT + 2] * M2[IdxT + 2]; M3[IdxT + 3] = M1[IdxT + 3] * M2[IdxT + 3]; } }; //============================================================================= // Specialization when both input matrices are diagonal for a chunk of size 3 template class MultiplyMatrix { public: template static void Compute(const MatrixT1& M1, const MatrixT2& M2, MatrixT3& M3) { M3[IdxT] = M1[IdxT] * M2[IdxT]; M3[IdxT + 1] = M1[IdxT + 1] * M2[IdxT + 1]; M3[IdxT + 2] = M1[IdxT + 2] * M2[IdxT + 2]; } }; //============================================================================= // Specialization when both input matrices are diagonal for a chunk of size 2 template class MultiplyMatrix { public: template static void Compute(const MatrixT1& M1, const MatrixT2& M2, MatrixT3& M3) { M3[IdxT] = M1[IdxT] * M2[IdxT]; M3[IdxT + 1] = M1[IdxT + 1] * M2[IdxT + 1]; } }; //============================================================================= // Specialization when both input matrices are diagonal for a chunk of size 1 template class MultiplyMatrix { public: template static void Compute(const MatrixT1& M1, const MatrixT2& M2, MatrixT3& M3) { M3[IdxT] = M1[IdxT] * M2[IdxT]; } }; } // namespace detail //============================================================================= // Multiply matrices such that M3 = M1 * M2. // Template parameters LayoutT1 and LayoutT2 respectively reindex // input matrices M1 and M2 following MatrixLayout options // Hence, if LayoutT1 == vtkMatrixUtilities::Layout::Transpose, then M3 = M1^T * M2, and so on. // M1 (or M1^T if LayoutT1 == vtkMatrixUtilities::Layout::Transpose) is a matrix of RowsT x // MidDimT M2 (or M2^T if LayoutT2 == vtkMatrixUtilities::Layout::Transpose) is a matrix of MidDimT // x ColsDimT // // RemainingRowSizeT should be disregarded when first instantiating this class. It is // the number of remaining elements in the current row to process. // // To compute the multiplication, each component of the output matrix // is computed chunk by chunk (of size VTK_MATH_PRIVATE_PACK_SIZE), // starting at the top left, sweeping the rows one by one. template class MultiplyMatrix { public: template static void Compute(const MatrixT1& M1, const MatrixT2& M2, MatrixT3& M3) { detail::MultiplyMatrix::Compute( M1, M2, M3); MultiplyMatrix::Compute(M1, M2, M3); } private: static constexpr int Row = NextRowT - 1; static constexpr int Col = NextColT - 1; // We go to a new row when the last chunk is lower or equal to // VTK_MATH_PRIVATE_PACK_SIZE static constexpr bool GoToNewRow = !((ColsT - Col - 1) / VTK_MATH_PRIVATE_PACK_SIZE); // This is the chunk size, which is from what we should shift in recursive // calls static constexpr int Shift = GoToNewRow ? ColsT - Col : VTK_MATH_PRIVATE_PACK_SIZE; // Row / col / pack size for the next recursive call, depending on if we // change row or not. static constexpr int ForwardRow = GoToNewRow ? NextRowT + 1 : NextRowT; static constexpr int ForwardCol = GoToNewRow ? 1 : NextColT + Shift; static constexpr int ForwardRemainingRowSize = GoToNewRow ? ColsT : RemainingRowSizeT - Shift; static constexpr bool ROW_OUT_OF_BOUNDS = Row < RowsT && Row >= 0; static_assert(ROW_OUT_OF_BOUNDS, "RowT is out of bounds"); static constexpr bool COL_OUT_OF_BOUNDS = Col < ColsT && Col >= 0; static_assert(COL_OUT_OF_BOUNDS, "ColT is out of bounds"); }; //============================================================================= // Specialization for when both input matrices are diagonal // Warning: RowsT, MidDimT and ColsT MUST match template class MultiplyMatrix { public: template static void Compute(const MatrixT1& M1, const MatrixT2& M2, MatrixT3& M3) { detail::MultiplyMatrix::Compute(M1, M2, M3); MultiplyMatrix::Compute(M1, M2, M3); } private: static constexpr bool Shift = VTK_MATH_PRIVATE_PACK_SIZE; static constexpr bool DIAGONAL_MATRICES_DIMENSIONS_DONT_MATCH = RowsT == MidDimT && RowsT == ColsT; static_assert(DIAGONAL_MATRICES_DIMENSIONS_DONT_MATCH, "There must be RowsT = MidDimT = colsT"); static constexpr bool ROW_OUT_OF_BOUNDS = NextIdxT <= RowsT && NextIdxT > 0; static_assert(ROW_OUT_OF_BOUNDS, "RowT is out of bounds"); static constexpr bool COL_OUT_OF_BOUNDS = NextIdxT <= ColsT && NextIdxT > 0; static_assert(COL_OUT_OF_BOUNDS, "ColT is out of bounds"); }; //============================================================================= // Macro defining the specialization for when both input matrices are diagonal, // implementing the last chunk to compute. They should be specialized // for integers below VTK_MATH_PRIVATE_PACK_SIZE #define vtkEndForBothDiagonalMultiplyMatrixSpecializationMacro(RemainingRowSize) \ template \ class MultiplyMatrix \ { \ public: \ template \ static void Compute(const MatrixT1& M1, const MatrixT2& M2, MatrixT3& M3) \ { \ detail::MultiplyMatrix::Compute(M1, M2, M3); \ } \ \ private: \ static constexpr bool DIAGONAL_MATRICES_DIMENSIONS_DONT_MATCH = \ RowsT == MidDimT && RowsT == ColsT; \ static_assert( \ DIAGONAL_MATRICES_DIMENSIONS_DONT_MATCH, "There must be RowsT = MidDimT = colsT"); \ static constexpr bool ROW_OUT_OF_BOUNDS = NextIdxT <= RowsT && NextIdxT > 0; \ static_assert(ROW_OUT_OF_BOUNDS, "RowT is out of bounds"); \ static constexpr bool COL_OUT_OF_BOUNDS = NextIdxT <= ColsT && NextIdxT > 0; \ static_assert(COL_OUT_OF_BOUNDS, "ColT is out of bounds"); \ }; //============================================================================= vtkEndForBothDiagonalMultiplyMatrixSpecializationMacro(1); vtkEndForBothDiagonalMultiplyMatrixSpecializationMacro(2); vtkEndForBothDiagonalMultiplyMatrixSpecializationMacro(3); vtkEndForBothDiagonalMultiplyMatrixSpecializationMacro(4); #undef vtkEndForBothDiagonalMultiplyMatrixSpecializationMacro //============================================================================= // Macro defining specialization for the last chunk to compute. They should be // specialized for integers below VTK_MATH_PRIVATE_PACK_SIZE #define vtkLastRowMultiplyMatrixSpecializationMacro(RemainingRowSize) \ template \ class MultiplyMatrix \ { \ public: \ template \ static void Compute(const MatrixT1& M1, const MatrixT2& M2, MatrixT3& M3) \ { \ detail::MultiplyMatrix::Compute(M1, M2, M3); \ } \ \ private: \ static constexpr bool COL_OUT_OF_BOUNDS = NextColT - 1 < ColsT && NextColT >= 1; \ static_assert(COL_OUT_OF_BOUNDS, "ColT is out of bounds"); \ }; //============================================================================= vtkLastRowMultiplyMatrixSpecializationMacro(1); vtkLastRowMultiplyMatrixSpecializationMacro(2); vtkLastRowMultiplyMatrixSpecializationMacro(3); vtkLastRowMultiplyMatrixSpecializationMacro(4); #undef vtkLastRowMultiplyMatrixSpecializationMacro //============================================================================= // Class computing the determinant of square matrices SizeT x SizeT. // The template parameter LayoutT is a struct embedded in MatrixLayout template class Determinant; //============================================================================= // Specialization for diagonal 3x3 matrices of size template <> class Determinant<3, vtkMatrixUtilities::Layout::Diag> { public: template static typename vtkMatrixUtilities::ScalarTypeExtractor::value_type Compute( const MatrixT& M) { return M[0] * M[1] * M[3]; } }; //============================================================================= // Specialization for diagonal 2x2 matrices template <> class Determinant<2, vtkMatrixUtilities::Layout::Diag> { public: template static typename vtkMatrixUtilities::ScalarTypeExtractor::value_type Compute( const MatrixT& M) { return M[0] * M[1]; } }; //============================================================================= // Specialization for 1x1 matrices template class Determinant<1, LayoutT> { public: template static typename vtkMatrixUtilities::ScalarTypeExtractor::value_type Compute( const MatrixT& M) { return M[0]; } }; //============================================================================= // Specialization for 2x2 non-diagonal matrices template class Determinant<2, LayoutT> { public: template static typename vtkMatrixUtilities::ScalarTypeExtractor::value_type Compute( const MatrixT& M) { using Wrap = vtkMatrixUtilities::Wrapper<2, 2, MatrixT, LayoutT>; return Wrap::template Get<0, 0>(M) * Wrap::template Get<1, 1>(M) - Wrap::template Get<1, 0>(M) * Wrap::template Get<0, 1>(M); } private: }; //============================================================================= // Specialization for 3x3 non-diagonal matrices template class Determinant<3, LayoutT> { public: template static typename vtkMatrixUtilities::ScalarTypeExtractor::value_type Compute( const MatrixT& M) { using Wrap = vtkMatrixUtilities::Wrapper<3, 3, MatrixT, LayoutT>; return Wrap::template Get<0, 0>(M) * Wrap::template Get<1, 1>(M) * Wrap::template Get<2, 2>(M) + Wrap::template Get<0, 1>(M) * Wrap::template Get<1, 2>(M) * Wrap::template Get<2, 0>(M) + Wrap::template Get<0, 2>(M) * Wrap::template Get<1, 0>(M) * Wrap::template Get<2, 1>(M) - Wrap::template Get<0, 0>(M) * Wrap::template Get<1, 2>(M) * Wrap::template Get<2, 1>(M) - Wrap::template Get<0, 1>(M) * Wrap::template Get<1, 0>(M) * Wrap::template Get<2, 2>(M) - Wrap::template Get<0, 2>(M) * Wrap::template Get<1, 1>(M) * Wrap::template Get<2, 0>(M); } }; //============================================================================= // Class inverting square matrices SizeT x SizeT. // The template parameter LayoutT is a struct embedded in MatrixLayout template class InvertMatrix; //============================================================================= // Specialization for 2x2 non-diagonal matrices template class InvertMatrix<2, LayoutT> { public: template static void Compute(const MatrixT1& M1, MatrixT2& M2) { using Scalar = typename vtkMatrixUtilities::ScalarTypeExtractor::value_type; using Wrap1 = vtkMatrixUtilities::Wrapper<2, 2, MatrixT1, LayoutT>; using Wrap2 = vtkMatrixUtilities::Wrapper<2, 2, MatrixT2>; Scalar detInv = 1.0 / Determinant<2, LayoutT>::Compute(M1); Wrap2::template Get<0, 0>(M2) = detInv * Wrap1::template Get<1, 1>(M1); Wrap2::template Get<1, 0>(M2) = -detInv * Wrap1::template Get<1, 0>(M1); Wrap2::template Get<0, 1>(M2) = -detInv * Wrap1::template Get<0, 1>(M1); Wrap2::template Get<1, 1>(M2) = detInv * Wrap1::template Get<0, 0>(M1); } }; //============================================================================= // Specialization for 3x3 non-diagonal matrices template class InvertMatrix<3, LayoutT> { public: template static void Compute(const MatrixT1& M1, MatrixT2& M2) { using Scalar = typename vtkMatrixUtilities::ScalarTypeExtractor::value_type; using Wrap1 = vtkMatrixUtilities::Wrapper<3, 3, MatrixT1, LayoutT>; using Wrap2 = vtkMatrixUtilities::Wrapper<3, 3, MatrixT2>; Scalar detInv = 1.0 / (Wrap1::template Get<0, 0>(M1) * (Wrap1::template Get<1, 1>(M1) * Wrap1::template Get<2, 2>(M1) - Wrap1::template Get<2, 1>(M1) * Wrap1::template Get<1, 2>(M1)) - Wrap1::template Get<0, 1>(M1) * (Wrap1::template Get<1, 0>(M1) * Wrap1::template Get<2, 2>(M1) - Wrap1::template Get<2, 0>(M1) * Wrap1::template Get<1, 2>(M1)) + Wrap1::template Get<0, 2>(M1) * (Wrap1::template Get<1, 0>(M1) * Wrap1::template Get<2, 1>(M1) - Wrap1::template Get<2, 0>(M1) * Wrap1::template Get<1, 1>(M1))); Wrap2::template Get<0, 0>(M2) = detInv * (Wrap1::template Get<1, 1>(M1) * Wrap1::template Get<2, 2>(M1) - Wrap1::template Get<2, 1>(M1) * Wrap1::template Get<1, 2>(M1)); Wrap2::template Get<1, 0>(M2) = -detInv * (Wrap1::template Get<1, 0>(M1) * Wrap1::template Get<2, 2>(M1) - Wrap1::template Get<2, 0>(M1) * Wrap1::template Get<1, 2>(M1)); Wrap2::template Get<2, 0>(M2) = detInv * (Wrap1::template Get<1, 0>(M1) * Wrap1::template Get<2, 1>(M1) - Wrap1::template Get<2, 0>(M1) * Wrap1::template Get<1, 1>(M1)); Wrap2::template Get<0, 1>(M2) = -detInv * (Wrap1::template Get<0, 1>(M1) * Wrap1::template Get<2, 2>(M1) - Wrap1::template Get<2, 1>(M1) * Wrap1::template Get<0, 2>(M1)); Wrap2::template Get<1, 1>(M2) = detInv * (Wrap1::template Get<0, 0>(M1) * Wrap1::template Get<2, 2>(M1) - Wrap1::template Get<2, 0>(M1) * Wrap1::template Get<0, 2>(M1)); Wrap2::template Get<2, 1>(M2) = -detInv * (Wrap1::template Get<0, 0>(M1) * Wrap1::template Get<2, 1>(M1) - Wrap1::template Get<2, 0>(M1) * Wrap1::template Get<0, 1>(M1)); Wrap2::template Get<0, 2>(M2) = detInv * (Wrap1::template Get<0, 1>(M1) * Wrap1::template Get<1, 2>(M1) - Wrap1::template Get<1, 1>(M1) * Wrap1::template Get<0, 2>(M1)); Wrap2::template Get<1, 2>(M2) = -detInv * (Wrap1::template Get<0, 0>(M1) * Wrap1::template Get<1, 2>(M1) - Wrap1::template Get<1, 0>(M1) * Wrap1::template Get<0, 2>(M1)); Wrap2::template Get<2, 2>(M2) = detInv * (Wrap1::template Get<0, 0>(M1) * Wrap1::template Get<1, 1>(M1) - Wrap1::template Get<1, 0>(M1) * Wrap1::template Get<0, 1>(M1)); } }; //============================================================================= // Specialization for 1x1 matrices template class InvertMatrix<1, LayoutT> { public: template static void Compute(const MatrixT1& M1, MatrixT2& M2) { M2[0] = 1.0 / M1[0]; } }; //============================================================================= // Specialization for 2x2 diagonal matrices template <> class InvertMatrix<2, vtkMatrixUtilities::Layout::Diag> { public: template static void Compute(const MatrixT1& M1, MatrixT2& M2) { M2[0] = 1.0 / M1[0]; M2[1] = 1.0 / M1[1]; } }; //============================================================================= // Specialization for 3x3 diagonal matrices template <> class InvertMatrix<3, vtkMatrixUtilities::Layout::Diag> { public: template static void Compute(const MatrixT1& M1, MatrixT2& M2) { M2[0] = 1.0 / M1[0]; M2[1] = 1.0 / M1[1]; M2[2] = 1.0 / M1[2]; } }; //============================================================================= // Class solving systems M*y = x for square matrices RowsT x ColsT. // The template parameter LayoutT is a struct embedded in MatrixLayout // This class is currently specialized for 1x1, 2x2 and 3x3 matrices template class LinearSolve; //============================================================================= // Specialization for 1x1 matrices template class LinearSolve<1, 1, LayoutT> { public: template static void Compute(const MatrixT& M, const VectorT1& x, VectorT2& y) { y[0] = x[0] / M[0]; } }; //============================================================================= // Specialization for 2x2 matrices template class LinearSolve<2, 2, LayoutT> { public: template static void Compute(const MatrixT& M, const VectorT1& x, VectorT2& y) { using Scalar = typename vtkMatrixUtilities::ScalarTypeExtractor::value_type; using Wrap = vtkMatrixUtilities::Wrapper<2, 2, MatrixT, LayoutT>; Scalar detInv = 1.0 / Determinant<2, LayoutT>::Compute(M); y[0] = (x[0] * Wrap::template Get<1, 1>(M) - x[1] * Wrap::template Get<0, 1>(M)) * detInv; y[1] = (-x[0] * Wrap::template Get<1, 0>(M) + x[1] * Wrap::template Get<0, 0>(M)) * detInv; } }; //============================================================================= // Specialization for 3x3 matrices template class LinearSolve<3, 3, LayoutT> { public: template static void Compute(const MatrixT& M, const VectorT1& x, VectorT2& y) { using Scalar = typename vtkMatrixUtilities::ScalarTypeExtractor::value_type; using Wrap = vtkMatrixUtilities::Wrapper<3, 3, MatrixT, LayoutT>; Scalar detInv = 1.0 / (Wrap::template Get<0, 0>(M) * (Wrap::template Get<1, 1>(M) * Wrap::template Get<2, 2>(M) - Wrap::template Get<2, 1>(M) * Wrap::template Get<1, 2>(M)) - Wrap::template Get<0, 1>(M) * (Wrap::template Get<1, 0>(M) * Wrap::template Get<2, 2>(M) - Wrap::template Get<2, 0>(M) * Wrap::template Get<1, 2>(M)) + Wrap::template Get<0, 2>(M) * (Wrap::template Get<1, 0>(M) * Wrap::template Get<2, 1>(M) - Wrap::template Get<2, 0>(M) * Wrap::template Get<1, 1>(M))); y[0] = detInv * (x[0] * (Wrap::template Get<1, 1>(M) * Wrap::template Get<2, 2>(M) - Wrap::template Get<2, 1>(M) * Wrap::template Get<1, 2>(M)) - x[1] * (Wrap::template Get<0, 1>(M) * Wrap::template Get<2, 2>(M) - Wrap::template Get<2, 1>(M) * Wrap::template Get<0, 2>(M)) + x[2] * (Wrap::template Get<0, 1>(M) * Wrap::template Get<1, 2>(M) - Wrap::template Get<1, 1>(M) * Wrap::template Get<0, 2>(M))); y[1] = detInv * (-x[0] * (Wrap::template Get<1, 0>(M) * Wrap::template Get<2, 2>(M) - Wrap::template Get<2, 0>(M) * Wrap::template Get<1, 2>(M)) + x[1] * (Wrap::template Get<0, 0>(M) * Wrap::template Get<2, 2>(M) - Wrap::template Get<2, 0>(M) * Wrap::template Get<0, 2>(M)) - x[2] * (Wrap::template Get<0, 0>(M) * Wrap::template Get<1, 2>(M) - Wrap::template Get<1, 0>(M) * Wrap::template Get<0, 2>(M))); y[2] = detInv * (x[0] * (Wrap::template Get<1, 0>(M) * Wrap::template Get<2, 1>(M) - Wrap::template Get<2, 0>(M) * Wrap::template Get<1, 1>(M)) - x[1] * (Wrap::template Get<0, 0>(M) * Wrap::template Get<2, 1>(M) - Wrap::template Get<2, 0>(M) * Wrap::template Get<0, 1>(M)) + x[2] * (Wrap::template Get<0, 0>(M) * Wrap::template Get<1, 1>(M) - Wrap::template Get<1, 0>(M) * Wrap::template Get<0, 1>(M))); } }; //============================================================================= // Specialization for 2x2 diagonal matrices template <> class LinearSolve<2, 2, vtkMatrixUtilities::Layout::Diag> { public: template static void Compute(const MatrixT& M, const VectorT1& x, VectorT2& y) { y[0] = x[0] / M[0]; y[1] = x[1] / M[1]; } }; //============================================================================= // Specialization for 3x3 diagonal matrices template <> class LinearSolve<3, 3, vtkMatrixUtilities::Layout::Diag> { public: template static void Compute(const MatrixT& M, const VectorT1& x, VectorT2& y) { y[0] = x[0] / M[0]; y[1] = x[1] / M[1]; y[2] = x[2] / M[2]; } }; } // namespace vtkMathPrivate #endif