]> git.tdb.fi Git - libs/math.git/blob - source/linal/matrix.h
Remove SquareMatrix and instead use static_assert to check squareness
[libs/math.git] / source / linal / matrix.h
1 #ifndef MSP_LINAL_MATRIX_H_
2 #define MSP_LINAL_MATRIX_H_
3
4 #include <algorithm>
5 #include <ostream>
6 #include "matrixops.h"
7 #include "vector.h"
8
9 namespace Msp {
10 namespace LinAl {
11
12 /**
13 A general mathematical matrix with M rows and N columns.
14 */
15 template<typename T, unsigned M, unsigned N>
16 class Matrix
17 {
18 public:
19         typedef T ElementType;
20
21 private:
22         T data[M*N];
23
24 public:
25         Matrix();
26         Matrix(const T *);
27         template<typename U>
28         Matrix(const Matrix<U, M, N> &);
29
30         static Matrix identity();
31         static Matrix from_columns(const Vector<T, M> *);
32         static Matrix from_rows(const Vector<T, N> *);
33
34         unsigned rows() const { return M; }
35         unsigned columns() const { return N; }
36
37         T &element(unsigned i, unsigned j) { return data[i+M*j]; }
38         const T &element(unsigned i, unsigned j) const { return data[i+M*j]; }
39         T &operator()(unsigned i, unsigned j) { return element(i, j); }
40         const T &operator()(unsigned i, unsigned j) const { return element(i, j); }
41
42         Vector<T, M> column(unsigned i) const { return Vector<T, M>(data+M*i); }
43         Vector<T, N> row(unsigned i) const { return Vector<T, N>(data+i, M); }
44
45         template<unsigned P, unsigned Q>
46         Matrix<T, P, Q> select(const Vector<unsigned, P> &, const Vector<unsigned, Q> &) const;
47
48         template<unsigned P, unsigned Q>
49         Matrix<T, P, Q> block(unsigned, unsigned) const;
50
51         Matrix &operator*=(T);
52         Matrix &operator*=(const Matrix &);
53         Matrix &operator/=(T);
54         Matrix &operator+=(const Matrix &);
55         Matrix &operator-=(const Matrix &);
56
57         Matrix &invert();
58
59         Matrix &exchange_columns(unsigned, unsigned);
60         Matrix &multiply_column(unsigned, T);
61         Matrix &add_column(unsigned, unsigned, T);
62 };
63
64 template<typename T, unsigned M, unsigned N>
65 inline Matrix<T, M, N>::Matrix()
66 {
67         std::fill(data, data+M*N, T());
68 }
69
70 template<typename T, unsigned M, unsigned N>
71 inline Matrix<T, M, N>::Matrix(const T *d)
72 {
73         std::copy(d, d+M*N, data);
74 }
75
76 template<typename T, unsigned M, unsigned N>
77 template<typename U>
78 inline Matrix<T, M, N>::Matrix(const Matrix<U, M, N> &other)
79 {
80         for(unsigned i=0; i<M; ++i)
81                 for(unsigned j=0; j<N; ++j)
82                         element(i, j) = other(i, j);
83 }
84
85 template<typename T, unsigned M, unsigned N>
86 inline Matrix<T, M, N> Matrix<T, M, N>::identity()
87 {
88         static_assert(M==N, "An identity matrix must be square");
89         Matrix<T, M, N> m;
90         for(unsigned i=0; i<M; ++i)
91                 m(i, i) = T(1);
92         return m;
93 }
94
95 template<typename T, unsigned M, unsigned N>
96 inline Matrix<T, M, N> Matrix<T, M, N>::from_columns(const Vector<T, M> *v)
97 {
98         Matrix<T, M, N> m;
99         for(unsigned i=0; i<M; ++i)
100                 for(unsigned j=0; j<N; ++j)
101                         m(i, j) = v[j][i];
102         return m;
103 }
104
105 template<typename T, unsigned M, unsigned N>
106 inline Matrix<T, M, N> Matrix<T, M, N>::from_rows(const Vector<T, N> *v)
107 {
108         Matrix<T, M, N> m;
109         for(unsigned i=0; i<M; ++i)
110                 for(unsigned j=0; j<N; ++j)
111                         m(i, j) = v[i][j];
112         return m;
113 }
114
115 template<typename T, unsigned M, unsigned N>
116 template<unsigned P, unsigned Q>
117 inline Matrix<T, P, Q> Matrix<T, M, N>::select(const Vector<unsigned, P> &row_indices, const Vector<unsigned, Q> &col_indices) const
118 {
119         Matrix<T, P, Q> r;
120         for(unsigned j=0; j<P; ++j)
121                 for(unsigned i=0; i<Q; ++i)
122                         r(j, i) = element(row_indices[j], col_indices[i]);
123         return r;
124 }
125
126 template<typename T, unsigned M, unsigned N>
127 template<unsigned P, unsigned Q>
128 inline Matrix<T, P, Q> Matrix<T, M, N>::block(unsigned y, unsigned x) const
129 {
130         Matrix<T, P, Q> r;
131         for(unsigned j=0; j<P; ++j)
132                 for(unsigned i=0; i<Q; ++i)
133                         r(j, i) = element(y+j, x+i);
134         return r;
135 }
136
137 template<typename T, unsigned M, unsigned N>
138 inline Matrix<T, M, N> &Matrix<T, M, N>::operator*=(T s)
139 {
140         for(unsigned i=0; i<M*N; ++i)
141                 data[i] *= s;
142         return *this;
143 }
144
145 template<typename T, unsigned M, unsigned N>
146 inline Matrix<T, M, N> &Matrix<T, M, N>::operator*=(const Matrix<T, M, N> &m)
147 {
148         static_assert(M==N, "Multiplication-assignment is only possible on square matrices");
149         return *this = *this*m;
150 }
151
152 template<typename T, unsigned M, unsigned N>
153 inline Matrix<T, M, N> operator*(const Matrix<T, M, N> &m, T s)
154 {
155         Matrix<T, M, N> r(m);
156         return r *= s;
157 }
158
159 template<typename T, unsigned M, unsigned N>
160 inline Matrix<T, M, N> operator*(T s, const Matrix<T, M, N> &m)
161 {
162         return m*s;
163 }
164
165 template<typename T, unsigned M, unsigned P, unsigned N>
166 inline Matrix<T, M, N> operator*(const Matrix<T, M, P> &m1, const Matrix<T, P, N> &m2)
167 {
168         Matrix<T, M, N> r;
169         for(unsigned i=0; i<M; ++i)
170                 for(unsigned j=0; j<N; ++j)
171                         for(unsigned k=0; k<P; ++k)
172                                 r(i, j) += m1(i, k)*m2(k, j);
173         return r;
174 }
175
176 template<typename T, unsigned M, unsigned N>
177 inline Vector<T, M> operator*(const Matrix<T, M, N> &m, const Vector<T, N> &v)
178 {
179         Vector<T, M> r;
180         for(unsigned i=0; i<M; ++i)
181                 for(unsigned j=0; j<N; ++j)
182                         r[i] += m(i, j)*v[j];
183         return r;
184 }
185
186 template<typename T, unsigned M, unsigned N>
187 inline Vector<T, N> operator*(const Vector<T, M> &v, const Matrix<T, M, N> &m)
188 {
189         Vector<T, N> r;
190         for(unsigned j=0; j<N; ++j)
191                 for(unsigned i=0; i<M; ++i)
192                         r[j] += v[i]*m(i, j);
193         return r;
194 }
195
196 template<typename T, unsigned M, unsigned N>
197 inline Matrix<T, M, N> &Matrix<T, M, N>::operator/=(T s)
198 {
199         for(unsigned i=0; i<M*N; ++i)
200                 data[i] /= s;
201         return *this;
202 }
203
204 template<typename T, unsigned M, unsigned N>
205 inline Matrix<T, M, N> operator/(const Matrix<T, M, N> &m, T s)
206 {
207         Matrix<T, M, N> r(m);
208         return r /= s;
209 }
210
211 template<typename T, unsigned M, unsigned N>
212 inline Matrix<T, M, N> &Matrix<T, M, N>::operator+=(const Matrix<T, M, N> &m)
213 {
214         for(unsigned i=0; i<M*N; ++i)
215                 data[i] += m.data[i];
216         return *this;
217 }
218
219 template<typename T, unsigned M, unsigned N>
220 inline Matrix<T, M, N> operator+(const Matrix<T, M, N> &m1, const Matrix<T, M, N> &m2)
221 {
222         Matrix<T, M, N> r(m1);
223         return r += m2;
224 }
225
226 template<typename T, unsigned M, unsigned N>
227 inline Matrix<T, M, N> &Matrix<T, M, N>::operator-=(const Matrix<T, M, N> &m)
228 {
229         for(unsigned i=0; i<M*N; ++i)
230                 data[i] -= m.data[i];
231         return *this;
232 }
233
234 template<typename T, unsigned M, unsigned N>
235 inline Matrix<T, M, N> operator-(const Matrix<T, M, N> &m1, const Matrix<T, M, N> &m2)
236 {
237         Matrix<T, M, N> r(m1);
238         return r -= m2;
239 }
240
241 template<typename T, unsigned M, unsigned N>
242 inline Matrix<T, M, N>& Matrix<T, M, N>::invert()
243 {
244         static_assert(M==N, "Inversion is only possible on square matrices");
245         Matrix<T, M, N> r = identity();
246         gauss_jordan(*this, r);
247         return *this = r;
248 }
249
250 template<typename T, unsigned S>
251 inline Matrix<T, S, S> invert(const Matrix<T, S, S> &m)
252 {
253         Matrix<T, S, S> temp = m;
254         Matrix<T, S, S> r = Matrix<T, S, S>::identity();
255         return gauss_jordan(temp, r);
256 }
257
258 template<typename T, unsigned M, unsigned N>
259 inline bool operator==(const Matrix<T, M, N> &a, const Matrix<T, M, N> &b)
260 {
261         for(unsigned j=0; j<N; ++j)
262                 for(unsigned i=0; i<M; ++i)
263                         if(a(i, j)!=b(i, j))
264                                 return false;
265         return true;
266 }
267
268 template<typename T, unsigned M, unsigned N>
269 inline Matrix<T, M, N> &Matrix<T, M, N>::exchange_columns(unsigned i, unsigned j)
270 {
271         using std::swap;
272         for(unsigned k=0; k<M; ++k)
273                 swap(element(k, i), element(k, j));
274         return *this;
275 }
276
277 template<typename T, unsigned M, unsigned N>
278 inline Matrix<T, M, N> &Matrix<T, M, N>::multiply_column(unsigned i, T s)
279 {
280         for(unsigned k=0; k<M; ++k)
281                 element(k, i) *= s;
282         return *this;
283 }
284
285 template<typename T, unsigned M, unsigned N>
286 inline Matrix<T, M, N> &Matrix<T, M, N>::add_column(unsigned i, unsigned j, T s)
287 {
288         for(unsigned k=0; k<M; ++k)
289                 element(k, j) += element(k, i)*s;
290         return *this;
291 }
292
293 template<typename T, unsigned M, unsigned N>
294 inline Matrix<T, N, M> transpose(const Matrix<T, M, N> &m)
295 {
296         Matrix<T, N, M> r;
297         for(unsigned j=0; j<N; ++j)
298                 for(unsigned i=0; i<M; ++i)
299                         r(j, i) = m(i, j);
300         return r;
301 }
302
303 template<typename T, unsigned M, unsigned N>
304 inline std::ostream &operator<<(std::ostream &s, const Matrix<T, M, N> &m)
305 {
306         s << "Matrix" << M << 'x' << N << '(';
307         for(unsigned i=0; i<N; ++i)
308         {
309                 if(i)
310                         s << ", ";
311                 s << '[';
312                 for(unsigned j=0; j<M; ++j)
313                 {
314                         if(j)
315                                 s << ", ";
316                         s << m(j, i);
317                 }
318                 s << ']';
319         }
320         s << ')';
321         return s;
322 }
323
324 } // namespace LinAl
325 } // namespace Msp
326
327 #endif