#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); template bool operator==(const Matrix &lhs, const Matrix &rhs); template bool operator!=(const Matrix &lhs, const Matrix &rhs); // 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); } } // namespace 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; // 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; //using tcu::Matrix; // Common typedefs 16Bit. typedef Matrix Matrix2f16b; typedef Matrix Matrix3f16b; typedef Matrix Matrix4f16b; // GLSL-style naming \note CxR. typedef Matrix2f16b Mat2_16b; typedef Matrix Mat2x3_16b; typedef Matrix Mat2x4_16b; typedef Matrix Mat3x2_16b; typedef Matrix3f16b Mat3_16b; typedef Matrix Mat3x4_16b; typedef Matrix Mat4x2_16b; typedef Matrix Mat4x3_16b; typedef Matrix4f16b Mat4_16b; // 64-bit matrices. typedef Matrix Matrix2d; typedef Matrix Matrix3d; typedef Matrix Matrix4d; // GLSL-style naming \note CxR. typedef Matrix2d Mat2d; typedef Matrix Mat2x3d; typedef Matrix Mat2x4d; typedef Matrix Mat3x2d; typedef Matrix3d Mat3d; typedef Matrix Mat3x4d; typedef Matrix Mat4x2d; typedef Matrix Mat4x3d; typedef Matrix4d Mat4d; // 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; } template bool operator==(const Matrix &lhs, const Matrix &rhs) { for (int row = 0; row < Rows; row++) for (int col = 0; col < Cols; col++) if (lhs(row, col) != rhs(row, col)) return false; return true; } template bool operator!=(const Matrix &lhs, const Matrix &rhs) { return !(lhs == rhs); } } // namespace tcu #endif // _TCUMATRIX_HPP