// -*- c++ -*- #pragma once #include #include #include class Imatrix { public: Imatrix() = default; explicit Imatrix(std::size_t w, std::size_t h) : data(0, w * h) , w(w) , h(h) { } Imatrix(Imatrix&& other) { *this = std::move(other); } Imatrix(const Imatrix& other) { *this = other; } Imatrix& operator=(Imatrix&& other) { w = other.w; other.w = 0; h = other.h; other.h = 0; data = std::move(other.data); return *this; } Imatrix& operator=(const Imatrix& other) { w = other.w; h = other.h; data = other.data; return *this; } int& m(std::size_t x, std::size_t y) { if(x >= w || y >= h) throw std::out_of_range("Subscript out of range."); return data[x + y * w]; } const int& m(std::size_t x, std::size_t y) const { if(x >= w || y >= h) throw std::out_of_range("Subscript out of range."); return data[x + y * w]; } Imatrix operator+(const Imatrix& other) const { if(w != other.w || h != other.h) throw std::invalid_argument("Dimension mismatch"); Imatrix m(*this); m.data += other.data; return m; } Imatrix operator+(int val) const { Imatrix m(*this); m.data += val; return m; } Imatrix operator-(const Imatrix& other) const { if(w != other.w || h != other.h) throw std::invalid_argument("Dimension mismatch"); Imatrix m(*this); m.data -= other.data; return m; } Imatrix operator-(int val) { Imatrix m(*this); m.data -= val; return m; } Imatrix operator%(const Imatrix& other) const { if(w != other.w || h != other.h) throw std::invalid_argument("Dimension mismatch"); Imatrix m(*this); m.data %= other.data; return m; } Imatrix operator%(int val) const { Imatrix m(*this); m.data %= val; return m; } Imatrix operator*(const Imatrix& other) const { if(w != other.h || h != other.w) throw std::invalid_argument("Dimension mismatch"); Imatrix out(w, other.h); for(std::size_t i = 0; i < w; ++i) { for(std::size_t j = 0; j < other.h; ++j) { out.m(i,j) = 0; for(std::size_t k = 0; k < other.w; ++k) { out.m(i,j) += m(i,k) * other.m(k,j); } } } return out; } Imatrix operator*(int val) const { Imatrix m(*this); m.data *= val; return m; } Imatrix operator/(const Imatrix& other) const { if(w != other.h || h != other.w) throw std::invalid_argument("Dimension mismatch"); Imatrix out(w, other.h); for(std::size_t i = 0; i < w; ++i) { for(std::size_t j = 0; j < other.h; ++j) { out.m(i,j) = 0; for(std::size_t k = 0; k < other.w; ++k) { out.m(i,j) += m(i,k) / other.m(k,j); } } } return out; } Imatrix operator/(int val) const { Imatrix m(*this); m.data /= val; return m; } struct pos_t { std::size_t x; std::size_t y; }; void Move(pos_t from, pos_t to) { m(to.x, to.x) = m(from.x, from.x); m(from.x, from.y) = 0; } std::vector Row(std::size_t n) const { if(n >= h) throw std::out_of_range("Subscript out of range."); std::vector out; for(std::size_t x = 0; x < w; ++x) { out.push_back(m(x, n)); } return out; } std::vector Column(std::size_t n) const { if(n >= w) throw std::out_of_range("Subscript out of range."); std::vector out; for(std::size_t y = 0; y < h; ++y) { out.push_back(m(n, y)); } return out; } private: // Invariant; at all times data contains w * h initialized data members std::valarray data; // default initialized to empty std::size_t w{}; // default initialized to 0 std::size_t h{}; // default initialized to 0 friend std::ostream& operator<<(std::ostream& s, const Imatrix& m); };