#include #include #include #include #include "matrix.h" using namespace std; /***************************************************** * range class ****************************************************/ range::range(int start) : _start(start), _stop(start+1), _stride(1) { } // supports construction such as range(3,6), which includes values {3, 4, 5} range::range(int start, int stop) : _start(start), _stop(stop), _stride(1) { } // supports construction such as range(3,2,8), which includes values {3, 5, 7} range::range(int start, int stride, int stop) : _start(start), _stop(stop), _stride(stride) { if (stride < 1) throw invalid_argument("stride must be positive."); } // Returns starting index int range::start() const { return _start; } // Returns stopping index int range::stop() const { return _stop; } // Returns stopping index int range::stride() const { return _stride; } // Returns the number of values included within the range int range::size() const { // partials strides should count as one. e.g. range(1,2,4).size() should be 2 return max(0, (_stop - _start + _stride - 1) / _stride); // trucates properly } /***************************************************** * matrix class ****************************************************/ matrix::matrix() : _nr(0), _nc(0), _data() {}; matrix::matrix(int numRows, int numColumns, double value) : _nr(numRows), _nc(numColumns), _data(numRows*numColumns, value) {} int matrix::numRows() const { return _nr; } int matrix::numColumns() const { return _nc; } matrix matrix::size() const { matrix result(1,2); result(0,0) = numRows(); result(0,1) = numColumns(); return result; } void matrix::reshape(int r, int c) { if (r * c != _nr * _nc) throw invalid_argument("To reshape, the number of elements must not change."); _nr = r; _nc = c; } bool matrix::operator==(const matrix &other) const { return (_nr == other._nr && _nc == other._nc && _data == other._data); } bool matrix::operator!=(const matrix &other) const { return !(*this == other); } // provides read-only access to a matrix entry double matrix::operator()(int r, int c) const { if (r < 0 || r >= _nr || c < 0 || c >= _nc) throw out_of_range("Invalid indices for matrix"); return _data[r + c * _nr]; // column-major } // provides write access to a matrix entry (albeit, without expansion) double& matrix::operator()(int r, int c) { if (r < 0 || r >= _nr || c < 0 || c >= _nc) throw out_of_range("Invalid indices for matrix"); return _data[r + c * _nr]; // column-major } // provides write access to a submatrix as a proxy matrix_proxy matrix::operator()(range rows, range cols) { return matrix_proxy(*this, rows, cols); } //----------------------------------------------- // addition //----------------------------------------------- matrix matrix::operator+(const matrix& other) const { // produce sum of two matrices if (_nr != other._nr && _nc != other._nc) throw invalid_argument("Matrix dimensions must agree."); matrix result(*this); // start with copy for (int r=0; r < _nr; r++) for (int c=0; c < _nc; c++) result(r,c) += other(r,c); return result; } matrix matrix::operator+(double scalar) const { // add scalar to all elements matrix result(*this); // start with copy for (int r=0; r < _nr; r++) for (int c=0; c < _nc; c++) result(r,c) += scalar; return result; } //----------------------------------------------- // multiplication //----------------------------------------------- matrix matrix::operator*(double scalar) const { // multiply each element by scalar matrix result(*this); // start with copy for (int r=0; r < _nr; r++) for (int c=0; c < _nc; c++) result(r,c) *= scalar; return result; } matrix matrix::operator*(const matrix& other) const { // matrix multiplicaiton if (_nc != other._nr) throw invalid_argument("Inner matrix dimensions must agree."); matrix result(_nr, other._nc); for (int r=0; r < _nr; r++) for (int c=0; c < other._nc; c++) { // let's compute the proper entry float subtotal = 0; for(int k=0; k < _nc; k++) { subtotal += (*this)(r,k) * other(k,c); } result(r,c) = subtotal; } return result; } /***************************************************** * IO operations ****************************************************/ ostream& operator<<(ostream& out, const matrix& m) { string temp; unsigned int maxfield = 0; for (int r=0; r < m.numRows(); r++) { for (int c=0; c < m.numColumns(); c++) { stringstream s; s << fixed << setprecision(3); s << m(r,c); s >> temp; if (temp.size() > maxfield) maxfield = temp.size(); } } for (int r=0; r < m.numRows(); r++) { for (int c=0; c < m.numColumns(); c++) { stringstream s; s << fixed << setprecision(3); s << m(r,c); s >> temp; out << " " << setw(maxfield) << temp; } out << endl; } return out; } ostream& operator<<(ostream& out, const matrix_proxy& m) { string temp; unsigned int maxfield = 0; for (int r=0; r < m.numRows(); r++) { for (int c=0; c < m.numColumns(); c++) { stringstream s; s << fixed << setprecision(3); s << m(r,c); s >> temp; if (temp.size() > maxfield) maxfield = temp.size(); } } for (int r=0; r < m.numRows(); r++) { for (int c=0; c < m.numColumns(); c++) { stringstream s; s << fixed << setprecision(3); s << m(r,c); s >> temp; out << " " << setw(maxfield) << temp; } out << endl; } return out; } istream& operator>>(istream& in, matrix& m) { // presumes that there is a blank line to terminate the matrix vector< vector > _data; unsigned int numColumns = 0; bool done = false; while (!done) { vector row; string temp; getline(in, temp); stringstream s(temp); double val; while (s >> val) { row.push_back(val); } if (row.size() == 0) done = true; else if (numColumns > 0 and numColumns != row.size()) done = true; else { numColumns = row.size(); _data.push_back(row); } } m = matrix(_data.size(), numColumns); for (int r=0; r < m.numRows(); r++) for (int c=0; c< m.numColumns(); c++) m(r,c) = _data[r][c]; return in; }