Я начал реализовывать следующий класс Matrix, чтобы лучше понимать классы шаблонов в целом. На данный момент ему не хватает многих функций, он выполняет очень простые вещи:
- добавление
- умножение (здесь доступно только умножение матрицы X)
- транспонировать
- преобразование в строку
Вот некоторые моменты, которые, на мой взгляд, могут быть интересными
Размеры матриц могут быть «статическими» или «динамическими». Под статическим я подразумеваю, что количество строк / столбцов не может изменяться, даже если данные хранятся в std :: vector
При сложении двух матриц размер результирующей матрицы является статическим, если хотя бы один из двух операндов является статическим.
При умножении двух матриц вместе размер результирующей матрицы зависит от строк в левой части и столбцов в правой части символа «*».
Тип данных, содержащихся в возвращаемой матрице, соответствует неявному приведению типов левой и правой частей выражения. Если пользователь решил умножить матрицу Foos, с матрицей Бары, это на нем.
Метод changeSize при вызове статической матрицы срабатывает только в том случае, если запрошенное изменение отличается от размера матрицы.
Я пока не беспокоился о типе исключения, которое использовал, поскольку это скорее упражнение, чем то, что я буду использовать в реальном приложении.
Причина, по которой я сделал возможным создание статических или динамических матриц, заключается в том, что я хочу, чтобы они могли управлять операциями Vector X Matrix. Поскольку вектор — это просто частный случай матриц, я решил объединить их в один класс. (в стиле Eigen, на который мой код вдохновлен с точки зрения используемого интерфейса).
Правильно ли я использую ссылки rvalues и семантику перемещения? (об этом я узнал на прошлой неделе, любой совет может помочь)
Как вы думаете, что можно улучшить в моем коде?
Есть ли какое-то понятие, которое я должен изучить, прежде чем продолжить?
Были ли какие-либо варианты дизайна с точки зрения параметров шаблона хорошими или плохими?
#ifndef UTILS_MATRIX_H_
#define UTILS_MATRIX_H_
#include <vector>
#include <stdexcept>
#include <sstream>
#include <iomanip>
namespace mat
{
constexpr size_t DYNAMIC = static_cast<size_t>(-1); // [-] No matrix can be of this size... right?
template<typename TYPE, size_t NBROWS, size_t NBCOLS>
class Matrix
{
private:
std::vector<std::vector<TYPE>> matrixData; // [-] Contents of the Matrix as a 2D array
static constexpr bool isRowStatic = NBROWS != DYNAMIC; // [-] Is the number of rows of this matrix editable at run time
static constexpr bool isColStatic = NBCOLS != DYNAMIC; // [-] Is the number of columns of this matrix editable at run time
public:
/** @brief Default constructor
*
* @return Void.
*/
Matrix() :
matrixData()
{
if ((NBROWS <= 0 and NBROWS != DYNAMIC) or (NBCOLS <= 0 and NBCOLS != DYNAMIC))
throw std::runtime_error("The number of rows and columns of a static matrix must be positive integers");
// In case of a dynamic shape, the matrix should not be instanciated
if(isRowStatic and isColStatic)
internalChangeSize(NBROWS, NBCOLS);
}
/** @brief Consutuctor for the static size matrix
* @param i_DefaultValue IN : Default value used to fill
* the matrix
*
* @return Void.
*/
Matrix(const TYPE &i_DefaultValue) :
matrixData()
{
// error handling
if (not isRowStatic or not isColStatic)
throw std::runtime_error("The default value constructor can not be called on a Matrix with at least one dynamic component");
if ((NBROWS <= 0 and NBROWS != DYNAMIC) or (NBCOLS <= 0 and NBCOLS != DYNAMIC))
throw std::runtime_error("The number of rows and columns of a static matrix must be positive integers");
internalChangeSize(NBROWS, NBCOLS, i_DefaultValue);
}
/** @brief Consutuctor for the dynamic size matrix without default value
*
* @param i_Nbrows IN : Number of rows of the matrix
* @param i_Nbcols IN : Number of columns of the matrix
*
* @return Void.
*/
Matrix(const size_t i_Nbrows,
const size_t i_Nbcols) :
matrixData()
{
// error handling
if (i_Nbrows <= 0 or i_Nbcols <= 0)
throw std::runtime_error("The number or rows and columns has to be a positive integer");
// If one dimension is static, ignore the related constructor parameters
size_t NbRows = i_Nbrows;
size_t NbCols = i_Nbcols;
if(isRowStatic)
NbRows = NBROWS;
if(isColStatic)
NbCols = NBCOLS;
internalChangeSize(NbRows, NbCols, TYPE());
}
/** @brief Consutuctor for the dynamic size matrix with default value
*
* @param i_Nbrows IN : Number of rows of the matrix
* @param i_Nbcols IN : Number of columns of the matrix
* @param i_DefaultValue IN : Default value used to fill the
* matrix
*
* @return Void.
*/
Matrix(const size_t i_Nbrows,
const size_t i_Nbcols,
const TYPE &i_DefaultValue) :
matrixData()
{
// error handling
if (i_Nbrows <= 0 or i_Nbcols <= 0)
throw std::runtime_error("The number or rows and columns has to be a positive integer");
// If one dimension is static, ignore the related constructor parameters
size_t NbRows = i_Nbrows;
size_t NbCols = i_Nbcols;
if(isRowStatic)
NbRows = NBROWS;
if(isColStatic)
NbCols = NBCOLS;
internalChangeSize(NbRows, NbCols, i_DefaultValue);
}
/** @brief Copy constructor
*
* @param i_otherMatrix IN : Matrix to be copied
*
* @return Void.
*/
Matrix(const Matrix<TYPE, NBROWS, NBCOLS>& i_otherMatrix):
matrixData()
{
if(not i_otherMatrix.isEmpty())
{
changeSize(i_otherMatrix.getNbRows(), i_otherMatrix.getNbCols());
matrixData = i_otherMatrix.matrixData;
}
}
/** @brief Move constructor
*
* @param i_otherMatrix IN : Matrix to be moved
*
* @return Void.
*/
Matrix(Matrix<TYPE, NBROWS, NBCOLS>&& i_otherMatrix):
matrixData()
{
matrixData = std::move(i_otherMatrix.matrixData);
}
/** @brief getter for the matrix data vector
*
* @return std::vector<std::vector<TYPE>>&.
*/
const std::vector<std::vector<TYPE>>& getMatrixData() const
{
return matrixData;
}
/** @brief getter for the number or rows
*
* @return size_t
*/
size_t getNbRows() const
{
return matrixData.size();
}
/** @brief getter for the number or columns
*
* @return size_t
*/
size_t getNbCols() const
{
if(matrixData.size() > 0)
return matrixData[0].size();
else
return 0;
}
/** @brief is the Matrix is empty
*
* @return bool
*/
bool isEmpty() const
{
return getNbRows() == 0 or getNbCols() == 0;
}
/** @brief function used to retrieve the shape of the matrix
* @param o_NbRows OUT : Number of rows of the matrix
* @param o_NbCols OUT : Number of columns of the matrix
*
* @return Void.
*/
std::pair<size_t, size_t> shape() const
{
return std::pair<size_t, size_t>(getNbRows(), getNbCols());
}
/** @brief function used to print the contents of the
* matrix formatted into a string
*
* @return std::string
*/
std::string toString(int i_Precision = 10) const
{
std::ostringstream SS;
// if 0 lines representation is an empty bracket
if(matrixData.size() == 0)
SS << "| |" << std::endl;
// This will align the floating point numbers
SS << std::showpoint;
SS << std::setprecision(i_Precision);
for(auto& Row : matrixData)
{
SS << "|";
for(auto& Value : Row)
{
SS << " " << Value << " ";
}
SS << "|" << std::endl;
}
return SS.str();
}
/** @brief function used to change the size of the matrix
* This method does not require a default value,
* hence it is default initialized
*
* @param i_NbRows IN : New number of rows of the matrix
* @param o_NbCols IN : New number of columns of the matrix
*
* @return Void.
*/
void changeSize(const size_t i_NbRows, const size_t i_NbCols)
{
// Error handling
if (i_NbRows <= 0 or i_NbCols <= 0)
throw std::runtime_error("The number or rows and columns has to be a positive integer");
if (isRowStatic and NBROWS != i_NbRows)
throw std::runtime_error("You cannot change the number of rows, the matrix row size is static.");
if(isColStatic and NBCOLS != i_NbCols)
throw std::runtime_error("You cannot change the number of columns, the matrix columns size is static.");
internalChangeSize(i_NbRows, i_NbCols);
}
/** @brief function used to change the size of the matrix
* This method does not require a default value,
* hence it is default initialized
*
* @param i_NewShape IN : New shape of the matrix
*
* @return Void.
*/
void changeSize(const std::pair<size_t, size_t>& i_NewShape)
{
changeSize(i_NewShape.first, i_NewShape.second);
}
/** @brief function used to change the size of the matrix
* This method requires a default value for filling
* any new row / column.
*
* @param i_NbRows IN : New number of rows of the matrix
* @param o_NbCols IN : New number of columns of the matrix
* @param DefaultValue IN : Default value used to fill the matrix
*
* @return Void.
*/
void changeSize(const size_t i_NbRows, const size_t i_NbCols, const TYPE &DefaultValue)
{
// error handling
if (i_NbRows <= 0 or i_NbCols <= 0)
throw std::runtime_error("The number or rows and columns has to be a positive integer");
if (isRowStatic and NBROWS != i_NbRows)
throw std::runtime_error("You cannot change the number of rows, the matrix columns size is static.");
if(isColStatic and NBCOLS != i_NbCols)
throw std::runtime_error("You cannot change the number of columns, the matrix columns size is static.");
internalChangeSize(i_NbRows, i_NbCols, DefaultValue);
}
/** @brief function used to change the size of the matrix
* This method requires a default value for filling
* any new row / column.
*
* @param i_NewShape IN : New shape of the matrix
* @param DefaultValue IN : Default value used to fill the matrix
*
* @return Void.
*/
void changeSize(const std::pair<size_t, size_t>& i_NewShape, const TYPE &DefaultValue)
{
changeSize(i_NewShape.first, i_NewShape.second, DefaultValue);
}
/** @brief function used to transpose the current matrix.
* If the matrix is dynamically allocated, it's shape
* might be changed by the function
*
* @return Void.
*/
void transpose()
{
// Error handlingmatrixData
if (isEmpty())
throw std::runtime_error("The transpose function can not be called on an empty matrix");
if ((isRowStatic or isColStatic) and getNbRows() != getNbCols())
throw std::runtime_error("The transpose function can not be called on a non square matrix with at least one static component");
// The transposed Matrix is built and replaces the old data
std::vector<std::vector<TYPE>> newData(getNbCols(), std::vector<TYPE>(getNbRows(), (*this)(0,0)));
for (size_t i = 0 ; i < getNbCols() ; i += 1)
for (size_t j = 0 ; j < getNbRows() ; j += 1)
newData[i][j] = (*this)(i,j);
matrixData = std::move(newData);
}
/** @brief () operator. returns a reference to
* the value at row i, column j
*
* @return const TYPE&
*/
const TYPE& operator()(size_t i_Row, size_t i_Col) const
{
try
{
return matrixData.at(i_Row).at(i_Col);
}
catch(std::out_of_range& e)
{
const auto MatrixShape = this->shape();
std::ostringstream SS;
SS << "Indexes : (" << i_Row << ", " << i_Col << ") are out of bounds of the Matrix : " << "(" << MatrixShape.first << ", " << MatrixShape.second << ")";
throw std::runtime_error(SS.str());
}
}
/** @brief () operator. returns a reference to
* the value at row i, column j
*
* @return const TYPE&
*/
TYPE& operator()(size_t i_Row, size_t i_Col)
{
try
{
return matrixData.at(i_Row).at(i_Col);
}
catch(std::out_of_range& e)
{
const auto MatrixShape = this->shape();
std::ostringstream SS;
SS << "Indexes : (" << i_Row << ", " << i_Col << ") are out of bounds of the Matrix : " << "(" << MatrixShape.first << ", " << MatrixShape.second << ")";
throw std::runtime_error(SS.str());
}
}
/** @brief = operator. It copies the right hand side
* into the left hand size Matrix. If the sizes are
* different and the left hand side is static, the copy
* fails
* @param rhs IN : Right hand side matrix
*
* @return Void.
*/
template<typename RHSTYPE, size_t RHSNBROWS, size_t RHSNBCOLS>
Matrix<TYPE, NBROWS, NBCOLS>& operator=(const Matrix<RHSTYPE, RHSNBROWS, RHSNBCOLS> &rhs)
{
const auto LhsShape = this->shape();
const auto RhsShape = rhs.shape();
// Error handling
if ((isRowStatic and (this->getNbRows() != rhs.getNbRows())) or
(isColStatic and (this->getNbCols() != rhs.getNbCols())))
{
std::ostringstream SS;
SS << "Impossible to fit data from a matrix of size (" << rhs.getNbRows() << ", " << rhs.getNbCols() << ") into"
" a static matrix of size (" << this->getNbRows() << ", " << this->getNbCols() << ")";
throw std::runtime_error(SS.str());
}
// If both matrices are empty, we dont need to do anything
if(not(isEmpty() and rhs.isEmpty()))
{
// else, change the size only if necessary, taking a default value in one of the non empty matrices in order not to call the default constructor
if (LhsShape != RhsShape )
{
if(not isEmpty())
{
changeSize(RhsShape, (*this)(0,0));
}
else if(not rhs.isEmpty())
{
changeSize(RhsShape, rhs(0,0));
}
}
}
matrixData = rhs.getMatrixData();
return *this;
}
/** @brief move = operator. It moves the right hand side
* into the left hand size Matrix. If the sizes are
* different and the left hand side is static, the copy
* fails
* @param rhs IN : Right hand side matrix
*
* @return Void.
*/
template<typename RHSTYPE, size_t RHSNBROWS, size_t RHSNBCOLS>
Matrix<TYPE, NBROWS, NBCOLS>& operator=(Matrix<RHSTYPE, RHSNBROWS, RHSNBCOLS>&& rhs)
{
const auto LhsShape = this->shape();
const auto RhsShape = rhs.shape();
// Error handling
if ((isRowStatic and (this->getNbRows() != rhs.getNbRows())) or
(isColStatic and (this->getNbCols() != rhs.getNbCols())))
{
std::ostringstream SS;
SS << "Impossible to fit data from a matrix of size (" << rhs.getNbRows() << ", " << rhs.getNbCols() << ") into"
" a static matrix of size (" << this->getNbRows() << ", " << this->getNbCols() << ")";
throw std::runtime_error(SS.str());
}
// If both matrices are empty, we dont need to resize anything
if(not(isEmpty() and rhs.isEmpty()))
{
// else, change the size only if necessary, taking a default value in one of the non empty matrices in order not to call the default constructor
if (LhsShape != RhsShape )
{
if(not isEmpty())
{
changeSize(RhsShape, (*this)(0,0));
}
else if(not rhs.isEmpty())
{
changeSize(RhsShape, rhs(0,0));
}
}
}
matrixData = std::move(rhs.matrixData);
return *this;
}
/** @brief += operator. It adds the right hand side
* into the left hand size Matrix. If the sizes are
* different the operator fails
*
* @param i_NbRows IN : New number of rows of the matrix
* @param o_NbCols IN : New number of columns of the matrix
* @param io_Matrix IN : Matrix which size will be reduced
*
* @return Void.
*/
template<typename RHSTYPE, size_t RHSNBROWS, size_t RHSNBCOLS>
Matrix<TYPE, NBROWS, NBCOLS>& operator+=(const Matrix<RHSTYPE, RHSNBROWS, RHSNBCOLS> &rhs)
{
// Error handling
if(this->isEmpty() or rhs.isEmpty())
throw std::runtime_error("Adding empty matrices is forbidden");
if (rhs.shape() != this->shape())
throw std::runtime_error("Adding matrices of different shapes is forbidden");
for(size_t i = 0; i < getNbRows() ; i += 1)
for(size_t j = 0 ; j < getNbCols() ; j += 1)
matrixData[i][j] += rhs(i,j);
return *this;
}
/** @brief + operator. It adds both sides of the "+" sign
* and returns a static size matrix. Both sides
* have to be of the same shape, otherwise the
* operator fails.
*
* @param rhs IN : Matrix, right side of the equation
*
* @return Matrix<decltype(rhs(0,0) + (*this)(0,0)), NBROWS, NBCOLS, true>.
*/
template<typename LHSTYPE, size_t LHSNBROWS, size_t LHSNBCOLS, typename RHSTYPE, size_t RHSNBROWS, size_t RHSNBCOLS>
friend auto operator+(const Matrix<LHSTYPE, LHSNBROWS, LHSNBCOLS> &lhs, const Matrix<RHSTYPE, RHSNBROWS, RHSNBCOLS> &rhs) ->
Matrix<decltype(lhs(0,0) + rhs(0,0)), LHSNBROWS == DYNAMIC ? RHSNBROWS : DYNAMIC,
LHSNBCOLS == DYNAMIC ? RHSNBCOLS : DYNAMIC>;
/** @brief operator* It multiplies both sides of the "*" sign
* and returns a static size matrix. Both sides
* have to have compatible sizes, (lhs.columns == rhs.cols)
* otherwise, the operator fails.
*
* @param rhs IN : Matrix, right side of the equation
*
* @return Matrix<decltype(rhs(0,0) * (*this)(0,0)), this->getNbRows(), rhs.getNbCols(), true>
*/
template<typename LHSTYPE, size_t LHSNBROWS, size_t LHSNBCOLS, typename RHSTYPE, size_t RHSNBROWS, size_t RHSNBCOLS>
friend auto operator*(const Matrix<LHSTYPE, LHSNBROWS, LHSNBCOLS> &lhs, const Matrix<RHSTYPE, RHSNBROWS, RHSNBCOLS> &rhs) -> Matrix<decltype(rhs(0,0) * lhs(0,0)), LHSNBROWS, RHSNBCOLS>;
private:
/** @brief function used to change the size of the matrix
* This method does not require a default value,
* hence it is default initialized. It does not check if the matrix is static or not
*
* @param i_NbRows IN : New number of rows of the matrix
* @param o_NbCols IN : New number of columns of the matrix
*
* @return Void.
*/
void internalChangeSize(const size_t i_NbRows, const size_t i_NbCols)
{
// Error handling
if (i_NbRows <= 0 or i_NbCols <= 0)
throw std::runtime_error("The number or rows and columns should be a positive integer");
matrixData.resize(i_NbRows, std::vector<TYPE>(i_NbCols, TYPE()));
for (auto& row : matrixData)
row.resize(i_NbCols, TYPE());
}
/** @brief function used to change the size of the matrix
* This method requires a default value for filling
* any new row / column. It does not check if the matrix is static or not
*
* @param i_NbRows IN : New number of rows of the matrix
* @param o_NbCols IN : New number of columns of the matrix
* @param DefaultValue IN : Default value used to fill the matrix
*
* @return Void.
*/
void internalChangeSize(const size_t i_NbRows, const size_t i_NbCols, const TYPE &DefaultValue)
{
// error handling
if (i_NbRows <= 0 or i_NbCols <= 0)
throw std::runtime_error("The number or rows and columns has to be a positive integer");
matrixData.resize(i_NbRows, std::vector<TYPE>(i_NbCols, DefaultValue));
for (auto& row : matrixData)
row.resize(i_NbCols, DefaultValue);
}
};
/** @brief + operator. It adds both sides of the "+" sign
* and returns a static size matrix. Both sides
* have to be of the same shape, otherwise the
* operator fails.
*
* @param rhs IN : Matrix, right side of the equation
*
* @return Matrix<decltype(rhs(0,0) + (*this)(0,0)), NBROWS, NBCOLS, true>.
*/
template<typename LHSTYPE, size_t LHSNBROWS, size_t LHSNBCOLS, typename RHSTYPE, size_t RHSNBROWS, size_t RHSNBCOLS>
auto operator+(const Matrix<LHSTYPE, LHSNBROWS, LHSNBCOLS> &lhs, const Matrix<RHSTYPE, RHSNBROWS, RHSNBCOLS> &rhs) ->
Matrix<decltype(lhs(0,0) + rhs(0,0)), LHSNBROWS == DYNAMIC ? RHSNBROWS : DYNAMIC,
LHSNBCOLS == DYNAMIC ? RHSNBCOLS : DYNAMIC>
{
// Error handling
if(lhs.isEmpty() or rhs.isEmpty())
throw std::runtime_error("Adding empty matrices is forbidden");
if (rhs.shape() != lhs.shape())
throw std::runtime_error("Adding matrices of different shapes is forbidden");
Matrix<decltype(lhs(0,0) + rhs(0,0)), LHSNBROWS == DYNAMIC ? RHSNBROWS : DYNAMIC,
LHSNBCOLS == DYNAMIC ? RHSNBCOLS : DYNAMIC> newMatrix(lhs.getNbRows(), lhs.getNbCols(), lhs(0,0));
for(size_t i = 0 ; i < rhs.getNbRows() ; i += 1)
for(size_t j = 0 ; j < rhs.getNbCols() ; j += 1)
newMatrix(i, j) = lhs(i,j) + rhs(i,j);
return newMatrix;
}
/** @brief operator* It multiplies both sides of the "*" sign
* and returns a static size matrix. Both sides
* have to have compatible sizes, (lhs.columns == rhs.cols)
* otherwise, the operator fails.
*
* @param rhs IN : Matrix, right side of the equation
*
* @return Matrix<decltype(rhs(0,0) * (*this)(0,0)), this->getNbRows(), rhs.getNbCols(), true>
*/
template<typename LHSTYPE, size_t LHSNBROWS, size_t LHSNBCOLS, typename RHSTYPE, size_t RHSNBROWS, size_t RHSNBCOLS>
auto operator*(const Matrix<LHSTYPE, LHSNBROWS, LHSNBCOLS> &lhs, const Matrix<RHSTYPE, RHSNBROWS, RHSNBCOLS> &rhs) -> Matrix<decltype(rhs(0,0) * lhs(0,0)), LHSNBROWS, RHSNBCOLS>
{
// error handling
if(lhs.isEmpty() or rhs.isEmpty())
throw std::runtime_error("Multiplying empty matrices is forbidden");
if(lhs.getNbCols() != rhs.getNbRows())
throw std::runtime_error("The size of the matrices is incompatible with matrix multiplication");
Matrix<decltype(rhs(0,0) * lhs(0,0)), LHSNBROWS, RHSNBCOLS> newMatrix(lhs.getNbRows(), rhs.getNbCols(), lhs(0,0));
for(size_t i = 0 ; i < lhs.getNbRows() ; i += 1)
{
for(size_t j = 0 ; j < rhs.getNbCols(); j += 1)
{
decltype(rhs(0,0) * lhs(0,0)) sum = lhs(i,0) * rhs(0,j); // Compute the first element of the sum in order not to call the default constructor
for(size_t k = 1 ; k < lhs.getNbRows() ; k += 1)
{
sum += lhs(i,k) * rhs(k,j);
}
newMatrix(i, j) = std::move(sum);
}
}
return newMatrix;
}
/** @brief operator<< outputs the Matrix into a stream
*
* @param i_Matrix IN : Matrix to output
* @param o_OS OUT : Stream in which the matrix must be fitted
*
* @return std::ostream&
*/
template <typename TYPE, size_t NBROWS, size_t NBCOLS>
std::ostream& operator<<(std::ostream& o_OS, const Matrix<TYPE, NBROWS, NBCOLS>& i_Matrix)
{
return o_OS << i_Matrix.toString();
}
} /* namespace Mat */
[EDIT]
Как и просили, я написал эту главную, в которой я создаю несколько матриц, складываю и умножаю их. Некоторые статичны, некоторые — динамичны. Я не показал случай, когда только одно измерение матрицы является динамическим, а другое — статическим (например, в векторе динамического размера), но это работает одинаково.
Я использовал эти параметры при компиляции при работе с классом: -std = c ++ 11 -O0 -g -pedantic -pedantic-errors -Wall -Wextra -Werror -Wconversion -fmessage-length = 0 Однако для поведения неявного преобразования для работы в тестовой главной программе -Wconversion использовать нельзя.
#include <iostream>
#include "Matrix.h"
int main()
{
// Test of static Matrix operations
// ==============================================
std::cout << "==============================================" << std::endl;
std::cout << "===============STATIC MATRICES================" << std::endl;
std::cout << "==============================================" << std::endl;
mat::Matrix<int, 3,2> StaticMatrix_1(21);
mat::Matrix<float, 3,2> StaticMatrix3x2(2.0);
mat::Matrix<float, 3,3> StaticMatrix3x3(2.0);
// Resizing a static matrix should throw if it changes the size of the matrix only
// should not throw
StaticMatrix_1.changeSize(3, 2);
try
{
StaticMatrix_1.changeSize(4, 5);
std::cout << "Did not throw ==> problem" << std::endl;
}
catch(std::runtime_error& E)
{
}
std::cout << "STATIC MATRICES USED:" << std::endl;
std::cout << StaticMatrix_1 << std::endl;
std::cout << StaticMatrix3x2 << std::endl;
std::cout << StaticMatrix3x3 << std::endl;
// test of Matrix multiplication: Should yield a 3 by 2 matrix, full of 12.0 floats
std::cout << "TEST_ADDITION FLOAT + FLOAT" << std::endl;
std::cout << StaticMatrix3x3 * StaticMatrix3x2 << std::endl;
// test of matrix addition: This should yield a matrix of floats as int + float does yield a float
std::cout << "TEST_ADDITION INT + FLOAT" << std::endl;
std::cout << StaticMatrix_1 + StaticMatrix3x2 << std::endl;
// Test of matrix addition with different sizes (should throw)
try
{
StaticMatrix3x2 + StaticMatrix3x3;
std::cout << "Did not throw ==> problem" << std::endl;
}
catch(std::runtime_error& E)
{
}
// This property should be commutative
std::cout << "TEST_ADDITION FLOAT + INT" << std::endl;
std::cout << StaticMatrix3x2 + StaticMatrix_1 << std::endl;
std::cout << "TEST_MATRIX_MULTIPLICATION" << std::endl;
std::cout << StaticMatrix3x3 * StaticMatrix3x2 << std::endl;
// This should throw (incompatible sizes for multiplication)
try
{
StaticMatrix3x2 * StaticMatrix3x3;
std::cout << "Did not throw ==> problem" << std::endl;
}
catch(std::runtime_error& E)
{
}
std::cout << std::endl << std::endl << std::endl;
std::cout << "==============================================" << std::endl;
std::cout << "===============DYNAMIC MATRICES===============" << std::endl;
std::cout << "==============================================" << std::endl;
// We use the same types, contents and sizes
mat::Matrix<int, mat::DYNAMIC, mat::DYNAMIC> DynamicMatrix_1(3, 2, 21);
mat::Matrix<float, mat::DYNAMIC, mat::DYNAMIC> DynamicMatrix3x2(3, 2, 2.0);
mat::Matrix<float, mat::DYNAMIC, mat::DYNAMIC> DynamicMatrix3x3(3, 3, 2.0);
std::cout << "DYNAMYC MATRICES USED:" << std::endl;
std::cout << DynamicMatrix_1 << std::endl;
std::cout << DynamicMatrix3x2 << std::endl;
std::cout << DynamicMatrix3x3 << std::endl;
// Resizing a dynamic matrix should throw only if the requested size is <= 0
// should not throw
DynamicMatrix_1.changeSize(1, 1);
DynamicMatrix_1.changeSize(3, 2);
try
{
DynamicMatrix_1.changeSize(0, 0);
std::cout << "Did not throw ==> problem" << std::endl;
}
catch(std::runtime_error& E)
{
}
// test of Matrix multiplication: Should yield a 3 by 2 matrix, full of 12.0 floats
std::cout << "TEST_ADDITION FLOAT + FLOAT" << std::endl;
std::cout << DynamicMatrix3x3 * DynamicMatrix3x2 << std::endl;
// test of matrix addition: This should yield a matrix of floats as int + float does yield a float
std::cout << "TEST_ADDITION INT + FLOAT" << std::endl;
std::cout << DynamicMatrix_1 + DynamicMatrix3x2 << std::endl;
// Test of matrix addition with different sizes (should throw)
try
{
DynamicMatrix3x2 + DynamicMatrix3x3;
std::cout << "Did not throw ==> problem" << std::endl;
}
catch(std::runtime_error& E)
{
}
// This property should be commutative
std::cout << "TEST_ADDITION FLOAT + INT" << std::endl;
std::cout << DynamicMatrix3x2 + DynamicMatrix_1 << std::endl;
std::cout << "TEST_MATRIX_MULTIPLICATION" << std::endl;
std::cout << DynamicMatrix3x3 * DynamicMatrix3x2 << std::endl;
// This should throw (incompatible sizes for multiplication)
try
{
DynamicMatrix3x2 * DynamicMatrix3x3;
std::cout << "Did not throw ==> problem" << std::endl;
}
catch(std::runtime_error& E)
{
}
return 0;
}
```