#ifndef _TCUMATRIX_HPP #define _TCUMATRIX_HPP /*------------------------------------------------------------------------- * drawElements Quality Program Tester Core * ---------------------------------------- * * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *//*! * \file * \brief Templatized matrix class. *//*--------------------------------------------------------------------*/ #include "tcuDefs.hpp" #include "tcuVector.hpp" #include "tcuArray.hpp" namespace tcu { // Templated matrix class. template class Matrix { public: typedef Vector Element; typedef T Scalar; enum { SIZE = Cols, ROWS = Rows, COLS = Cols, }; Matrix (void); explicit Matrix (const T& src); explicit Matrix (const T src[Rows*Cols]); Matrix (const Vector& src); Matrix (const Matrix& src); ~Matrix (void); Matrix& operator= (const Matrix& src); Matrix& operator*= (const Matrix& src); void setRow (int rowNdx, const Vector& vec); void setColumn (int colNdx, const Vector& vec); Vector getRow (int ndx) const; Vector& getColumn (int ndx); const Vector& getColumn (int ndx) const; Vector& operator[] (int ndx) { return getColumn(ndx); } const Vector& operator[] (int ndx) const { return getColumn(ndx); } inline const T& operator() (int row, int col) const { return m_data[col][row]; } inline T& operator() (int row, int col) { return m_data[col][row]; } Array getRowMajorData (void) const; Array getColumnMajorData (void) const; private: Vector, Cols> m_data; } DE_WARN_UNUSED_TYPE; // Operators. // Mat * Mat. template Matrix operator* (const Matrix& a, const Matrix& b); // Mat * Vec (column vector). template Vector operator* (const Matrix& mtx, const Vector& vec); // Vec * Mat (row vector). template Vector operator* (const Vector& vec, const Matrix& mtx); // Further operations template struct SquareMatrixOps { static T doDeterminant (const Matrix& mat); static Matrix doInverse (const Matrix& mat); }; template struct SquareMatrixOps { static T doDeterminant (const Matrix& mat); static Matrix doInverse (const Matrix& mat); }; template struct SquareMatrixOps { static T doDeterminant (const Matrix& mat); static Matrix doInverse (const Matrix& mat); }; template struct SquareMatrixOps { static T doDeterminant (const Matrix& mat); static Matrix doInverse (const Matrix& mat); }; namespace matrix { template T determinant (const Matrix& mat) { return SquareMatrixOps::doDeterminant(mat); } template Matrix inverse (const Matrix& mat) { return SquareMatrixOps::doInverse(mat); } } // matrix // Template implementations. template T SquareMatrixOps::doDeterminant (const Matrix& mat) { return mat(0,0) * mat(1,1) - mat(1,0) * mat(0,1); } template T SquareMatrixOps::doDeterminant (const Matrix& mat) { return + mat(0,0) * mat(1,1) * mat(2,2) + mat(0,1) * mat(1,2) * mat(2,0) + mat(0,2) * mat(1,0) * mat(2,1) - mat(0,0) * mat(1,2) * mat(2,1) - mat(0,1) * mat(1,0) * mat(2,2) - mat(0,2) * mat(1,1) * mat(2,0); } template T SquareMatrixOps::doDeterminant (const Matrix& mat) { using matrix::determinant; const T minorMatrices[4][3*3] = { { mat(1,1), mat(2,1), mat(3,1), mat(1,2), mat(2,2), mat(3,2), mat(1,3), mat(2,3), mat(3,3), }, { mat(1,0), mat(2,0), mat(3,0), mat(1,2), mat(2,2), mat(3,2), mat(1,3), mat(2,3), mat(3,3), }, { mat(1,0), mat(2,0), mat(3,0), mat(1,1), mat(2,1), mat(3,1), mat(1,3), mat(2,3), mat(3,3), }, { mat(1,0), mat(2,0), mat(3,0), mat(1,1), mat(2,1), mat(3,1), mat(1,2), mat(2,2), mat(3,2), } }; return + mat(0,0) * determinant(Matrix(minorMatrices[0])) - mat(0,1) * determinant(Matrix(minorMatrices[1])) + mat(0,2) * determinant(Matrix(minorMatrices[2])) - mat(0,3) * determinant(Matrix(minorMatrices[3])); } template Matrix SquareMatrixOps::doInverse (const Matrix& mat) { using matrix::determinant; const T det = determinant(mat); Matrix retVal; retVal(0, 0) = mat(1, 1) / det; retVal(0, 1) = -mat(0, 1) / det; retVal(1, 0) = -mat(1, 0) / det; retVal(1, 1) = mat(0, 0) / det; return retVal; } template Matrix SquareMatrixOps::doInverse (const Matrix& mat) { // Blockwise inversion using matrix::inverse; const T areaA[2*2] = { mat(0,0), mat(0,1), mat(1,0), mat(1,1) }; const T areaB[2] = { mat(0,2), mat(1,2), }; const T areaC[2] = { mat(2,0), mat(2,1), }; const T areaD[1] = { mat(2,2) }; const T nullField[4] = { T(0.0f) }; const Matrix invA = inverse(Matrix(areaA)); const Matrix matB = Matrix(areaB); const Matrix matC = Matrix(areaC); const Matrix matD = Matrix(areaD); const T schurComplement = T(1.0f) / (matD - matC*invA*matB)(0,0); const Matrix zeroMat = Matrix(nullField); const Matrix blockA = invA + invA*matB*schurComplement*matC*invA; const Matrix blockB = (zeroMat-invA)*matB*schurComplement; const Matrix blockC = matC*invA*(-schurComplement); const T blockD = schurComplement; const T result[3*3] = { blockA(0,0), blockA(0,1), blockB(0,0), blockA(1,0), blockA(1,1), blockB(1,0), blockC(0,0), blockC(0,1), blockD, }; return Matrix(result); } template Matrix SquareMatrixOps::doInverse (const Matrix& mat) { // Blockwise inversion using matrix::inverse; const T areaA[2*2] = { mat(0,0), mat(0,1), mat(1,0), mat(1,1) }; const T areaB[2*2] = { mat(0,2), mat(0,3), mat(1,2), mat(1,3) }; const T areaC[2*2] = { mat(2,0), mat(2,1), mat(3,0), mat(3,1) }; const T areaD[2*2] = { mat(2,2), mat(2,3), mat(3,2), mat(3,3) }; const T nullField[4] = { T(0.0f) }; const Matrix invA = inverse(Matrix(areaA)); const Matrix matB = Matrix(areaB); const Matrix matC = Matrix(areaC); const Matrix matD = Matrix(areaD); const Matrix schurComplement = inverse(matD - matC*invA*matB); const Matrix zeroMat = Matrix(nullField); const Matrix blockA = invA + invA*matB*schurComplement*matC*invA; const Matrix blockB = (zeroMat-invA)*matB*schurComplement; const Matrix blockC = (zeroMat-schurComplement)*matC*invA; const Matrix blockD = schurComplement; const T result[4*4] = { blockA(0,0), blockA(0,1), blockB(0,0), blockB(0,1), blockA(1,0), blockA(1,1), blockB(1,0), blockB(1,1), blockC(0,0), blockC(0,1), blockD(0,0), blockD(0,1), blockC(1,0), blockC(1,1), blockD(1,0), blockD(1,1), }; return Matrix(result); } // Initialize to identity. template Matrix::Matrix (void) { for (int row = 0; row < Rows; row++) for (int col = 0; col < Cols; col++) (*this)(row, col) = (row == col) ? T(1) : T(0); } // Initialize to diagonal matrix. template Matrix::Matrix (const T& src) { for (int row = 0; row < Rows; row++) for (int col = 0; col < Cols; col++) (*this)(row, col) = (row == col) ? src : T(0); } // Initialize from data array. template Matrix::Matrix (const T src[Rows*Cols]) { for (int row = 0; row < Rows; row++) for (int col = 0; col < Cols; col++) (*this)(row, col) = src[row*Cols + col]; } // Initialize to diagonal matrix. template Matrix::Matrix (const Vector& src) { DE_STATIC_ASSERT(Rows == Cols); for (int row = 0; row < Rows; row++) for (int col = 0; col < Cols; col++) (*this)(row, col) = (row == col) ? src.m_data[row] : T(0); } // Copy constructor. template Matrix::Matrix (const Matrix& src) { *this = src; } // Destructor. template Matrix::~Matrix (void) { } // Assignment operator. template Matrix& Matrix::operator= (const Matrix& src) { for (int row = 0; row < Rows; row++) for (int col = 0; col < Cols; col++) (*this)(row, col) = src(row, col); return *this; } // Multipy and assign op template Matrix& Matrix::operator*= (const Matrix& src) { *this = *this * src; return *this; } template void Matrix::setRow (int rowNdx, const Vector& vec) { for (int col = 0; col < Cols; col++) (*this)(rowNdx, col) = vec.m_data[col]; } template void Matrix::setColumn (int colNdx, const Vector& vec) { m_data[colNdx] = vec; } template Vector Matrix::getRow (int rowNdx) const { Vector res; for (int col = 0; col < Cols; col++) res[col] = (*this)(rowNdx, col); return res; } template Vector& Matrix::getColumn (int colNdx) { return m_data[colNdx]; } template const Vector& Matrix::getColumn (int colNdx) const { return m_data[colNdx]; } template Array Matrix::getColumnMajorData (void) const { Array a; T* dst = a.getPtr(); for (int col = 0; col < Cols; col++) for (int row = 0; row < Rows; row++) *dst++ = (*this)(row, col); return a; } template Array Matrix::getRowMajorData (void) const { Array a; T* dst = a.getPtr(); for (int row = 0; row < Rows; row++) for (int col = 0; col < Cols; col++) *dst++ = (*this)(row, col); return a; } // Multiplication of two matrices. template Matrix operator* (const Matrix& a, const Matrix& b) { DE_STATIC_ASSERT(Cols0 == Rows1); Matrix res; for (int row = 0; row < Rows0; row++) { for (int col = 0; col < Cols1; col++) { T v = T(0); for (int ndx = 0; ndx < Cols0; ndx++) v += a(row,ndx) * b(ndx,col); res(row,col) = v; } } return res; } // Multiply of matrix with column vector. template Vector operator* (const Matrix& mtx, const Vector& vec) { Vector res; for (int row = 0; row < Rows; row++) { T v = T(0); for (int col = 0; col < Cols; col++) v += mtx(row,col) * vec.m_data[col]; res.m_data[row] = v; } return res; } // Multiply of matrix with row vector. template Vector operator* (const Vector& vec, const Matrix& mtx) { Vector res; for (int col = 0; col < Cols; col++) { T v = T(0); for (int row = 0; row < Rows; row++) v += mtx(row,col) * vec.m_data[row]; res.m_data[col] = v; } return res; } // Common typedefs. typedef Matrix Matrix2f; typedef Matrix Matrix3f; typedef Matrix Matrix4f; typedef Matrix Matrix2d; typedef Matrix Matrix3d; typedef Matrix Matrix4d; // GLSL-style naming \note CxR. typedef Matrix2f Mat2; typedef Matrix Mat2x3; typedef Matrix Mat2x4; typedef Matrix Mat3x2; typedef Matrix3f Mat3; typedef Matrix Mat3x4; typedef Matrix Mat4x2; typedef Matrix Mat4x3; typedef Matrix4f Mat4; // Matrix-scalar operators. template Matrix operator+ (const Matrix& mtx, T scalar) { Matrix res; for (int col = 0; col < Cols; col++) for (int row = 0; row < Rows; row++) res(row, col) = mtx(row, col) + scalar; return res; } template Matrix operator- (const Matrix& mtx, T scalar) { Matrix res; for (int col = 0; col < Cols; col++) for (int row = 0; row < Rows; row++) res(row, col) = mtx(row, col) - scalar; return res; } template Matrix operator* (const Matrix& mtx, T scalar) { Matrix res; for (int col = 0; col < Cols; col++) for (int row = 0; row < Rows; row++) res(row, col) = mtx(row, col) * scalar; return res; } template Matrix operator/ (const Matrix& mtx, T scalar) { Matrix res; for (int col = 0; col < Cols; col++) for (int row = 0; row < Rows; row++) res(row, col) = mtx(row, col) / scalar; return res; } // Matrix-matrix component-wise operators. template Matrix operator+ (const Matrix& a, const Matrix& b) { Matrix res; for (int col = 0; col < Cols; col++) for (int row = 0; row < Rows; row++) res(row, col) = a(row, col) + b(row, col); return res; } template Matrix operator- (const Matrix& a, const Matrix& b) { Matrix res; for (int col = 0; col < Cols; col++) for (int row = 0; row < Rows; row++) res(row, col) = a(row, col) - b(row, col); return res; } template Matrix operator/ (const Matrix& a, const Matrix& b) { Matrix res; for (int col = 0; col < Cols; col++) for (int row = 0; row < Rows; row++) res(row, col) = a(row, col) / b(row, col); return res; } } // tcu #endif // _TCUMATRIX_HPP