C plus plus:Tutorials:Matrices
From GPWiki
A general-purpose templated two-dimensional matrix in C++. Feel free to add to it.
#ifndef MATRIX2_HPP #define MATRIX2_HPP #include <cmath> #include <iostream> #include <vector> #include <stdexcept> #include <algorithm> #include <functional> template <class T> class Matrix2 { public: explicit Matrix2(int r = 0, int c = 0, T init_with = T()) : rows_( r < 1 ? 4 : r), columns_( c < 1 ? 4 : c ), data_( rows_ * columns_, init_with ) {} template <typename U> explicit Matrix2(Matrix2<U> const &other) : rows_( other.rows() ), columns_( other.columns() ), data_( &*other, &*other+(rows_*columns_) ) {} T &operator()(int row, int column) { return data_[column+(columns_*row)]; } T const &operator()(int row, int column) const { return data_[column+(columns_*row)]; } int rows() const { return rows_; } int columns() const { return columns_; } operator T*() { return data_.empty() ? 0 : &data_[0]; } operator T const*() const { return data_.empty() ? 0 : &data_[0]; } Matrix2 &operator+=(const Matrix2& other) { if ( rows() != other.rows() || columns() != other.columns() ) { throw std::invalid_argument("To add matrices they must have the same size"); } std::transform( data_.begin(), data_.end(), other.data_.begin(), data_.begin(), std::plus<T>() ); return *this; } Matrix2 &operator-=(const Matrix2& other) { if ( rows() != other.rows() || columns() != other.columns() ) { throw std::invalid_argument("To subtract matrices they must have the same size"); } std::transform( data_.begin(), data_.end(), other.data_.begin(), data_.begin(), std::minus<T>() ); return *this; } template <class U> friend const Matrix2<U> operator*(const Matrix2<U>& one, const Matrix2<U>& two); Matrix2 &operator*=(const Matrix2& other) { return *this = *this * other; } Matrix2 &operator*=(T const &scale) { std::transform( data_.begin(), data_.end(), data_.begin(), std::bind2nd( std::multiplies<T>(), scale ) ); return *this; } Matrix2 &operator/=(T const &scale) { std::transform( data_.begin(), data_.end(), data_.begin(), std::bind2nd( std::divides<T>(), scale ) ); return *this; } void load_identity() { if ( rows() != columns() ) { throw std::invalid_argument("Identity matrices only exist for square matrices"); } for (int i=0; i<rows(); i++) { for (int j=0; j<columns(); j++) { operator()( i, j ) = (i==j); } } } template <typename U> Matrix2 &operator=(Matrix2<U> const &other) { // note that the assign needs to be done first for exception safety. data_.assign( other.data_.begin(), other.data_.end() ); rows_ = other.rows_; columns_ = other.columns_; return *this; } private: // note: changing the order here will break both constructors int rows_; int columns_; std::vector<T> data_; }; template <class T> const Matrix2<T> operator+(Matrix2<T> one, Matrix2<T> const &two) { return one += two; } template <class T> const Matrix2<T> operator-(Matrix2<T> one, Matrix2<T> const &two) { return one -= two; } template <class T> const Matrix2<T> operator*(const Matrix2<T>& one, const Matrix2<T>& two) { if ( one.columns() != two.rows() ) { throw std::invalid_argument("Matrices can only be multiplied if the first has" " exactly as many columns as the second has rows"); } Matrix2<T> result( one.rows(), two.columns() ); for (int i=0; i<result.rows(); i++) for (int j=0; j<result.columns(); j++) for (int a=0; a<one.columns(); a++) result(i,j) += one(i,a) * two(a,j); return result; } template <class T> const Matrix2<T> operator*(Matrix2<T> one, T const &factor) { return one *= factor; } template <class T> const Matrix2<T> operator*(T const &factor, Matrix2<T> one) { return one *= factor; } template <class T> const Matrix2<T> operator/(Matrix2<T> one, T const &factor) { return one /= factor; } template <typename T, typename U> bool operator==(Matrix2<T> const &one, Matrix2<U> const &two) { return (one.rows() == two.rows() && one.columns() == two.columns() && std::equal( &*one, &*one + one.rows()*one.columns(), &*two )); } template <typename T, typename U> bool operator!=(Matrix2<T> const &one, Matrix2<U> const &two) { return !( one == two ); } template<class T> std::ostream& operator<<(std::ostream& os, const Matrix2<T>& mat) { for (int i=0; i< mat.rows(); i++) { os << "\n["; for (int j=0; j<mat.columns(); j++) { os << mat(i,j); if ( j+1 < mat.columns() ) os << "\t"; } os << "]" << std::endl; } return os; } typedef Matrix2<float> Matrixf; typedef Matrix2<int> Matrixi; typedef Matrix2<size_t> Matrixu; #endif // MATRIX2_HPP