It took me while to finish, but here is my custom matrix class. I assume that the row/column iterators are the most critical part of this class but anyway I would very much appreciate your ideas of this project.
#include <iostream>
#include <iomanip>
#include <ios>
#include <sstream>
#include <algorithm>
#include <functional>
#include <boost/range/algorithm.hpp>
#include <boost/range/adaptor/strided.hpp>
#include <boost/range/adaptor/sliced.hpp>
#include <boost/typeof/typeof.hpp>
#include "Vector.h"
#ifndef MATRIX_H
#define MATRIX_H
template<class T,
std::size_t rowsize,
std::size_t colsize>
class Matrix{
private:
// row and/or colsize must be greater then 0;
static_assert(rowsize > 0, "Number of Rows must be greater then 0.");
static_assert(colsize > 0, "Number of Columns must be greater then 0.");
// Data is stored in a MVector, a modified std::vector
MVector<T> matrix;
// size of row dimension of the matrix
std::size_t row_dim;
// size of row dimension of the matrix
std::size_t column_dim;
public:
// *******************************************************
// Constructors
// *******************************************************
// default constructor
// @ param "rowsize" - row dimension of matrix
// @ param "colsize" - column dimension of matrix
Matrix() :matrix(rowsize * colsize),
row_dim(rowsize),
column_dim(colsize) {}
// initializer list constructor
// allows to create a matrix by an initialiser list
// example: Matrix<int, 2, 2> a_matrix = {1,2,3,4};
// @param "il" - initializer list
Matrix(std::initializer_list<T> il) :matrix(il),
row_dim(rowsize),
column_dim(colsize){}
// constructor by MVector
// if the size of the vector is larger then the size of the matrix,
// the matrix will construct with the first rowsize*colsize elements of the vector
// if the size of the vector is smaller then the size of the matrix,
// the matrix will not construct
explicit Matrix(const MVector<T>& s): matrix(s),
row_dim(rowsize),
column_dim(colsize){
}
explicit Matrix(MVector<T>&& s): matrix(s),
row_dim(rowsize),
column_dim(colsize){
}
// parameter pack constructor
// constructs a matrix by typing values into the brackets
// example: Matrix<int, 2, 2> a_matrix(1,2,3,4)
// values can be of any type, they will be interpreted as of class T
template<class ... N>
explicit Matrix(T first, N&&... values): matrix{first,
std::forward<T>(static_cast<T>(values))...},
row_dim(rowsize),
column_dim(colsize){}
// *******************************************************
// Iterator support
// *******************************************************
// traverse the entire vector
typename std::vector<T>::iterator Begin(){
return matrix.Begin();
}
typename std::vector<T>::iterator End(){
return matrix.End();
}
typename std::vector<T>::const_iterator Cbegin() const{
return matrix.Cbegin();
}
typename std::vector<T>::const_iterator Cend() const{
return matrix.Cend();
}
typename std::vector<T>::reverse_iterator Rbegin(){
return matrix.Rbegin();
}
typename std::vector<T>::reverse_iterator Rend(){
return matrix.Rend();
}
typename std::vector<T>::const_reverse_iterator Crbegin() const{
return matrix.Crbegin();
}
typename std::vector<T>::const_reverse_iterator Crend() const{
return matrix.Crend();
}
// column traversing
// don't unfortunatly lnow what to replace auto with
auto Begin_col( std::size_t i ){
return = boost::begin(boost::adaptors::stride(
boost::adaptors::slice(matrix.get_data(), i, size()), cols()) );
}
auto End_col( std::size_t i ){
return boost::end(boost::adaptors::stride(
boost::adaptors::slice(matrix.get_data(), i, size()), cols()) );
}
//row traversing
auto Begin_row( std::size_t i ){
return boost::begin(boost::adaptors::slice(matrix.get_data(), i*cols(), i*cols()+cols()));
}
auto End_row( std::size_t i ){
return boost::end(boost::adaptors::slice(matrix.get_data(), i*cols(), i*cols()+cols()));
}
// returns the number of elements in the matrix
std::size_t size() const{
return matrix.size();
}
// returns the number of rows of the matrix
std::size_t rows() const{
return row_dim;
}
// returns the number of colums of the matrix
std::size_t cols() const{
return column_dim;
}
// returns the matrix as a vector
std::vector<T>& as_vector() {
return matrix.get_data();
}
// allows to access an element of the matrix by index expressed
// in terms of rows and columns
// @ param "r" - r'th row of the matrix
// @ param "c" - c'th column of the matrix
std::size_t index(std::size_t r, std::size_t c) const {
return r*cols()+c;
}
// returns a MVector object with the r'th row as it's elements
// slicing is possible from both ends and by "jumping" over elements
// @ param "begin" - starts at the n'th element
// @ param "end" - substracts m from from the last element.
// @ param "by" - selects every n'th element
MVector<T> get_row(std::size_t r, std::size_t begin = 0,
std::size_t end = 0, std::size_t by = 1) const{
MVector<T> row;
for (std::size_t i = index(r,begin); i < index(r,cols()-end); i += by) {
row.addTo(matrix[i]);
}
return row;
}
// get c'th column
// slicing is possible from both ends and by "jumping" over elements
// @ param "begin" - starts at the n'th element
// @ param "end" - substracts m from from the last element.
// @ param "by" - selects every n'th colum
MVector<T> get_column(std::size_t c, std::size_t begin = 0,
std::size_t end = 0, std::size_t by = 1) const{
assert(c < cols() && end < rows());
MVector<T> columns;
for (std::size_t i = index(begin, c); i < index(rows()-end,c); i+=by*cols()) {
columns.addTo(matrix[i]);
}
return columns;
}
// get the diagonal elements of the matrix
// stors the diagonal in MVector
// and returns the vector
MVector<T> get_diagonal(){
MVector<T> diag;
Matrix<T, rowsize, colsize> temp = *this;
for (std::size_t i = 0; i < rowsize; i++) {
diag.addTo(temp(i,i));
}
return diag;
}
// assignment operator
// assignes the content of another Matrix object to this one
// takes advantage of the overloaded " = " operator of the MVector class
// @ param "rhs" = Matrix object on the right hand side of the " = " sign
Matrix<T, rowsize, colsize>& operator=(Matrix<T, rowsize, colsize> rhs) {
this->matrix = rhs.matrix;
return *this;
}
// brackets operator
// return an elements stored in the matrix
// @ param "i" - i'th element in the matrix
T& operator[](std::size_t i) {
assert(i < size());
return matrix[i];
}
const T& operator[](std::size_t i) const {
assert(i < size());
return matrix[i];
}
// brackets operator
// return an elements stored in the matrix
// @ param "r" - r'th row in the matrix
// @ param "c" - c'th column in the matrix
T& operator()(std::size_t r, std::size_t c) {
assert(r < rows() && c < matrix.size() / rows());
return matrix[index(r,c)];
}
const T& operator()(std::size_t r, std::size_t c) const {
assert(r < rows() && c < matrix.size() / rows());
return matrix[index(r,c)];
}
// end of class
};
// *****************************************************************************
// // Equality operators
// *****************************************************************************
template<class T, std::size_t rowsize, std::size_t colsize>
bool operator==(const Matrix<T, rowsize, colsize> &lhs,
const Matrix<T, rowsize, colsize> &rhs) {
// defined in MVector:
return lhs.as_vector() == rhs.as_vector();
}
template<class T, std::size_t rowsize, std::size_t colsize>
bool operator!=(const Matrix<T, rowsize, colsize> &lhs,
const Matrix<T, rowsize, colsize> &rhs) {
// defined in MVector:
return (! (lhs == rhs) );
}
// *****************************************************************************
// // OS/iS operators
// *****************************************************************************
template<class T, std::size_t row_dim, std::size_t col_dim>
std::ostream& operator<<(std::ostream &os, const Matrix<T, row_dim, col_dim>& m){
double max = *std::max_element( m.Cbegin(), m.Cend() );
std::stringstream convert;
convert << max;
for(std::size_t i = 0; i < m.rows(); i++){
os << "[" << i << ",]" << " ";
for(std::size_t j = 0; j <m.cols(); j++){
os << std::right << std::setw( convert.str().size() + 1 ) << m(i,j) << " ";
} os << std::endl;
}
return os;
}
// stores the data rowise
template<class T, std::size_t rowsize, std::size_t colsize>
std::istream& operator>>(std::istream &is, Matrix<T, rowsize, colsize>& m){
std::cout << "Enter " << rowsize*colsize << " numbers to construct the matrix: " <<std::endl;
for(std::size_t i = 0; i < rowsize*colsize; i++){
is >> m[i];
}
return is;
}
//more +=, +, *=, * ... overloaded operators