blob: 7131ee9b2ddee05de1327d482346c60f63556876 [file] [log] [blame]
#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 <typename T, int Rows, int Cols>
class Matrix
{
public:
typedef Vector<T, Rows> 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<T, Rows> &src);
Matrix(const Matrix<T, Rows, Cols> &src);
~Matrix(void);
Matrix<T, Rows, Cols> &operator=(const Matrix<T, Rows, Cols> &src);
Matrix<T, Rows, Cols> &operator*=(const Matrix<T, Rows, Cols> &src);
void setRow(int rowNdx, const Vector<T, Cols> &vec);
void setColumn(int colNdx, const Vector<T, Rows> &vec);
Vector<T, Cols> getRow(int ndx) const;
Vector<T, Rows> &getColumn(int ndx);
const Vector<T, Rows> &getColumn(int ndx) const;
Vector<T, Rows> &operator[](int ndx)
{
return getColumn(ndx);
}
const Vector<T, Rows> &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<T, Rows * Cols> getRowMajorData(void) const;
Array<T, Rows * Cols> getColumnMajorData(void) const;
private:
Vector<Vector<T, Rows>, Cols> m_data;
} DE_WARN_UNUSED_TYPE;
// Operators.
// Mat * Mat.
template <typename T, int Rows0, int Cols0, int Rows1, int Cols1>
Matrix<T, Rows0, Cols1> operator*(const Matrix<T, Rows0, Cols0> &a, const Matrix<T, Rows1, Cols1> &b);
// Mat * Vec (column vector).
template <typename T, int Rows, int Cols>
Vector<T, Rows> operator*(const Matrix<T, Rows, Cols> &mtx, const Vector<T, Cols> &vec);
// Vec * Mat (row vector).
template <typename T, int Rows, int Cols>
Vector<T, Cols> operator*(const Vector<T, Rows> &vec, const Matrix<T, Rows, Cols> &mtx);
template <typename T, int Rows, int Cols>
bool operator==(const Matrix<T, Rows, Cols> &lhs, const Matrix<T, Rows, Cols> &rhs);
template <typename T, int Rows, int Cols>
bool operator!=(const Matrix<T, Rows, Cols> &lhs, const Matrix<T, Rows, Cols> &rhs);
// Further operations
template <typename T, int Size>
struct SquareMatrixOps
{
static T doDeterminant(const Matrix<T, Size, Size> &mat);
static Matrix<T, Size, Size> doInverse(const Matrix<T, Size, Size> &mat);
};
template <typename T>
struct SquareMatrixOps<T, 2>
{
static T doDeterminant(const Matrix<T, 2, 2> &mat);
static Matrix<T, 2, 2> doInverse(const Matrix<T, 2, 2> &mat);
};
template <typename T>
struct SquareMatrixOps<T, 3>
{
static T doDeterminant(const Matrix<T, 3, 3> &mat);
static Matrix<T, 3, 3> doInverse(const Matrix<T, 3, 3> &mat);
};
template <typename T>
struct SquareMatrixOps<T, 4>
{
static T doDeterminant(const Matrix<T, 4, 4> &mat);
static Matrix<T, 4, 4> doInverse(const Matrix<T, 4, 4> &mat);
};
namespace matrix
{
template <typename T, int Size>
T determinant(const Matrix<T, Size, Size> &mat)
{
return SquareMatrixOps<T, Size>::doDeterminant(mat);
}
template <typename T, int Size>
Matrix<T, Size, Size> inverse(const Matrix<T, Size, Size> &mat)
{
return SquareMatrixOps<T, Size>::doInverse(mat);
}
} // namespace matrix
// Template implementations.
template <typename T>
T SquareMatrixOps<T, 2>::doDeterminant(const Matrix<T, 2, 2> &mat)
{
return mat(0, 0) * mat(1, 1) - mat(1, 0) * mat(0, 1);
}
template <typename T>
T SquareMatrixOps<T, 3>::doDeterminant(const Matrix<T, 3, 3> &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 <typename T>
T SquareMatrixOps<T, 4>::doDeterminant(const Matrix<T, 4, 4> &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<T, 3, 3>(minorMatrices[0])) -
mat(0, 1) * determinant(Matrix<T, 3, 3>(minorMatrices[1])) +
mat(0, 2) * determinant(Matrix<T, 3, 3>(minorMatrices[2])) -
mat(0, 3) * determinant(Matrix<T, 3, 3>(minorMatrices[3]));
}
template <typename T>
Matrix<T, 2, 2> SquareMatrixOps<T, 2>::doInverse(const Matrix<T, 2, 2> &mat)
{
using matrix::determinant;
const T det = determinant(mat);
Matrix<T, 2, 2> 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 <typename T>
Matrix<T, 3, 3> SquareMatrixOps<T, 3>::doInverse(const Matrix<T, 3, 3> &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<T, 2, 2> invA = inverse(Matrix<T, 2, 2>(areaA));
const Matrix<T, 2, 1> matB = Matrix<T, 2, 1>(areaB);
const Matrix<T, 1, 2> matC = Matrix<T, 1, 2>(areaC);
const Matrix<T, 1, 1> matD = Matrix<T, 1, 1>(areaD);
const T schurComplement = T(1.0f) / (matD - matC * invA * matB)(0, 0);
const Matrix<T, 2, 2> zeroMat = Matrix<T, 2, 2>(nullField);
const Matrix<T, 2, 2> blockA = invA + invA * matB * schurComplement * matC * invA;
const Matrix<T, 2, 1> blockB = (zeroMat - invA) * matB * schurComplement;
const Matrix<T, 1, 2> 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<T, 3, 3>(result);
}
template <typename T>
Matrix<T, 4, 4> SquareMatrixOps<T, 4>::doInverse(const Matrix<T, 4, 4> &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<T, 2, 2> invA = inverse(Matrix<T, 2, 2>(areaA));
const Matrix<T, 2, 2> matB = Matrix<T, 2, 2>(areaB);
const Matrix<T, 2, 2> matC = Matrix<T, 2, 2>(areaC);
const Matrix<T, 2, 2> matD = Matrix<T, 2, 2>(areaD);
const Matrix<T, 2, 2> schurComplement = inverse(matD - matC * invA * matB);
const Matrix<T, 2, 2> zeroMat = Matrix<T, 2, 2>(nullField);
const Matrix<T, 2, 2> blockA = invA + invA * matB * schurComplement * matC * invA;
const Matrix<T, 2, 2> blockB = (zeroMat - invA) * matB * schurComplement;
const Matrix<T, 2, 2> blockC = (zeroMat - schurComplement) * matC * invA;
const Matrix<T, 2, 2> 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<T, 4, 4>(result);
}
// Initialize to identity.
template <typename T, int Rows, int Cols>
Matrix<T, Rows, Cols>::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 <typename T, int Rows, int Cols>
Matrix<T, Rows, Cols>::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 <typename T, int Rows, int Cols>
Matrix<T, Rows, Cols>::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 <typename T, int Rows, int Cols>
Matrix<T, Rows, Cols>::Matrix(const Vector<T, Rows> &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 <typename T, int Rows, int Cols>
Matrix<T, Rows, Cols>::Matrix(const Matrix<T, Rows, Cols> &src)
{
*this = src;
}
// Destructor.
template <typename T, int Rows, int Cols>
Matrix<T, Rows, Cols>::~Matrix(void)
{
}
// Assignment operator.
template <typename T, int Rows, int Cols>
Matrix<T, Rows, Cols> &Matrix<T, Rows, Cols>::operator=(const Matrix<T, Rows, Cols> &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 <typename T, int Rows, int Cols>
Matrix<T, Rows, Cols> &Matrix<T, Rows, Cols>::operator*=(const Matrix<T, Rows, Cols> &src)
{
*this = *this * src;
return *this;
}
template <typename T, int Rows, int Cols>
void Matrix<T, Rows, Cols>::setRow(int rowNdx, const Vector<T, Cols> &vec)
{
for (int col = 0; col < Cols; col++)
(*this)(rowNdx, col) = vec.m_data[col];
}
template <typename T, int Rows, int Cols>
void Matrix<T, Rows, Cols>::setColumn(int colNdx, const Vector<T, Rows> &vec)
{
m_data[colNdx] = vec;
}
template <typename T, int Rows, int Cols>
Vector<T, Cols> Matrix<T, Rows, Cols>::getRow(int rowNdx) const
{
Vector<T, Cols> res;
for (int col = 0; col < Cols; col++)
res[col] = (*this)(rowNdx, col);
return res;
}
template <typename T, int Rows, int Cols>
Vector<T, Rows> &Matrix<T, Rows, Cols>::getColumn(int colNdx)
{
return m_data[colNdx];
}
template <typename T, int Rows, int Cols>
const Vector<T, Rows> &Matrix<T, Rows, Cols>::getColumn(int colNdx) const
{
return m_data[colNdx];
}
template <typename T, int Rows, int Cols>
Array<T, Rows * Cols> Matrix<T, Rows, Cols>::getColumnMajorData(void) const
{
Array<T, Rows * Cols> 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 <typename T, int Rows, int Cols>
Array<T, Rows * Cols> Matrix<T, Rows, Cols>::getRowMajorData(void) const
{
Array<T, Rows * Cols> 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 <typename T, int Rows0, int Cols0, int Rows1, int Cols1>
Matrix<T, Rows0, Cols1> operator*(const Matrix<T, Rows0, Cols0> &a, const Matrix<T, Rows1, Cols1> &b)
{
DE_STATIC_ASSERT(Cols0 == Rows1);
Matrix<T, Rows0, Cols1> 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 <typename T, int Rows, int Cols>
Vector<T, Rows> operator*(const Matrix<T, Rows, Cols> &mtx, const Vector<T, Cols> &vec)
{
Vector<T, Rows> 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 <typename T, int Rows, int Cols>
Vector<T, Cols> operator*(const Vector<T, Rows> &vec, const Matrix<T, Rows, Cols> &mtx)
{
Vector<T, Cols> 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<float, 2, 2> Matrix2f;
typedef Matrix<float, 3, 3> Matrix3f;
typedef Matrix<float, 4, 4> Matrix4f;
// GLSL-style naming \note CxR.
typedef Matrix2f Mat2;
typedef Matrix<float, 3, 2> Mat2x3;
typedef Matrix<float, 4, 2> Mat2x4;
typedef Matrix<float, 2, 3> Mat3x2;
typedef Matrix3f Mat3;
typedef Matrix<float, 4, 3> Mat3x4;
typedef Matrix<float, 2, 4> Mat4x2;
typedef Matrix<float, 3, 4> Mat4x3;
typedef Matrix4f Mat4;
//using tcu::Matrix;
// Common typedefs 16Bit.
typedef Matrix<uint16_t, 2, 2> Matrix2f16b;
typedef Matrix<uint16_t, 3, 3> Matrix3f16b;
typedef Matrix<uint16_t, 4, 4> Matrix4f16b;
// GLSL-style naming \note CxR.
typedef Matrix2f16b Mat2_16b;
typedef Matrix<uint16_t, 3, 2> Mat2x3_16b;
typedef Matrix<uint16_t, 4, 2> Mat2x4_16b;
typedef Matrix<uint16_t, 2, 3> Mat3x2_16b;
typedef Matrix3f16b Mat3_16b;
typedef Matrix<uint16_t, 4, 3> Mat3x4_16b;
typedef Matrix<uint16_t, 2, 4> Mat4x2_16b;
typedef Matrix<uint16_t, 3, 4> Mat4x3_16b;
typedef Matrix4f16b Mat4_16b;
// 64-bit matrices.
typedef Matrix<double, 2, 2> Matrix2d;
typedef Matrix<double, 3, 3> Matrix3d;
typedef Matrix<double, 4, 4> Matrix4d;
// GLSL-style naming \note CxR.
typedef Matrix2d Mat2d;
typedef Matrix<double, 3, 2> Mat2x3d;
typedef Matrix<double, 4, 2> Mat2x4d;
typedef Matrix<double, 2, 3> Mat3x2d;
typedef Matrix3d Mat3d;
typedef Matrix<double, 4, 3> Mat3x4d;
typedef Matrix<double, 2, 4> Mat4x2d;
typedef Matrix<double, 3, 4> Mat4x3d;
typedef Matrix4d Mat4d;
// Matrix-scalar operators.
template <typename T, int Rows, int Cols>
Matrix<T, Rows, Cols> operator+(const Matrix<T, Rows, Cols> &mtx, T scalar)
{
Matrix<T, Rows, Cols> 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 <typename T, int Rows, int Cols>
Matrix<T, Rows, Cols> operator-(const Matrix<T, Rows, Cols> &mtx, T scalar)
{
Matrix<T, Rows, Cols> 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 <typename T, int Rows, int Cols>
Matrix<T, Rows, Cols> operator*(const Matrix<T, Rows, Cols> &mtx, T scalar)
{
Matrix<T, Rows, Cols> 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 <typename T, int Rows, int Cols>
Matrix<T, Rows, Cols> operator/(const Matrix<T, Rows, Cols> &mtx, T scalar)
{
Matrix<T, Rows, Cols> 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 <typename T, int Rows, int Cols>
Matrix<T, Rows, Cols> operator+(const Matrix<T, Rows, Cols> &a, const Matrix<T, Rows, Cols> &b)
{
Matrix<T, Rows, Cols> 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 <typename T, int Rows, int Cols>
Matrix<T, Rows, Cols> operator-(const Matrix<T, Rows, Cols> &a, const Matrix<T, Rows, Cols> &b)
{
Matrix<T, Rows, Cols> 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 <typename T, int Rows, int Cols>
Matrix<T, Rows, Cols> operator/(const Matrix<T, Rows, Cols> &a, const Matrix<T, Rows, Cols> &b)
{
Matrix<T, Rows, Cols> 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 <typename T, int Rows, int Cols>
bool operator==(const Matrix<T, Rows, Cols> &lhs, const Matrix<T, Rows, Cols> &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 <typename T, int Rows, int Cols>
bool operator!=(const Matrix<T, Rows, Cols> &lhs, const Matrix<T, Rows, Cols> &rhs)
{
return !(lhs == rhs);
}
} // namespace tcu
#endif // _TCUMATRIX_HPP