      1  #ifndef MATRIX5_H
      2  #define MATRIX5_H
      3
      4  #include <iostream>
      5  #include <stdexcept>
      6  #include <iomanip>
      7
      8  using namespace std;
      9
     10  /**
     11     Matrix exception class for indexing error
     12  */
     13  class MatrixIndexException : public out_of_range
     14  {
     15  public:
     16     MatrixIndexException(int i);
     17  private:
     18     string format_message(int i);
     19  };
     20
     21  /**
     22     Matrix exception class for mismatched argument error
     23  */
     24  class MatrixMismatchException : public invalid_argument
     25  {
     26  public:
     27     MatrixMismatchException();
     28  };
     29
     30  /**
     31     This class describes a row in a matrix.
     32  */
     33  template<typename T> class Matrix;
     34
     35  template<typename T>
     36  class MatrixRow
     37  {
     38  public:
     39     /**
     40        Remember a row for a given matrix
     41        @param r a pointer to the first element in the row
     42        @param s the size of the row
     43     */
     44     MatrixRow(Matrix<T>* m, int s);
     45
     46     /**
     47        Accesses a row element.
     48        @param j the column index
     49        @return a reference to the element with the given index
     50     */
     51     T& operator[](int j) throw (MatrixIndexException);
     52
     53  private:
     54     Matrix<T>* mat;
     55     int i;
     56  };
     57
     58  /**
     59     This class describes a row in a constant matrix.
     60  */
     61  template<typename T>
     62  class ConstMatrixRow
     63  {
     64  public:
     65     /**
     66        Constructs a row with a given start and size.
     67        @param r a pointer to the first element in the row
     68        @param s the size of the row
     69     */
     70     ConstMatrixRow(const Matrix<T>* m, int s);
     71
     72     /**
     73        Accesses a row element.
     74        @param j the column index
     75        @return a reference to the element with the given index
     76     */
     77     const T& operator[](int j) const throw (MatrixIndexException);
     78
     79  private:
     80     const Matrix<T>* mat;
     81     int i;
     82  };
     83
     84  /**
     85     This class describes a matrix with arbitrary rows and columns
     86  */
     87  template<typename T>
     88  class Matrix
     89  {
     90  public:
     91     /**
     92        Constructs a matrix filled with zero elements.
     93     */
     94     Matrix(int r, int c);
     95
     96     /**
     97        The big three
     98     */
     99     Matrix(const Matrix<T>& other);
    100     Matrix<T>& operator=(const Matrix<T>& other);
    101     ~Matrix();
    102
    103     /**
    104        Gets the number of rows of this matrix.
    105        @return the number of rows
    106     */
    107     int get_rows() const;
    108
    109     /**
    110        Gets the number of columns of this matrix.
    111        @return the number of columns
    112     */
    113     int get_columns() const;
    114
    115     /**
    116        Accesses a matrix element.
    117        @param i the row index
    118        @param j the column index
    119        @return a reference to the element with the given indexes
    120     */
    121     T& operator()(int i, int j) throw (MatrixIndexException);
    122
    123     /**
    124        Accesses a matrix element.
    125        @param i the row index
    126        @param j the column index
    127        @return the element with the given indexes
    128     */
    129     T operator()(int i, int j) const throw (MatrixIndexException);
    130
    131     /**
    132        Accesses a matrix row.
    133        @param i the row index
    134        @return the row with the given index
    135     */
    136     MatrixRow<T> operator[](int i) throw (MatrixIndexException);
    137
    138     /**
    139        Accesses a matrix row.
    140        @param i the row index
    141        @return the row with the given index
    142     */
    143     ConstMatrixRow<T> operator[](int i) const
    144        throw (MatrixIndexException);
    145
    146     /**
    147        Computes the matrix sum
    148        @param right another matrix
    149        @return the update matrix
    150     */
    151     Matrix<T>& operator+=(const Matrix<T>& right)
    152        throw (MatrixMismatchException);
    153
    154  private:
    155     /**
    156        Copies another matrix into this matrix.
    157        @param other the other matrix
    158     */
    159     void copy(const Matrix& other);
    160
    161     /**
    162        Frees the memory for this matrix.
    163     */
    164     void free();
    165
    166     int rows;
    167     int columns;
    168     T* elements;
    169  };
    170
    171  /**
    172     Computes the matrix sum.
    173     @param right another matrix
    174     @return the product of this matrix and the other
    175  */
    176  template<typename T>
    177  Matrix<T> operator+(const Matrix<T>& left, const Matrix<T>& right)
    178     throw (MatrixMismatchException);
    179
    180  /**
    181     Computes the matrix product.
    182     @param right another matrix
    183     @return the product of this matrix and the other
    184  */
    185  template<typename T>
    186  Matrix<T> operator*(const Matrix<T>& left, const Matrix<T>& right)
    187     throw (MatrixMismatchException);
    188
    189  /**
    190     Computes the scalar product of a scalar value and a matrix.
    191     @param left a scalar value
    192     @param right a matrix
    193     @return the sum of the given value and the given matrix
    194  */
    195  template<typename T>
    196  Matrix<T> operator*(double left, const Matrix<T>& right);
    197
    198  /**
    199     Computes the scalar product of a matrix and a scalar value.
    200     @param right a scalar value
    201     @return the sum of this matrix and the given value
    202  */
    203  template<typename T>
    204  Matrix<T> operator*(const Matrix<T>& left, double right);
    205
    206  /**
    207     Prints a matrix to an output stream.
    208     @param left an output stream
    209     @param right a matrix
    210     @return the given output stream
    211  */
    212  template<typename T>
    213  ostream& operator<<(ostream& left, const Matrix<T>& right);
    214
    215  inline MatrixIndexException::MatrixIndexException(int idx)
    216     : out_of_range(format_message(idx)) {}
    217
    218  inline MatrixMismatchException::MatrixMismatchException()
    219     : invalid_argument("Matrix arguments have incompatible sizes")  {}
    220
    221  template<typename T>
    222  inline Matrix<T>::Matrix(const Matrix<T>& other)
    223  {
    224     copy(other);
    225  }
    226
    227  template<typename T>
    228  inline Matrix<T>::~Matrix()
    229  {
    230     free();
    231  }
    232
    233  template<typename T>
    234  inline int Matrix<T>::get_rows() const
    235  {
    236     return rows;
    237  }
    238
    239  template<typename T>
    240  inline int Matrix<T>::get_columns() const
    241  {
    242     return columns;
    243  }
    244
    245  template<typename T>
    246  inline void Matrix<T>::free()
    247  {
    248     delete[] elements;
    249  }
    250
    251  template<typename T>
    252  inline MatrixRow<T> Matrix<T>::operator[](int i)
    253     throw (MatrixIndexException)
    254  {
    255     return MatrixRow<T>(this, i);
    256  }
    257
    258  template<typename T>
    259  inline ConstMatrixRow<T> Matrix<T>::operator[](int i) const
    260     throw (MatrixIndexException)
    261  {
    262     return ConstMatrixRow<T>(this, i);
    263  }
    264
    265  template<typename T>
    266  inline MatrixRow<T>::MatrixRow(Matrix<T>* m, int s) : mat(m), i(s) { }
    267
    268  template<typename T>
    269  inline T& MatrixRow<T>::operator[](int j) throw (MatrixIndexException)
    270  {
    271     return (*mat)(i,j);
    272  }
    273
    274  template<typename T>
    275  inline ConstMatrixRow<T>::ConstMatrixRow(const Matrix<T>* m, int s)
    276     : mat(m), i(s) { }
    277
    278  template<typename T>
    279  inline const T& ConstMatrixRow<T>::operator[](int j) const
    280     throw (MatrixIndexException)
    281  {
    282     return (*mat)(i, j);
    283  }
    284
    285  template<typename T>
    286  inline Matrix<T> operator*(double left, const Matrix<T>& right)
    287  {
    288     return right * left;
    289  }
    290
    291  template<typename T>
    292  Matrix<T>::Matrix(int r, int c)
    293  {
    294     rows = r;
    295     columns = c;
    296     elements = new T[rows * columns];
    297  }
    298
    299  template<typename T>
    300  Matrix<T>& Matrix<T>::operator=(const Matrix<T>& other)
    301  {
    302     if (this != &other)
    303     {
    304        free();
    305        copy(other);
    306     }
    307     return *this;
    308  }
    309
    310  template<typename T>
    311  void Matrix<T>::copy(const Matrix<T>& other)
    312  {
    313     rows = other.rows;
    314     columns = other.columns;
    315     elements = new T[rows * columns];
    316  }
    317
    318  template<typename T>
    319  T& Matrix<T>::operator()(int i, int j) throw (MatrixIndexException)
    320  {
    321     if (i < 0 || i >= rows)
    322        throw MatrixIndexException(i);
    323     if (j < 0 || j >= columns)
    324        throw MatrixIndexException(j);
    325     return elements[i * get_columns() + j];
    326  }
    327
    328  template<typename T>
    329  T Matrix<T>::operator()(int i, int j) const
    330     throw (MatrixIndexException)
    331  {
    332     if (i < 0 || i >= rows)
    333        throw MatrixIndexException(i);
    334     if (j < 0 || j >= columns)
    335        throw MatrixIndexException(j);
    336     return elements[i * get_columns() + j];
    337  }
    338
    339  template<typename T>
    340  Matrix<T>& Matrix<T>::operator+=(const Matrix<T>& right)
    341     throw (MatrixMismatchException)
    342  {
    343     if (rows != right.rows || columns != right.columns)
    344        throw MatrixMismatchException();
    345     for (int i = 0; i < rows; i++)
    346        for (int j = 0; j < columns; j++)
    347           (*this)(i, j) += right(i, j);
    348     return *this;
    349  }
    350
    351  template<typename T>
    352  Matrix<T> operator+(const Matrix<T>& left, const Matrix<T>& right)
    353     throw (MatrixMismatchException)
    354  {
    355     Matrix<T> result = left;
    356     result += right;
    357     return result;
    358  }
    359
    360  template<typename T>
    361  Matrix<T> operator*(const Matrix<T>& left, const Matrix<T>& right)
    362     throw (MatrixMismatchException)
    363  {
    364     if (left.get_columns() != right.get_rows())
    365        throw MatrixMismatchException();
    366     Matrix<T> result(left.get_rows(), right.get_columns());
    367     for (int i = 0; i < left.get_rows(); i++)
    368        for (int j = 0; j < right.get_columns(); j++)
    369           for (int k = 0; k < left.get_columns(); k++)
    370              result(i, j) += left(i, k) * right(k, j);
    371     return result;
    372  }
    373
    374  template<typename T>
    375  Matrix<T> operator*(const Matrix<T>& left, double right)
    376  {
    377     Matrix<T> result(left);
    378     for (int i = 0; i < result.get_rows(); i++)
    379        for (int j = 0; j < result.get_columns(); j++)
    380           result(i, j) *= right;
    381     return result;
    382  }
    383
    384  template<typename T>
    385  ostream& operator<<(ostream& left, const Matrix<T>& right)
    386  {
    387     const int WIDTH = 10;
    388     for (int i = 0; i < right.get_rows(); i++)
    389     {
    390        for (int j = 0; j < right.get_columns(); j++)
    391           left << setw(WIDTH) << right(i, j);
    392        left << "\n";
    393     }
    394     return left;
    395  }
    396
    397  #endif