summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBent Bisballe Nyeng <deva@aasimon.org>2023-08-03 16:18:00 +0200
committerBent Bisballe Nyeng <deva@aasimon.org>2023-08-03 16:18:00 +0200
commit034a5fddfb292f22659f293d72ceb576f5c61d82 (patch)
tree80fb94e7f859ba81943132e2c02fa09946b9be0a
parentd4d7a3a372fa64d84a48e8f0a472349cbb67b4fb (diff)
A5: code complete
-rw-r--r--a5/Makefile4
-rw-r--r--a5/exercise.tex3
-rw-r--r--a5/imatrix.h6
-rw-r--r--a5/imatrix_nm.h80
-rw-r--r--a5/matrix.cc222
-rw-r--r--a5/matrix.h136
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));
}