Home | History | Annotate | Download | only in common
      1 #ifndef _TCUMATRIX_HPP
      2 #define _TCUMATRIX_HPP
      3 /*-------------------------------------------------------------------------
      4  * drawElements Quality Program Tester Core
      5  * ----------------------------------------
      6  *
      7  * Copyright 2014 The Android Open Source Project
      8  *
      9  * Licensed under the Apache License, Version 2.0 (the "License");
     10  * you may not use this file except in compliance with the License.
     11  * You may obtain a copy of the License at
     12  *
     13  *      http://www.apache.org/licenses/LICENSE-2.0
     14  *
     15  * Unless required by applicable law or agreed to in writing, software
     16  * distributed under the License is distributed on an "AS IS" BASIS,
     17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     18  * See the License for the specific language governing permissions and
     19  * limitations under the License.
     20  *
     21  *//*!
     22  * \file
     23  * \brief Templatized matrix class.
     24  *//*--------------------------------------------------------------------*/
     25 
     26 #include "tcuDefs.hpp"
     27 #include "tcuVector.hpp"
     28 #include "tcuArray.hpp"
     29 
     30 namespace tcu
     31 {
     32 
     33 // Templated matrix class.
     34 template <typename T, int Rows, int Cols>
     35 class Matrix
     36 {
     37 public:
     38 	typedef	Vector<T, Rows>			Element;
     39 	typedef	T						Scalar;
     40 
     41 	enum
     42 	{
     43 		SIZE = Cols,
     44 		ROWS = Rows,
     45 		COLS = Cols,
     46 	};
     47 
     48 									Matrix				(void);
     49 	explicit						Matrix				(const T& src);
     50 	explicit						Matrix				(const T src[Rows*Cols]);
     51 									Matrix				(const Vector<T, Rows>& src);
     52 									Matrix				(const Matrix<T, Rows, Cols>& src);
     53 									~Matrix				(void);
     54 
     55 	Matrix<T, Rows, Cols>&			operator=			(const Matrix<T, Rows, Cols>& src);
     56 	Matrix<T, Rows, Cols>&			operator*=			(const Matrix<T, Rows, Cols>& src);
     57 
     58 	void							setRow				(int rowNdx, const Vector<T, Cols>& vec);
     59 	void							setColumn			(int colNdx, const Vector<T, Rows>& vec);
     60 
     61 	Vector<T, Cols>					getRow				(int ndx) const;
     62 	Vector<T, Rows>&				getColumn			(int ndx);
     63 	const Vector<T, Rows>&			getColumn			(int ndx) const;
     64 
     65 	Vector<T, Rows>&				operator[]			(int ndx)					{ return getColumn(ndx);	}
     66 	const Vector<T, Rows>&			operator[]			(int ndx) const				{ return getColumn(ndx);	}
     67 
     68 	inline const T&					operator()			(int row, int col) const	{ return m_data[col][row];	}
     69 	inline T&						operator()			(int row, int col)			{ return m_data[col][row];	}
     70 
     71 	Array<T, Rows*Cols>				getRowMajorData		(void) const;
     72 	Array<T, Rows*Cols>				getColumnMajorData	(void) const;
     73 
     74 private:
     75 	Vector<Vector<T, Rows>, Cols>	m_data;
     76 } DE_WARN_UNUSED_TYPE;
     77 
     78 // Operators.
     79 
     80 // Mat * Mat.
     81 template <typename T, int Rows0, int Cols0, int Rows1, int Cols1>
     82 Matrix<T, Rows0, Cols1> operator* (const Matrix<T, Rows0, Cols0>& a, const Matrix<T, Rows1, Cols1>& b);
     83 
     84 // Mat * Vec (column vector).
     85 template <typename T, int Rows, int Cols>
     86 Vector<T, Rows> operator* (const Matrix<T, Rows, Cols>& mtx, const Vector<T, Cols>& vec);
     87 
     88 // Vec * Mat (row vector).
     89 template <typename T, int Rows, int Cols>
     90 Vector<T, Cols> operator* (const Vector<T, Rows>& vec, const Matrix<T, Rows, Cols>& mtx);
     91 
     92 // Further operations
     93 
     94 template <typename T, int Size>
     95 struct SquareMatrixOps
     96 {
     97 	static T						doDeterminant	(const Matrix<T, Size, Size>& mat);
     98 	static Matrix<T, Size, Size>	doInverse		(const Matrix<T, Size, Size>& mat);
     99 };
    100 
    101 template <typename T>
    102 struct SquareMatrixOps<T, 2>
    103 {
    104 	static T						doDeterminant	(const Matrix<T, 2, 2>& mat);
    105 	static Matrix<T, 2, 2>			doInverse		(const Matrix<T, 2, 2>& mat);
    106 };
    107 
    108 template <typename T>
    109 struct SquareMatrixOps<T, 3>
    110 {
    111 	static T						doDeterminant	(const Matrix<T, 3, 3>& mat);
    112 	static Matrix<T, 3, 3>			doInverse		(const Matrix<T, 3, 3>& mat);
    113 };
    114 
    115 template <typename T>
    116 struct SquareMatrixOps<T, 4>
    117 {
    118 	static T						doDeterminant	(const Matrix<T, 4, 4>& mat);
    119 	static Matrix<T, 4, 4>			doInverse		(const Matrix<T, 4, 4>& mat);
    120 };
    121 
    122 namespace matrix
    123 {
    124 
    125 template <typename T, int Size>
    126 T determinant (const Matrix<T, Size, Size>& mat)
    127 {
    128 	return SquareMatrixOps<T, Size>::doDeterminant(mat);
    129 }
    130 
    131 template <typename T, int Size>
    132 Matrix<T, Size, Size> inverse (const Matrix<T, Size, Size>& mat)
    133 {
    134 	return SquareMatrixOps<T, Size>::doInverse(mat);
    135 }
    136 
    137 } // matrix
    138 
    139 // Template implementations.
    140 
    141 template <typename T>
    142 T SquareMatrixOps<T, 2>::doDeterminant (const Matrix<T, 2, 2>& mat)
    143 {
    144 	return mat(0,0) * mat(1,1) - mat(1,0) * mat(0,1);
    145 }
    146 
    147 template <typename T>
    148 T SquareMatrixOps<T, 3>::doDeterminant (const Matrix<T, 3, 3>& mat)
    149 {
    150 	return	+ mat(0,0) * mat(1,1) * mat(2,2)
    151 			+ mat(0,1) * mat(1,2) * mat(2,0)
    152 			+ mat(0,2) * mat(1,0) * mat(2,1)
    153 			- mat(0,0) * mat(1,2) * mat(2,1)
    154 			- mat(0,1) * mat(1,0) * mat(2,2)
    155 			- mat(0,2) * mat(1,1) * mat(2,0);
    156 }
    157 
    158 template <typename T>
    159 T SquareMatrixOps<T, 4>::doDeterminant (const Matrix<T, 4, 4>& mat)
    160 {
    161 	using matrix::determinant;
    162 
    163 	const T minorMatrices[4][3*3] =
    164 	{
    165 		{
    166 			mat(1,1),	mat(2,1),	mat(3,1),
    167 			mat(1,2),	mat(2,2),	mat(3,2),
    168 			mat(1,3),	mat(2,3),	mat(3,3),
    169 		},
    170 		{
    171 			mat(1,0),	mat(2,0),	mat(3,0),
    172 			mat(1,2),	mat(2,2),	mat(3,2),
    173 			mat(1,3),	mat(2,3),	mat(3,3),
    174 		},
    175 		{
    176 			mat(1,0),	mat(2,0),	mat(3,0),
    177 			mat(1,1),	mat(2,1),	mat(3,1),
    178 			mat(1,3),	mat(2,3),	mat(3,3),
    179 		},
    180 		{
    181 			mat(1,0),	mat(2,0),	mat(3,0),
    182 			mat(1,1),	mat(2,1),	mat(3,1),
    183 			mat(1,2),	mat(2,2),	mat(3,2),
    184 		}
    185 	};
    186 
    187 	return	+ mat(0,0) * determinant(Matrix<T, 3, 3>(minorMatrices[0]))
    188 			- mat(0,1) * determinant(Matrix<T, 3, 3>(minorMatrices[1]))
    189 			+ mat(0,2) * determinant(Matrix<T, 3, 3>(minorMatrices[2]))
    190 			- mat(0,3) * determinant(Matrix<T, 3, 3>(minorMatrices[3]));
    191 }
    192 
    193 template <typename T>
    194 Matrix<T, 2, 2> SquareMatrixOps<T, 2>::doInverse (const Matrix<T, 2, 2>& mat)
    195 {
    196 	using matrix::determinant;
    197 
    198 	const T			det		= determinant(mat);
    199 	Matrix<T, 2, 2>	retVal;
    200 
    201 	retVal(0, 0) =  mat(1, 1) / det;
    202 	retVal(0, 1) = -mat(0, 1) / det;
    203 	retVal(1, 0) = -mat(1, 0) / det;
    204 	retVal(1, 1) =  mat(0, 0) / det;
    205 
    206 	return retVal;
    207 }
    208 
    209 template <typename T>
    210 Matrix<T, 3, 3> SquareMatrixOps<T, 3>::doInverse (const Matrix<T, 3, 3>& mat)
    211 {
    212 	// Blockwise inversion
    213 	using matrix::inverse;
    214 
    215 	const T areaA[2*2] =
    216 	{
    217 		mat(0,0),	mat(0,1),
    218 		mat(1,0),	mat(1,1)
    219 	};
    220 	const T areaB[2] =
    221 	{
    222 		mat(0,2),
    223 		mat(1,2),
    224 	};
    225 	const T areaC[2] =
    226 	{
    227 		mat(2,0),	mat(2,1),
    228 	};
    229 	const T areaD[1] =
    230 	{
    231 		mat(2,2)
    232 	};
    233 	const T nullField[4] = { T(0.0f) };
    234 
    235 	const Matrix<T, 2, 2>	invA = inverse(Matrix<T, 2, 2>(areaA));
    236 	const Matrix<T, 2, 1>	matB =         Matrix<T, 2, 1>(areaB);
    237 	const Matrix<T, 1, 2>	matC =         Matrix<T, 1, 2>(areaC);
    238 	const Matrix<T, 1, 1>	matD =         Matrix<T, 1, 1>(areaD);
    239 
    240 	const T					schurComplement = T(1.0f) / (matD - matC*invA*matB)(0,0);
    241 	const Matrix<T, 2, 2>	zeroMat         = Matrix<T, 2, 2>(nullField);
    242 
    243 	const Matrix<T, 2, 2>	blockA = invA + invA*matB*schurComplement*matC*invA;
    244 	const Matrix<T, 2, 1>	blockB = (zeroMat-invA)*matB*schurComplement;
    245 	const Matrix<T, 1, 2>	blockC = matC*invA*(-schurComplement);
    246 	const T					blockD = schurComplement;
    247 
    248 	const T result[3*3] =
    249 	{
    250 		blockA(0,0),	blockA(0,1),	blockB(0,0),
    251 		blockA(1,0),	blockA(1,1),	blockB(1,0),
    252 		blockC(0,0),	blockC(0,1),	blockD,
    253 	};
    254 
    255 	return Matrix<T, 3, 3>(result);
    256 }
    257 
    258 template <typename T>
    259 Matrix<T, 4, 4> SquareMatrixOps<T, 4>::doInverse (const Matrix<T, 4, 4>& mat)
    260 {
    261 	// Blockwise inversion
    262 	using matrix::inverse;
    263 
    264 	const T areaA[2*2] =
    265 	{
    266 		mat(0,0),	mat(0,1),
    267 		mat(1,0),	mat(1,1)
    268 	};
    269 	const T areaB[2*2] =
    270 	{
    271 		mat(0,2),	mat(0,3),
    272 		mat(1,2),	mat(1,3)
    273 	};
    274 	const T areaC[2*2] =
    275 	{
    276 		mat(2,0),	mat(2,1),
    277 		mat(3,0),	mat(3,1)
    278 	};
    279 	const T areaD[2*2] =
    280 	{
    281 		mat(2,2),	mat(2,3),
    282 		mat(3,2),	mat(3,3)
    283 	};
    284 	const T nullField[4] = { T(0.0f) };
    285 
    286 	const Matrix<T, 2, 2> invA = inverse(Matrix<T, 2, 2>(areaA));
    287 	const Matrix<T, 2, 2> matB =         Matrix<T, 2, 2>(areaB);
    288 	const Matrix<T, 2, 2> matC =         Matrix<T, 2, 2>(areaC);
    289 	const Matrix<T, 2, 2> matD =         Matrix<T, 2, 2>(areaD);
    290 
    291 	const Matrix<T, 2, 2> schurComplement = inverse(matD - matC*invA*matB);
    292 	const Matrix<T, 2, 2> zeroMat         = Matrix<T, 2, 2>(nullField);
    293 
    294 	const Matrix<T, 2, 2> blockA = invA + invA*matB*schurComplement*matC*invA;
    295 	const Matrix<T, 2, 2> blockB = (zeroMat-invA)*matB*schurComplement;
    296 	const Matrix<T, 2, 2> blockC = (zeroMat-schurComplement)*matC*invA;
    297 	const Matrix<T, 2, 2> blockD = schurComplement;
    298 
    299 	const T result[4*4] =
    300 	{
    301 		blockA(0,0),	blockA(0,1),	blockB(0,0),	blockB(0,1),
    302 		blockA(1,0),	blockA(1,1),	blockB(1,0),	blockB(1,1),
    303 		blockC(0,0),	blockC(0,1),	blockD(0,0),	blockD(0,1),
    304 		blockC(1,0),	blockC(1,1),	blockD(1,0),	blockD(1,1),
    305 	};
    306 
    307 	return Matrix<T, 4, 4>(result);
    308 }
    309 
    310 // Initialize to identity.
    311 template <typename T, int Rows, int Cols>
    312 Matrix<T, Rows, Cols>::Matrix (void)
    313 {
    314 	for (int row = 0; row < Rows; row++)
    315 		for (int col = 0; col < Cols; col++)
    316 			(*this)(row, col) = (row == col) ? T(1) : T(0);
    317 }
    318 
    319 // Initialize to diagonal matrix.
    320 template <typename T, int Rows, int Cols>
    321 Matrix<T, Rows, Cols>::Matrix (const T& src)
    322 {
    323 	for (int row = 0; row < Rows; row++)
    324 		for (int col = 0; col < Cols; col++)
    325 			(*this)(row, col) = (row == col) ? src : T(0);
    326 }
    327 
    328 // Initialize from data array.
    329 template <typename T, int Rows, int Cols>
    330 Matrix<T, Rows, Cols>::Matrix (const T src[Rows*Cols])
    331 {
    332 	for (int row = 0; row < Rows; row++)
    333 		for (int col = 0; col < Cols; col++)
    334 			(*this)(row, col) = src[row*Cols + col];
    335 }
    336 
    337 // Initialize to diagonal matrix.
    338 template <typename T, int Rows, int Cols>
    339 Matrix<T, Rows, Cols>::Matrix (const Vector<T, Rows>& src)
    340 {
    341 	DE_STATIC_ASSERT(Rows == Cols);
    342 	for (int row = 0; row < Rows; row++)
    343 		for (int col = 0; col < Cols; col++)
    344 			(*this)(row, col) = (row == col) ? src.m_data[row] : T(0);
    345 }
    346 
    347 // Copy constructor.
    348 template <typename T, int Rows, int Cols>
    349 Matrix<T, Rows, Cols>::Matrix (const Matrix<T, Rows, Cols>& src)
    350 {
    351 	*this = src;
    352 }
    353 
    354 // Destructor.
    355 template <typename T, int Rows, int Cols>
    356 Matrix<T, Rows, Cols>::~Matrix (void)
    357 {
    358 }
    359 
    360 // Assignment operator.
    361 template <typename T, int Rows, int Cols>
    362 Matrix<T, Rows, Cols>& Matrix<T, Rows, Cols>::operator= (const Matrix<T, Rows, Cols>& src)
    363 {
    364 	for (int row = 0; row < Rows; row++)
    365 		for (int col = 0; col < Cols; col++)
    366 			(*this)(row, col) = src(row, col);
    367 	return *this;
    368 }
    369 
    370 // Multipy and assign op
    371 template <typename T, int Rows, int Cols>
    372 Matrix<T, Rows, Cols>& Matrix<T, Rows, Cols>::operator*= (const Matrix<T, Rows, Cols>& src)
    373 {
    374 	*this = *this * src;
    375 	return *this;
    376 }
    377 
    378 template <typename T, int Rows, int Cols>
    379 void Matrix<T, Rows, Cols>::setRow (int rowNdx, const Vector<T, Cols>& vec)
    380 {
    381 	for (int col = 0; col < Cols; col++)
    382 		(*this)(rowNdx, col) = vec.m_data[col];
    383 }
    384 
    385 template <typename T, int Rows, int Cols>
    386 void Matrix<T, Rows, Cols>::setColumn (int colNdx, const Vector<T, Rows>& vec)
    387 {
    388 	m_data[colNdx] = vec;
    389 }
    390 
    391 template <typename T, int Rows, int Cols>
    392 Vector<T, Cols> Matrix<T, Rows, Cols>::getRow (int rowNdx) const
    393 {
    394 	Vector<T, Cols> res;
    395 	for (int col = 0; col < Cols; col++)
    396 		res[col] = (*this)(rowNdx, col);
    397 	return res;
    398 }
    399 
    400 template <typename T, int Rows, int Cols>
    401 Vector<T, Rows>& Matrix<T, Rows, Cols>::getColumn (int colNdx)
    402 {
    403 	return m_data[colNdx];
    404 }
    405 
    406 template <typename T, int Rows, int Cols>
    407 const Vector<T, Rows>& Matrix<T, Rows, Cols>::getColumn (int colNdx) const
    408 {
    409 	return m_data[colNdx];
    410 }
    411 
    412 template <typename T, int Rows, int Cols>
    413 Array<T, Rows*Cols> Matrix<T, Rows, Cols>::getColumnMajorData (void) const
    414 {
    415 	Array<T, Rows*Cols> a;
    416 	T* dst = a.getPtr();
    417 	for (int col = 0; col < Cols; col++)
    418 		for (int row = 0; row < Rows; row++)
    419 			*dst++ = (*this)(row, col);
    420 	return a;
    421 }
    422 
    423 template <typename T, int Rows, int Cols>
    424 Array<T, Rows*Cols> Matrix<T, Rows, Cols>::getRowMajorData (void) const
    425 {
    426 	Array<T, Rows*Cols> a;
    427 	T* dst = a.getPtr();
    428 	for (int row = 0; row < Rows; row++)
    429 		for (int col = 0; col < Cols; col++)
    430 			*dst++ = (*this)(row, col);
    431 	return a;
    432 }
    433 
    434 // Multiplication of two matrices.
    435 template <typename T, int Rows0, int Cols0, int Rows1, int Cols1>
    436 Matrix<T, Rows0, Cols1> operator* (const Matrix<T, Rows0, Cols0>& a, const Matrix<T, Rows1, Cols1>& b)
    437 {
    438 	DE_STATIC_ASSERT(Cols0 == Rows1);
    439 	Matrix<T, Rows0, Cols1> res;
    440 	for (int row = 0; row < Rows0; row++)
    441 	{
    442 		for (int col = 0; col < Cols1; col++)
    443 		{
    444 			T v = T(0);
    445 			for (int ndx = 0; ndx < Cols0; ndx++)
    446 				v += a(row,ndx) * b(ndx,col);
    447 			res(row,col) = v;
    448 		}
    449 	}
    450 	return res;
    451 }
    452 
    453 // Multiply of matrix with column vector.
    454 template <typename T, int Rows, int Cols>
    455 Vector<T, Rows> operator* (const Matrix<T, Rows, Cols>& mtx, const Vector<T, Cols>& vec)
    456 {
    457 	Vector<T, Rows> res;
    458 	for (int row = 0; row < Rows; row++)
    459 	{
    460 		T v = T(0);
    461 		for (int col = 0; col < Cols; col++)
    462 			v += mtx(row,col) * vec.m_data[col];
    463 		res.m_data[row] = v;
    464 	}
    465 	return res;
    466 }
    467 
    468 // Multiply of matrix with row vector.
    469 template <typename T, int Rows, int Cols>
    470 Vector<T, Cols> operator* (const Vector<T, Rows>& vec, const Matrix<T, Rows, Cols>& mtx)
    471 {
    472 	Vector<T, Cols> res;
    473 	for (int col = 0; col < Cols; col++)
    474 	{
    475 		T v = T(0);
    476 		for (int row = 0; row < Rows; row++)
    477 			v += mtx(row,col) * vec.m_data[row];
    478 		res.m_data[col] = v;
    479 	}
    480 	return res;
    481 }
    482 
    483 // Common typedefs.
    484 typedef Matrix<float, 2, 2>		Matrix2f;
    485 typedef Matrix<float, 3, 3>		Matrix3f;
    486 typedef Matrix<float, 4, 4>		Matrix4f;
    487 typedef Matrix<double, 2, 2>	Matrix2d;
    488 typedef Matrix<double, 3, 3>	Matrix3d;
    489 typedef Matrix<double, 4, 4>	Matrix4d;
    490 
    491 // GLSL-style naming \note CxR.
    492 typedef Matrix2f			Mat2;
    493 typedef Matrix<float, 3, 2>	Mat2x3;
    494 typedef Matrix<float, 4, 2>	Mat2x4;
    495 typedef Matrix<float, 2, 3>	Mat3x2;
    496 typedef Matrix3f			Mat3;
    497 typedef Matrix<float, 4, 3>	Mat3x4;
    498 typedef Matrix<float, 2, 4>	Mat4x2;
    499 typedef Matrix<float, 3, 4>	Mat4x3;
    500 typedef Matrix4f			Mat4;
    501 
    502 // Matrix-scalar operators.
    503 
    504 template <typename T, int Rows, int Cols>
    505 Matrix<T, Rows, Cols> operator+ (const Matrix<T, Rows, Cols>& mtx, T scalar)
    506 {
    507 	Matrix<T, Rows, Cols> res;
    508 	for (int col = 0; col < Cols; col++)
    509 		for (int row = 0; row < Rows; row++)
    510 			res(row, col) = mtx(row, col) + scalar;
    511 	return res;
    512 }
    513 
    514 template <typename T, int Rows, int Cols>
    515 Matrix<T, Rows, Cols> operator- (const Matrix<T, Rows, Cols>& mtx, T scalar)
    516 {
    517 	Matrix<T, Rows, Cols> res;
    518 	for (int col = 0; col < Cols; col++)
    519 		for (int row = 0; row < Rows; row++)
    520 			res(row, col) = mtx(row, col) - scalar;
    521 	return res;
    522 }
    523 
    524 template <typename T, int Rows, int Cols>
    525 Matrix<T, Rows, Cols> operator* (const Matrix<T, Rows, Cols>& mtx, T scalar)
    526 {
    527 	Matrix<T, Rows, Cols> res;
    528 	for (int col = 0; col < Cols; col++)
    529 		for (int row = 0; row < Rows; row++)
    530 			res(row, col) = mtx(row, col) * scalar;
    531 	return res;
    532 }
    533 
    534 template <typename T, int Rows, int Cols>
    535 Matrix<T, Rows, Cols> operator/ (const Matrix<T, Rows, Cols>& mtx, T scalar)
    536 {
    537 	Matrix<T, Rows, Cols> res;
    538 	for (int col = 0; col < Cols; col++)
    539 		for (int row = 0; row < Rows; row++)
    540 			res(row, col) = mtx(row, col) / scalar;
    541 	return res;
    542 }
    543 
    544 // Matrix-matrix component-wise operators.
    545 
    546 template <typename T, int Rows, int Cols>
    547 Matrix<T, Rows, Cols> operator+ (const Matrix<T, Rows, Cols>& a, const Matrix<T, Rows, Cols>& b)
    548 {
    549 	Matrix<T, Rows, Cols> res;
    550 	for (int col = 0; col < Cols; col++)
    551 		for (int row = 0; row < Rows; row++)
    552 			res(row, col) = a(row, col) + b(row, col);
    553 	return res;
    554 }
    555 
    556 template <typename T, int Rows, int Cols>
    557 Matrix<T, Rows, Cols> operator- (const Matrix<T, Rows, Cols>& a, const Matrix<T, Rows, Cols>& b)
    558 {
    559 	Matrix<T, Rows, Cols> res;
    560 	for (int col = 0; col < Cols; col++)
    561 		for (int row = 0; row < Rows; row++)
    562 			res(row, col) = a(row, col) - b(row, col);
    563 	return res;
    564 }
    565 
    566 template <typename T, int Rows, int Cols>
    567 Matrix<T, Rows, Cols> operator/ (const Matrix<T, Rows, Cols>& a, const Matrix<T, Rows, Cols>& b)
    568 {
    569 	Matrix<T, Rows, Cols> res;
    570 	for (int col = 0; col < Cols; col++)
    571 		for (int row = 0; row < Rows; row++)
    572 			res(row, col) = a(row, col) / b(row, col);
    573 	return res;
    574 }
    575 
    576 } // tcu
    577 
    578 #endif // _TCUMATRIX_HPP
    579