Matrix Templated

You can use it as you like. The only thing I ask you is to be recognized myself and inform me to any issue.

/* 
  * File:   Matrix.h
  * Author: Aikon
  * 
  * http://surprising-code.blogspot.com

  * Created on 20 de febrero de 2012, 22:43
  * updated at: 26/02/2012
  * last update at: 27/02/2012
  */

#ifndef MATRIX_H
#define     MATRIX_H

#include <vector>
#include <iostream>
#include <stdexcept>

template<typename T, int ROWS, int COLS>
class Matrix {
private:
     std::vector<T> _elements;

public:

     T& operator()(unsigned i, unsigned j) {
         return _elements[i * COLS + j];
     }

     const T& operator()(unsigned i, unsigned j) const {
         return _elements[i * COLS + j];
     }

     T& operator()(unsigned i) {
         return _elements[i];
     }

     const T& operator()(unsigned i) const {
         return _elements[i];
     }

public:
     // constructors
     Matrix();
     Matrix(T element);

     template<typename Function>
     Matrix(Function f);
     Matrix(const Matrix<T, ROWS, COLS>&);

     // destructor
     ~Matrix();

     // comparison
     bool operator==(const Matrix<T, ROWS, COLS>&) const;

     bool operator!=(const Matrix<T, ROWS, COLS>& cmp) const {
         return !((*this) == (cmp));
     }

     // scalar multiplication
     Matrix<T, ROWS, COLS>& operator*=(const T& a);

     Matrix<T, ROWS, COLS> operator*(const T& a) const {
         return Matrix<T, ROWS, COLS > (*this).operator*=(a);
     }

     Matrix<T, ROWS, COLS> operator-() const {
         return Matrix<T, ROWS, COLS > (*this)*(-1);
     }

     // addition/subtraction
     Matrix<T, ROWS, COLS>& operator+=(const Matrix<T, ROWS, COLS>&);
     Matrix<T, ROWS, COLS>& operator-=(const Matrix<T, ROWS, COLS>&);

     Matrix<T, ROWS, COLS> operator+(const Matrix<T, ROWS, COLS>& M) const {
         return Matrix<T, ROWS, COLS > (*this).operator+=(M);
     }

     Matrix<T, ROWS, COLS> operator-(const Matrix<T, ROWS, COLS>& M) const {
         return Matrix<T, ROWS, COLS > (*this).operator-=(M);
     }

     // Matrix multiplication
     template<int InCOLS>
     Matrix<T, ROWS, InCOLS> operator*(const Matrix<T, COLS, InCOLS>& in) const;

     template<int InCOLS>
             Matrix<T, ROWS, InCOLS>& operator*=(const Matrix<T, COLS, InCOLS>& M) {
         return *this = *this * M;
     }

     Matrix<T, COLS, ROWS> operator~();

     /*
     
     Matrix<T, ROWS, COLS> getcol( unsigned i ) const;
     Matrix<T, ROWS, COLS> getrow( unsigned j ) const;
     Matrix<T, ROWS, COLS>& setcol( unsigned j, const Matrix<T, ROWS, COLS>& C );
     Matrix<T, ROWS, COLS>& setrow( unsigned i, const Matrix<T, ROWS, COLS>& R );
     Matrix<T, ROWS, COLS> delrow( unsigned i ) const;
     Matrix<T, ROWS, COLS> delcol( unsigned j ) const;

     Matrix<T, ROWS, COLS> transpose() const;
      */
     void set(unsigned i, unsigned j, T in) {
         _elements[i * COLS + j] = in;
     }
};
#endif     /* MATRIX_H */


//constructors

template<typename T, int ROWS, int COLS>
Matrix<T, ROWS, COLS>::Matrix()
: _elements(ROWS*COLS, T(0.0)) {
     if (ROWS == 0 || COLS == 0)
         throw std::range_error("attempt to create a degenerate matrix");
};

template<typename T, int ROWS, int COLS>
Matrix<T, ROWS, COLS>::Matrix(T element)
: _elements(ROWS*COLS, T(element)) {
     if (ROWS == 0 || COLS == 0)
         throw std::range_error("attempt to create a degenerate matrix");
};

template<typename T, int ROWS, int COLS>
template<typename Function>
Matrix<T, ROWS, COLS>::Matrix(Function f){
     if (ROWS == 0 || COLS == 0)
         throw std::range_error("attempt to create a degenerate matrix");

     for (int i = 0; i < ROWS * COLS; i++) _elements.push_back(f());
}

template<typename T, int ROWS, int COLS>
Matrix<T, ROWS, COLS>::Matrix(const Matrix<T, ROWS, COLS>& M){
     if (ROWS == 0 || COLS == 0)
         throw std::range_error("attempt to create a degenerate matrix");
     (*this) = M;
}

// destructor

//Erases all the elements. Note that this function only erases 
//the elements, and that if the elements themselves are pointers, 
//the pointed-to memory is not touched in any way. Managing 
//the pointer is the user's responsibility.

template<typename T, int ROWS, int COLS>
Matrix<T, ROWS, COLS>::~Matrix() {
}

