diff options
author | Bent Bisballe Nyeng <deva@aasimon.org> | 2023-08-03 16:18:00 +0200 |
---|---|---|
committer | Bent Bisballe Nyeng <deva@aasimon.org> | 2023-08-03 16:18:00 +0200 |
commit | 034a5fddfb292f22659f293d72ceb576f5c61d82 (patch) | |
tree | 80fb94e7f859ba81943132e2c02fa09946b9be0a | |
parent | d4d7a3a372fa64d84a48e8f0a472349cbb67b4fb (diff) |
A5: code complete
-rw-r--r-- | a5/Makefile | 4 | ||||
-rw-r--r-- | a5/exercise.tex | 3 | ||||
-rw-r--r-- | a5/imatrix.h | 6 | ||||
-rw-r--r-- | a5/imatrix_nm.h | 80 | ||||
-rw-r--r-- | a5/matrix.cc | 222 | ||||
-rw-r--r-- | a5/matrix.h | 136 |
6 files changed, 349 insertions, 102 deletions
diff --git a/a5/Makefile b/a5/Makefile index 282dfa9..6869fd8 100644 --- a/a5/Makefile +++ b/a5/Makefile @@ -1,4 +1,4 @@ all: matrix -matrix: matrix.cc Makefile imatrix.h imatrix_nm.h matrix.h - g++ -O2 -Wall -Werror -Wextra -Wconversion -std=c++20 $< -o $@ +matrix: matrix.cc Makefile imatrix.h imatrix_nm.h matrix.h Makefile + g++ -g -O2 -Wall -Werror -Wextra -Wconversion -std=c++20 $< -o $@ diff --git a/a5/exercise.tex b/a5/exercise.tex index 6889950..9491afe 100644 --- a/a5/exercise.tex +++ b/a5/exercise.tex @@ -60,4 +60,7 @@ needed. This I think is actually not that good. Adding the requirement to each of the member functions might be better. + +I actually made some errors in the matrix subscripts in the matrix +multiplication/division code, which was shown to me by an assertion. \end{document} diff --git a/a5/imatrix.h b/a5/imatrix.h index f96cb0c..b13f60d 100644 --- a/a5/imatrix.h +++ b/a5/imatrix.h @@ -119,7 +119,7 @@ public: out.m(i,j) = 0; for(std::size_t k = 0; k < other.w; ++k) { - out.m(i,j) += m(i, j) * other.m(k, j); + out.m(i,j) += m(i,k) * other.m(k,j); } } } @@ -147,7 +147,7 @@ public: out.m(i,j) = 0; for(std::size_t k = 0; k < other.w; ++k) { - out.m(i,j) += m(i, j) / other.m(k, j); + out.m(i,j) += m(i,k) / other.m(k,j); } } } @@ -201,4 +201,6 @@ private: std::valarray<int> 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); }; diff --git a/a5/imatrix_nm.h b/a5/imatrix_nm.h index 970031a..f69a099 100644 --- a/a5/imatrix_nm.h +++ b/a5/imatrix_nm.h @@ -5,32 +5,32 @@ #include <valarray> #include <stdexcept> -template<std::size_t W, std::size_t H> +template<std::size_t N, std::size_t M> class ImatrixNM { public: ImatrixNM() - : data(0, W * H) + : data(0, N * M) { } - ImatrixNM(ImatrixNM<W, H>&& other) + ImatrixNM(ImatrixNM<N, M>&& other) { *this = std::move(other); } - ImatrixNM(const ImatrixNM<W, H>& other) + ImatrixNM(const ImatrixNM<N, M>& other) { *this = other; } - ImatrixNM& operator=(ImatrixNM<W, H>&& other) + ImatrixNM& operator=(ImatrixNM<N, M>&& other) { data = std::move(other.data); return *this; } - ImatrixNM& operator=(const ImatrixNM<W, H>& other) + ImatrixNM& operator=(const ImatrixNM<N, M>& other) { data = other.data; return *this; @@ -38,70 +38,70 @@ public: 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]; + if(x >= N || y >= M) throw std::out_of_range("Subscript out of range."); + return data[x + y * N]; } 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]; + if(x >= N || y >= M) throw std::out_of_range("Subscript out of range."); + return data[x + y * N]; } - ImatrixNM<W, H> operator+(const ImatrixNM<W, H>& other) const + ImatrixNM<N, M> operator+(const ImatrixNM<N, M>& other) const { ImatrixNM m(*this); m.data += other.data; return m; } - ImatrixNM<W, H> operator+(int val) + ImatrixNM<N, M> operator+(int val) { - ImatrixNM<W, H> m(*this); + ImatrixNM<N, M> m(*this); m.data += val; return m; } - ImatrixNM<W, H> operator-(const ImatrixNM<W, H>& other) const + ImatrixNM<N, M> operator-(const ImatrixNM<N, M>& other) const { - ImatrixNM<W, H> m(*this); + ImatrixNM<N, M> m(*this); m.data -= other.data; return m; } - ImatrixNM <W, H>operator-(int val) + ImatrixNM <N, M>operator-(int val) { - ImatrixNM<W, H> m(*this); + ImatrixNM<N, M> m(*this); m.data -= val; return m; } - ImatrixNM<W, H> operator%(const ImatrixNM<W, H>& other) const + ImatrixNM<N, M> operator%(const ImatrixNM<N, M>& other) const { - ImatrixNM<W, H> m(*this); + ImatrixNM<N, M> m(*this); m.data %= other.data; return m; } - ImatrixNM<W, H> operator%(int val) + ImatrixNM<N, M> operator%(int val) { ImatrixNM m(*this); m.data %= val; return m; } - template<std::size_t N> - ImatrixNM<W, N> operator*(const ImatrixNM<H, N>& other) const + template<std::size_t R> + ImatrixNM<N, R> operator*(const ImatrixNM<M, R>& other) const { - ImatrixNM<W, N> out; - for(std::size_t i = 0; i < W; ++i) + ImatrixNM<N, R> out; + for(std::size_t i = 0; i < N; ++i) { for(std::size_t j = 0; j < N; ++j) { out.m(i,j) = 0; - for(std::size_t k = 0; k < H; ++k) + for(std::size_t k = 0; k < M; ++k) { - out.m(i,j) += m(i, j) * other.m(k, j); + out.m(i,j) += m(i,k) * other.m(k,j); } } } @@ -109,25 +109,25 @@ public: return out; } - ImatrixNM<W, H> operator*(int val) const + ImatrixNM<N, M> operator*(int val) const { - ImatrixNM<W, H> m(*this); + ImatrixNM<N, M> m(*this); m.data *= val; return m; } - template<std::size_t N> - ImatrixNM<W, N> operator/(const ImatrixNM<H, N>& other) const + template<std::size_t R> + ImatrixNM<N, R> operator/(const ImatrixNM<M, R>& other) const { - ImatrixNM<W, N> out; - for(std::size_t i = 0; i < W; ++i) + ImatrixNM<N, R> out; + for(std::size_t i = 0; i < N; ++i) { for(std::size_t j = 0; j < N; ++j) { out.m(i,j) = 0; - for(std::size_t k = 0; k < H; ++k) + for(std::size_t k = 0; k < M; ++k) { - out.m(i,j) += m(i, j) / other.m(k, j); + out.m(i,j) += m(i,k) / other.m(k,j); } } } @@ -135,9 +135,9 @@ public: return out; } - ImatrixNM<W, H> operator/(int val) const + ImatrixNM<N, M> operator/(int val) const { - ImatrixNM<W, H> m(*this); + ImatrixNM<N, M> m(*this); m.data /= val; return m; } @@ -156,9 +156,9 @@ public: std::vector<int> Row(std::size_t n) const { - if(n >= H) throw std::out_of_range("Subscript out of range."); + if(n >= M) throw std::out_of_range("Subscript out of range."); std::vector<int> out; - for(std::size_t x = 0; x < W; ++x) + for(std::size_t x = 0; x < N; ++x) { out.push_back(m(x, n)); } @@ -167,9 +167,9 @@ public: std::vector<int> Column(std::size_t n) const { - if(n >= W) throw std::out_of_range("Subscript out of range."); + if(n >= N) throw std::out_of_range("Subscript out of range."); std::vector<int> out; - for(std::size_t y = 0; y < H; ++y) + for(std::size_t y = 0; y < M; ++y) { out.push_back(m(n, y)); } diff --git a/a5/matrix.cc b/a5/matrix.cc index 01744fa..4a34fa0 100644 --- a/a5/matrix.cc +++ b/a5/matrix.cc @@ -2,26 +2,226 @@ #include "imatrix_nm.h" #include "matrix.h" +#include <iostream> + +template<typename T, std::size_t N, std::size_t M> +std::ostream& operator<<(std::ostream& s, const Matrix<T,N,M>& m) +{ + for(auto j = 0u; j < M; ++j) + { + for(auto i = 0u; i < N; ++i) + { + s << m.m(i,j) << ' '; + } + s << '\n'; + } + return s; +} + +template<std::size_t N, std::size_t M> +std::ostream& operator<<(std::ostream& s, const ImatrixNM<N,M>& m) +{ + for(auto j = 0u; j < M; ++j) + { + for(auto i = 0u; i < N; ++i) + { + s << m.m(i,j) << ' '; + } + s << '\n'; + } + return s; +} + +std::ostream& operator<<(std::ostream& s, const Imatrix& m) +{ + for(auto j = 0u; j < m.h; ++j) + { + for(auto i = 0u; i < m.w; ++i) + { + s << m.m(i,j) << ' '; + } + s << '\n'; + } + return s; +} + struct Chess_piece { + Chess_piece operator*(const Chess_piece&) const {return {};} + Chess_piece operator/(const Chess_piece&) const {return {};} + Chess_piece operator+(const Chess_piece&) const {return {};} + Chess_piece operator-(const Chess_piece&) const {return {};} + + Chess_piece& operator*=(const Chess_piece&){return *this;} + Chess_piece& operator/=(const Chess_piece&){return *this;} + Chess_piece& operator+=(const Chess_piece&){return *this;} + Chess_piece& operator-=(const Chess_piece&){return *this;} + + Chess_piece operator*(int) const {return {};} + Chess_piece operator/(int) const {return {};} + Chess_piece operator+(int) const {return {};} + Chess_piece operator-(int) const {return {};} + + Chess_piece& operator*=(int){return *this;} + Chess_piece& operator/=(int){return *this;} + Chess_piece& operator+=(int){return *this;} + Chess_piece& operator-=(int){return *this;} }; +std::ostream& operator<<(std::ostream& s, const Chess_piece&) +{ + s << "Chess_piece"; + return s; +} + +template<typename M1, typename M2> +void test(M1& m1, M2& m2) +{ + std::cout << "m1=\n" << m1 << '\n'; + std::cout << "m2=\n" << m2 << '\n'; + + { + auto m3 = m1 * m2; + std::cout << "m1*m2\n" << m3 << '\n'; + } + + { + auto m3 = m1 / m2; + std::cout << "m1/m2\n" << m3 << '\n'; + } + + { + auto m3 = m1 + m1; + std::cout << "m1+m1\n" << m3 << '\n'; + } + + { + auto m3 = m1 - m1; + std::cout << "m1-m1\n" << m3 << '\n'; + } + + if constexpr (supports_modulo<M1, M1>) + { + auto m3 = m1 % m1; + std::cout << "m1%m1\n" << m3 << '\n'; + } + + { + auto m3 = m1 * 2; + std::cout << "m1*2\n" << m3 << '\n'; + } + + { + auto m3 = m1 / 2; + std::cout << "m1/2\n" << m3 << '\n'; + } + + { + auto m3 = m1 + 2; + std::cout << "m1+2\n" << m3 << '\n'; + } + + { + auto m3 = m1 - 2; + std::cout << "m1-2\n" << m3 << '\n'; + } + + if constexpr (supports_modulo<M1, int>) + { + auto m3 = m1 % 2; + std::cout << "m1%2\n" << m3 << '\n'; + } + + { + auto m3 = m1; + m3.Move({0,0}, {1,1}); + std::cout << "m3.Move (copy assign)\n" << m3 << '\n'; + } + + { + auto m3(m1); + auto r = m3.Row(0); + std::cout << "m3.Row (copy ctor)\n"; + for(auto i : r) std::cout << i << ' '; + std::cout << "\n\n"; + } + + { + auto m3(std::move(m1)); + auto c = m3.Column(0); + std::cout << "m3.Column (move ctor)\n"; + for(auto i : c) std::cout << i << ' '; + std::cout << "\n\n"; + } + + { + auto m3 = std::move(m2); + std::cout << "m3 (move assign)\n" << m3 << '\n'; + } +} + int main() { - Matrix<double, 3, 5> m1; - m1 = m1 + 2; - m1.m(2,2) = 42; - try + std::cout << "Imatrix:\n"; { - m1.m(6,6) = 0; + Imatrix m1(3,2); + m1.m(0,0) = 1; m1.m(1,0) = 2; m1.m(2,0) = 3; + m1.m(0,1) = 4; m1.m(1,1) = 5; m1.m(2,1) = 6; + + Imatrix m2(2,3); + m2.m(0,0) = 1; m2.m(1,0) = 2; + m2.m(0,1) = 3; m2.m(1,1) = 4; + m2.m(0,2) = 5; m2.m(1,2) = 6; + + test(m1, m2); } - catch(...) + + std::cout << "ImatrixNM<..,..>:\n"; { - // expected + ImatrixNM<3, 2> m1; + m1.m(0,0) = 1; m1.m(1,0) = 2; m1.m(2,0) = 3; + m1.m(0,1) = 4; m1.m(1,1) = 5; m1.m(2,1) = 6; + + ImatrixNM<2, 3> m2; + m2.m(0,0) = 1; m2.m(1,0) = 2; + m2.m(0,1) = 3; m2.m(1,1) = 4; + m2.m(0,2) = 5; m2.m(1,2) = 6; + + test(m1, m2); } - Matrix<double, 5, 2> m2; - auto m3 = m1 * m2; - Matrix<Chess_piece, 2, 2> c1; - auto c2 = c1 + 42; + std::cout << "Matrix<int, .., ..>:\n"; + { + Matrix<int, 3, 2> m1; + m1.m(0,0) = 1; m1.m(1,0) = 2; m1.m(2,0) = 3; + m1.m(0,1) = 4; m1.m(1,1) = 5; m1.m(2,1) = 6; + + Matrix<int, 2, 3> m2; + m2.m(0,0) = 1; m2.m(1,0) = 2; + m2.m(0,1) = 3; m2.m(1,1) = 4; + m2.m(0,2) = 5; m2.m(1,2) = 6; + + test(m1, m2); + } + + std::cout << "Matrix<double, .., ..>:\n"; + { + Matrix<double, 3, 2> m1; + m1.m(0,0) = 1; m1.m(1,0) = 2; m1.m(2,0) = 3; + m1.m(0,1) = 4; m1.m(1,1) = 5; m1.m(2,1) = 6; + + Matrix<double, 2, 3> m2; + m2.m(0,0) = 1; m2.m(1,0) = 2; + m2.m(0,1) = 3; m2.m(1,1) = 4; + m2.m(0,2) = 5; m2.m(1,2) = 6; + + test(m1, m2); + } + + std::cout << "Matrix<Chess_piece, .., ..>:\n"; + { + Matrix<Chess_piece, 3, 2> m1; + Matrix<Chess_piece, 2, 3> m2; + test(m1, m2); + } } diff --git a/a5/matrix.h b/a5/matrix.h index af83683..6d880e2 100644 --- a/a5/matrix.h +++ b/a5/matrix.h @@ -4,33 +4,71 @@ #include <utility> #include <valarray> #include <stdexcept> +#include <concepts> -template<typename T, std::size_t W, std::size_t H> +template<typename T1, typename T2> +concept supports_modulo = + requires(T1 t1, T2 t2) + { + t1 % t2; + }; + +template<typename T> +concept supports_matrix = + requires(T a, T b, int i) + { + a * b; + a / b; + a + b; + a - b; + + a * i; + a / i; + a + i; + a - i; + + a *= b; + a /= b; + a += b; + a -= b; + + a *= i; + a /= i; + a += i; + a -= i; + + a = b; + a = {}; + }; + + +template<typename T, std::size_t N, std::size_t M> + requires supports_matrix<T> class Matrix { public: Matrix() - : data(T{}, W * H) + : data(T{}, N * M) { } - Matrix(Matrix<T, W, H>&& other) + Matrix(Matrix<T, N, M>&& other) { *this = std::move(other); } - Matrix(const Matrix<T, W, H>& other) + Matrix(const Matrix<T, N, M>& other) { *this = other; } - Matrix& operator=(Matrix<T, W, H>&& other) + Matrix& operator=(Matrix<T, N, M>&& other) { data = std::move(other.data); return *this; } - Matrix& operator=(const Matrix<T, W, H>& other) + Matrix& operator=(const Matrix<T, N, M>& other) { data = other.data; return *this; @@ -38,70 +76,74 @@ public: T& 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]; + if(x >= N) throw std::out_of_range("Subscript x out of range."); + if(y >= M) throw std::out_of_range("Subscript y out of range."); + return data[x + y * N]; } const T& 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]; + if(x >= N) throw std::out_of_range("Subscript x out of range."); + if(y >= M) throw std::out_of_range("Subscript y out of range."); + return data[x + y * N]; } - Matrix<T, W, H> operator+(const Matrix<T, W, H>& other) const + Matrix<T, N, M> operator+(const Matrix<T, N, M>& other) const { Matrix m(*this); m.data += other.data; return m; } - Matrix<T, W, H> operator+(T val) + Matrix<T, N, M> operator+(int val) { - Matrix<T, W, H> m(*this); - m.data += val; + Matrix<T, N, M> m(*this); + for(auto& d : m.data) d += val; return m; } - Matrix<T, W, H> operator-(const Matrix<T, W, H>& other) const + Matrix<T, N, M> operator-(const Matrix<T, N, M>& other) const { - Matrix<T, W, H> m(*this); + Matrix<T, N, M> m(*this); m.data -= other.data; return m; } - Matrix <T, W, H>operator-(T val) + Matrix <T, N, M> operator-(int val) { - Matrix<T, W, H> m(*this); - m.data -= val; + Matrix<T, N, M> m(*this); + for(auto& d : m.data) d -= val; return m; } - Matrix<T, W, H> operator%(const Matrix<T, W, H>& other) const + Matrix<T, N, M> operator%(const Matrix<T, N, M>& other) const + requires(supports_modulo<T,T>) { - Matrix<T, W, H> m(*this); + Matrix<T, N, M> m(*this); m.data %= other.data; return m; } - Matrix<T, W, H> operator%(T val) + Matrix<T, N, M> operator%(int val) + requires(supports_modulo<T,int>) { Matrix m(*this); - m.data %= val; + for(auto& d : m.data) d %= val; return m; } - template<std::size_t N> - Matrix<T, W, N> operator*(const Matrix<T, H, N>& other) const + template<std::size_t R> + Matrix<T, N, R> operator*(const Matrix<T, M, R>& other) const { - Matrix<T, W, N> out; - for(std::size_t i = 0; i < W; ++i) + Matrix<T, N, R> out; + for(std::size_t i = 0; i < N; ++i) { - for(std::size_t j = 0; j < N; ++j) + for(std::size_t j = 0; j < R; ++j) { out.m(i,j) = {}; - for(std::size_t k = 0; k < H; ++k) + for(std::size_t k = 0; k < M; ++k) { - out.m(i,j) += m(i, j) * other.m(k, j); + out.m(i,j) += m(i,k) * other.m(k,j); } } } @@ -109,25 +151,25 @@ public: return out; } - Matrix<T, W, H> operator*(T val) + Matrix<T, N, M> operator*(int val) { - Matrix<T, W, H> m(*this); - m.data *= val; + Matrix<T, N, M> m(*this); + for(auto& d : m.data) d *= val; return m; } - template<std::size_t N> - Matrix<T, W, N> operator/(const Matrix<T, H, N>& other) const + template<std::size_t R> + Matrix<T, N, R> operator/(const Matrix<T, M, R>& other) const { - Matrix<T, W, N> out; - for(std::size_t i = 0; i < W; ++i) + Matrix<T, N, R> out; + for(std::size_t i = 0; i < N; ++i) { - for(std::size_t j = 0; j < N; ++j) + for(std::size_t j = 0; j < R; ++j) { out.m(i,j) = {}; - for(std::size_t k = 0; k < H; ++k) + for(std::size_t k = 0; k < M; ++k) { - out.m(i,j) += m(i, j) / other.m(k, j); + out.m(i,j) += m(i,k) / other.m(k,j); } } } @@ -135,10 +177,10 @@ public: return out; } - Matrix<T, W, H> operator/(T val) const + Matrix<T, N, M> operator/(int val) const { - Matrix<T, W, H> m(*this); - m.data /= val; + Matrix<T, N, M> m(*this); + for(auto& d : m.data) d /= val; return m; } @@ -156,9 +198,9 @@ public: std::vector<T> Row(std::size_t n) const { - if(n >= H) throw std::out_of_range("Subscript out of range."); + if(n >= M) throw std::out_of_range("Subscript out of range."); std::vector<T> out; - for(std::size_t x = 0; x < W; ++x) + for(std::size_t x = 0; x < N; ++x) { out.push_back(m(x, n)); } @@ -167,9 +209,9 @@ public: std::vector<T> Column(std::size_t n) const { - if(n >= W) throw std::out_of_range("Subscript out of range."); + if(n >= N) throw std::out_of_range("Subscript out of range."); std::vector<T> out; - for(std::size_t y = 0; y < H; ++y) + for(std::size_t y = 0; y < M; ++y) { out.push_back(m(n, y)); } |