#ifndef Magnum_Math_Matrix_h #define Magnum_Math_Matrix_h /* Copyright © 2010, 2011, 2012 Vladimír Vondruš This file is part of Magnum. Magnum is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 3 only, as published by the Free Software Foundation. Magnum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License version 3 for more details. */ /** @file * @brief Class Magnum::Math::Matrix */ #include "RectangularMatrix.h" namespace Magnum { namespace Math { #ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { template class MatrixDeterminant; } #endif /** @brief Square matrix @tparam size %Matrix size @tparam T Data type See @ref matrix-vector for brief introduction. @configurationvalueref{Magnum::Math::Matrix} */ template class Matrix: public RectangularMatrix { public: const static std::size_t Size = size; /**< @brief %Matrix size */ /** @brief Pass to constructor to create zero-filled matrix */ enum ZeroType { Zero }; /** * @brief Zero-filled matrix constructor * * Use this constructor by calling `Matrix m(Matrix::Zero);`. */ inline constexpr explicit Matrix(ZeroType) {} /** @brief Pass to constructor to create identity matrix */ enum IdentityType { Identity }; /** * @brief Default constructor * * You can also explicitly call this constructor with * `Matrix m(Matrix::Identity);`. Optional parameter @p value allows * you to specify value on diagonal. * @todo use constexpr fromDiagonal() for this when it's done */ inline /*implicit*/ Matrix(IdentityType = Identity, T value = T(1)) { for(std::size_t i = 0; i != size; ++i) (*this)[i][i] = value; } /** * @brief %Matrix from column vectors * @param first First column vector * @param next Next column vectors */ template inline constexpr /*implicit*/ Matrix(const Vector& first, const U&... next): RectangularMatrix(first, next...) {} /** * @brief Construct matrix from another of different type * * Performs only default casting on the values, no rounding or * anything else. Example usage: * @code * Matrix<2, float> floatingPoint({1.3f, 2.7f}, * {-15.0f, 7.0f}); * Matrix<2, std::int8_t> integral(floatingPoint); * // integral == {{1, 2}, {-15, 7}} * @endcode */ template inline constexpr explicit Matrix(const RectangularMatrix& other): RectangularMatrix(other) {} /** @brief Copy constructor */ inline constexpr Matrix(const RectangularMatrix& other): RectangularMatrix(other) {} /** * @brief Trace of the matrix * * @f[ * tr(A) = \sum_{i=1}^n a_{i,i} * @f] */ T trace() const { return this->diagonal().sum(); } /** @brief %Matrix without given column and row */ Matrix ij(std::size_t skipCol, std::size_t skipRow) const { Matrix out(Matrix::Zero); for(std::size_t col = 0; col != size-1; ++col) for(std::size_t row = 0; row != size-1; ++row) out[col][row] = (*this)[col + (col >= skipCol)] [row + (row >= skipRow)]; return out; } /** * @brief Determinant * * Computed recursively using Laplace's formula: @f[ * \det(A) = \sum_{j=1}^n (-1)^{i+j} a_{i,j} \det(A^{i,j}) * @f] @f$ A^{i, j} @f$ is matrix without i-th row and j-th column, see * ij(). The formula is expanded down to 2x2 matrix, where the * determinant is computed directly: @f[ * \det(A) = a_{0, 0} a_{1, 1} - a_{1, 0} a_{0, 1} * @f] */ inline T determinant() const { return Implementation::MatrixDeterminant()(*this); } /** * @brief Inverted matrix * * Computed using Cramer's rule: @f[ * A^{-1} = \frac{1}{\det(A)} Adj(A) * @f] * * See Matrix3::invertedEuclidean() and Matrix4::invertedEuclidean() * which are faster alternatives for particular matrix types. */ Matrix inverted() const { Matrix out(Zero); T _determinant = determinant(); for(std::size_t col = 0; col != size; ++col) for(std::size_t row = 0; row != size; ++row) out[col][row] = (((row+col) & 1) ? -1 : 1)*ij(row, col).determinant()/_determinant; return out; } #ifndef DOXYGEN_GENERATING_OUTPUT /* Reimplementation of functions to return correct type */ inline Matrix operator*(const Matrix& other) const { return RectangularMatrix::operator*(other); } template inline RectangularMatrix operator*(const RectangularMatrix& other) const { return RectangularMatrix::operator*(other); } inline Vector operator*(const Vector& other) const { return RectangularMatrix::operator*(other); } MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(size, size, Matrix) #endif }; #ifndef DOXYGEN_GENERATING_OUTPUT template inline typename std::enable_if::value, Matrix>::type operator*(U number, const Matrix& matrix) { return number*RectangularMatrix(matrix); } template inline typename std::enable_if::value, Matrix>::type operator/(U number, const Matrix& matrix) { return number/RectangularMatrix(matrix); } template inline Matrix operator*(const Vector& vector, const RectangularMatrix& matrix) { return RectangularMatrix<1, size, T>(vector)*matrix; } #endif /** @debugoperator{Magnum::Math::Matrix} */ template inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Matrix& value) { return debug << static_cast&>(value); } #ifndef DOXYGEN_GENERATING_OUTPUT #define MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(Type, VectorType, size) \ inline VectorType& operator[](std::size_t col) { \ return VectorType::from(Matrix::data()+col*size); \ } \ inline constexpr const VectorType& operator[](std::size_t col) const { \ return VectorType::from(Matrix::data()+col*size); \ } \ \ inline Type operator*(const Matrix& other) const { \ return Matrix::operator*(other); \ } \ template inline RectangularMatrix operator*(const RectangularMatrix& other) const { \ return Matrix::operator*(other); \ } \ inline VectorType operator*(const Vector& other) const { \ return Matrix::operator*(other); \ } \ \ inline Type transposed() const { return Matrix::transposed(); } \ inline Type inverted() const { return Matrix::inverted(); } #define MAGNUM_MATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(Type, size) \ template inline typename std::enable_if::value, Type>::type operator*(U number, const Type& matrix) { \ return number*Matrix(matrix); \ } \ template inline typename std::enable_if::value, Type>::type operator/(U number, const Type& matrix) { \ return number/Matrix(matrix); \ } \ template inline Type operator*(const Vector& vector, const RectangularMatrix& matrix) { \ return RectangularMatrix<1, size, T>(vector)*matrix; \ } namespace Implementation { template class MatrixDeterminant { public: T operator()(const Matrix& m) { T out(0); for(std::size_t col = 0; col != size; ++col) out += ((col & 1) ? -1 : 1)*m[col][0]*m.ij(col, 0).determinant(); return out; } }; template class MatrixDeterminant<2, T> { public: inline constexpr T operator()(const Matrix<2, T>& m) { return m[0][0]*m[1][1] - m[1][0]*m[0][1]; } }; template class MatrixDeterminant<1, T> { public: inline constexpr T operator()(const Matrix<1, T>& m) { return m[0][0]; } }; } #endif }} namespace Corrade { namespace Utility { /** @configurationvalue{Magnum::Math::Matrix} */ template struct ConfigurationValue>: public ConfigurationValue> {}; }} #endif