template<typename T, int ROWS, int COLS>
bool Matrix<T, ROWS, COLS>::operator==(const Matrix<T, ROWS, COLS>& cmp) const {
     for (unsigned i = 0; i < ROWS * COLS; i++)
         if (_elements[i] != cmp._elements[i])
             return false;
     return true;
}

template<typename T, int ROWS, int COLS>
         Matrix<T, ROWS, COLS>& Matrix<T, ROWS, COLS>::operator*=(const T& a) {
     for (int i = 0; i < ROWS * COLS; i++)
         _elements[i] *= a;
     return *this;
}

// Matrix multiplication
//(this)*B = C sizeX(files de this), sizeY = columnes de B sizeY

template<typename T, int ROWS, int COLS>
template<int InCOLS>
Matrix<T, ROWS, InCOLS> Matrix<T, ROWS, COLS>::operator*(const Matrix<T, COLS, InCOLS>& in) const {
     Matrix<T, ROWS, InCOLS> aux(0.0);

     for (int i = 0; i < ROWS; i++)
         for (int j = 0; j < InCOLS; j++)
             for (int k = 0; k < COLS; k++)
                 (aux)(i, j) += (*this)(i, k) * in(k, j);

     return aux;
}

// addition/subtraction

template<typename T, int ROWS, int COLS>
         Matrix<T, ROWS, COLS>& Matrix<T, ROWS, COLS>::operator+=(const Matrix<T, ROWS, COLS>& in) {
     for (unsigned i = 0; i < ROWS * COLS; i++)
         _elements[i] += in._elements[i];
     return *this;
}

template<typename T, int ROWS, int COLS>
         Matrix<T, ROWS, COLS>& Matrix<T, ROWS, COLS>::operator-=(const Matrix<T, ROWS, COLS>& in) {
     for (unsigned i = 0; i < ROWS * COLS; i++)
         _elements[i] -= in._elements[i];
     return *this;
}

template<typename T, int ROWS, int COLS>
Matrix<T, COLS, ROWS> Matrix<T, ROWS, COLS>::operator~() {
     Matrix<T, COLS, ROWS> aux;
     for (int i = 0; i < ROWS; i++)
         for (int j = 0; j < COLS; j++)
             aux(j, i) = (*this)(i, j);
     return aux;
}

template<class T, int ROWS, int COLS>
std::ostream& operator<<(std::ostream& out, const Matrix<T, ROWS, COLS>& M) {
     out << std::endl;
     for (int i = 0; i < ROWS; i++) {
         for (int j = 0; j < COLS; j++)
             out << " " << M(i, j) << " ";
         out << std::endl;
     }
     return out;
}

#include <cstdlib>
#include <ctime>

double myfunction() {
     return (rand() % 10) + 1;
}

std::string randomStrGen() {
     int length = 5;
     std::string charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
     std::string result;
     result.resize(length);

     for (int i = 0; i < length; i++)
         result[i] = charset[rand() % charset.length()];

     return result;
}

int main() {
     try {
         srand(time(0));

         Matrix<double, 4, 2 > m(1.1);
         Matrix<double, 2, 4 > m2(myfunction);
         Matrix<double, 4, 4 > m3(myfunction);
         Matrix<std::string, 2, 2 > m4(randomStrGen);

         std::cout << "isEqual: " << (m == m) << std::endl;
         std::cout << m << m2 << m3;

         m3 = m*m2;
         m * 2;
         std::cout << "new m3" << m3 << m;

         m3 = -m3;
         std::cout << m3 << m4;

         Matrix<double, 4, 2 > aux;
         aux = ~m2;
         std::cout << aux;
         
         Matrix<int, 2, 2> intMatrix;
         Matrix<int, 2, 2> intMatrix2(2);
         
         intMatrix = intMatrix - intMatrix2;
         std::cout << intMatrix - intMatrix2;//again -2 so is -4
         

     } catch (const std::exception& in) {
         std::cout << in.what() << std::endl;
     }
}

output:

isEqual: 1

 1.1  1.1 
 1.1  1.1 
 1.1  1.1 
 1.1  1.1 

 1  1  8  6 
 1  9  2  10 

 3  1  7  1 
 4  6  10  4 
 5  7  4  1 
 3  1  10  1 
new m3
 2.2  11  11  17.6 
 2.2  11  11  17.6 
 2.2  11  11  17.6 
 2.2  11  11  17.6 

 1.1  1.1 
 1.1  1.1 
 1.1  1.1 
 1.1  1.1 

 -2.2  -11  -11  -17.6 
 -2.2  -11  -11  -17.6 
 -2.2  -11  -11  -17.6 
 -2.2  -11  -11  -17.6 

 L019l  vpUG9 
 F77UO  mpQK8 

 1  1 
 1  9 
 8  2 
 6  10 

 -4  -4 
 -4  -4 

RUN SUCCESSFUL (total time: 72ms)


2 comments:

  1. Uau!
    Quina feinada, noi.
    Impressionant que facis tot això simplement pel plaer de programar. :)

    ReplyDelete
  2. ^^
    Tot i que realment és una classe interesant la qual possiblement necesitaré en algun moment, per això li estic dedicant temps extra.

    Merci ^^

    ReplyDelete