Library of Assembled Shared Sources
matrix.inl
Go to the documentation of this file.
1/** @file
2 * @author Bram de Greve (bram@cocamware.com)
3 * @author Tom De Muer (tom@cocamware.com)
4 *
5 * *** BEGIN LICENSE INFORMATION ***
6 *
7 * The contents of this file are subject to the Common Public Attribution License
8 * Version 1.0 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://lass.sourceforge.net/cpal-license. The License is based on the
11 * Mozilla Public License Version 1.1 but Sections 14 and 15 have been added to cover
12 * use of software over a computer network and provide for limited attribution for
13 * the Original Developer. In addition, Exhibit A has been modified to be consistent
14 * with Exhibit B.
15 *
16 * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
17 * WARRANTY OF ANY KIND, either express or implied. See the License for the specific
18 * language governing rights and limitations under the License.
19 *
20 * The Original Code is LASS - Library of Assembled Shared Sources.
21 *
22 * The Initial Developer of the Original Code is Bram de Greve and Tom De Muer.
23 * The Original Developer is the Initial Developer.
24 *
25 * All portions of the code written by the Initial Developer are:
26 * Copyright (C) 2004-2011 the Initial Developer.
27 * All Rights Reserved.
28 *
29 * Contributor(s):
30 *
31 * Alternatively, the contents of this file may be used under the terms of the
32 * GNU General Public License Version 2 or later (the GPL), in which case the
33 * provisions of GPL are applicable instead of those above. If you wish to allow use
34 * of your version of this file only under the terms of the GPL and not to allow
35 * others to use your version of this file under the CPAL, indicate your decision by
36 * deleting the provisions above and replace them with the notice and other
37 * provisions required by the GPL License. If you do not delete the provisions above,
38 * a recipient may use your version of this file under either the CPAL or the GPL.
39 *
40 * *** END LICENSE INFORMATION ***
41 */
42
43
44
45#ifndef LASS_GUARDIAN_OF_INCLUSION_NUM_MATRIX_INL
46#define LASS_GUARDIAN_OF_INCLUSION_NUM_MATRIX_INL
47
48#include "num_common.h"
49#include "matrix.h"
50#include "impl/matrix_solve.h"
51#include "../meta/meta_assert.h"
52
53#include <cstddef>
54
55#define LASS_NUM_MATRIX_ENFORCE_EQUAL_DIMENSION(a, b)\
56 *LASS_UTIL_IMPL_MAKE_ENFORCER(\
57 ::lass::util::impl::TruePredicate,\
58 ::lass::util::impl::DefaultRaiser,\
59 (a).rows() == (b).rows() && (a).columns() == (b).columns(),\
60 int(0), \
61 "Matrices '" LASS_STRINGIFY(a) "' and '" LASS_STRINGIFY(b) "' have different dimensions in '" LASS_HERE "'.")
62
63#define LASS_NUM_MATRIX_ENFORCE_ADJACENT_DIMENSION(a, b)\
64 *LASS_UTIL_IMPL_MAKE_ENFORCER(\
65 ::lass::util::impl::EqualPredicate,\
66 ::lass::util::impl::DefaultRaiser,\
67 (a).columns(),\
68 (b).rows(),\
69 "Matrices '" LASS_STRINGIFY(a) "' and '" LASS_STRINGIFY(b) "' have no matching dimensions for operation at '" LASS_HERE "'.")
70
71namespace lass
72{
73namespace num
74{
75
76// --- public --------------------------------------------------------------------------------------
77
78/** constructs an empty matrix
79 *
80 * @par Exception Safety:
81 * strong guarentee.
82 */
83template <typename T, typename S>
85 storage_()
86{
87}
88
89
90
91/** Construct a matrix of dimension @a rows x @a columns.
92 * Can be used as default constructor for storage in containers.
93 * @param rows the number of rows of the matrix to be created.
94 * @param columns the number of columns of the matrix to be created.
95 * By default both @a rows and @a columns are zero, what creates an empty matrix.
96 * Not very usefull though, except as place holder. So, it's safe to pass
97 * zero as arguments, but you shouldn't pass negative values.
98 *
99 * @par Complexity:
100 * O(rows * columns)
101 *
102 * @par Exception Safety:
103 * strong guarentee.
104 */
105template <typename T, typename S>
107 storage_(rows, columns)
108{
109}
110
111
112
113template <typename T, typename S>
114Matrix<T, S>::Matrix(const TStorage& storage):
115 storage_(storage)
116{
117}
118
119
120
121/** assign storage/expression matrix to this (this should be a storage matrix).
122 *
123 * @pre @c this must be an l-value (storage matrix).
124 *
125 * @par Complexity:
126 * O(other.rows() * other.columns())
127 *
128 * @par Exception Safety:
129 * basic guarentee.
130 */
131template <typename T, typename S>
132template <typename T2, typename S2>
134 storage_(other.rows(), other.columns())
135{
136 LASS_META_ASSERT(TStorage::lvalue, this_is_not_an_lvalue);
137
138 const S2& b = other.storage();
139 const TSize m = rows();
140 const TSize n = columns();
141 for (TSize i = 0; i < m; ++i)
142 {
143 for (TSize j = 0; j < n; ++j)
144 {
145 storage_(i, j) = b(i, j);
146 }
147 }
148}
149
150
151
152/** assign storage/expression matrix to this (this should be a storage matrix).
153 *
154 * @pre @c this must be an l-value (storage matrix).
156 * @par Complexity:
157 * O(other.rows() * other.columns())
158 *
159 * @par Exception Safety:
160 * basic guarentee.
161 */
162template <typename T, typename S>
163template <typename T2, typename S2>
166 LASS_META_ASSERT(TStorage::lvalue, this_is_not_an_lvalue);
168 const S2& b = other.storage();
169 const TSize m = other.rows();
170 const TSize n = other.columns();
171 storage_.resize(m, n);
172 for (TSize i = 0; i < m; ++i)
173 {
174 for (TSize j = 0; j < n; ++j)
176 storage_(i, j) = b(i, j);
179 return *this;
181
184/** return number of rows in matrix.
186 * @post should never return be a negative value.
188 * @par Complexity:
189 * O(1)
190 *
191 * @par Exception safety:
192 * no-fail
193 */
194template <typename T, typename S> inline
195const typename Matrix<T, S>::TSize
197{
198 return storage_.rows();
199}
200
201
202
203/** return number of columns in matrix.
204 *
205 * @post should never return be a negative value.
206 *
207 * @par Complexity:
208 * O(1)
209 *
210 * @par Exception safety:
211 * no-fail
212 */
213template <typename T, typename S> inline
214const typename Matrix<T, S>::TSize
216{
217 return storage_.columns();
218}
219
220
221
222/** return the component value at position (@a row, @a column)
223 *
224 * @pre (@a row, @a column) shouldn't be out of the range [0, this->rows()) x [0, this->columns()], unless
225 * you're asking for trouble.
226 */
227template <typename T, typename S> inline
228const typename Matrix<T, S>::TValue
230{
231 LASS_ASSERT(row < rows() && column < columns());
232 return storage_(row, column);
233}
234
235
236
237/** access the component value at position (@a row, @a column)
238 *
239 * @pre (@a row, @a column) shouldn't be out of the range [0, this->rows()) x [0, this->columns()], unless
240 * you're asking for trouble.
241 *
242 * @pre @c this must be an l-value (storage matrix).
243 */
244template <typename T, typename S> inline
245typename Matrix<T, S>::TReference
246Matrix<T, S>::operator()(TSize iRow, TSize iColumn)
247{
248 LASS_META_ASSERT(TStorage::lvalue, this_is_not_an_lvalue);
249 LASS_ASSERT(iRow < rows() && iColumn < columns());
250 return storage_(iRow, iColumn);
251}
252
253
254
255/** return the component value at position (@a row, @a column)
256 * (@a row, @a column) will be wrapped to range [0, this->rows()) x [0, this->columns()] by using a
257 * modulus operator
258 */
259template <typename T, typename S> inline
260const typename Matrix<T, S>::TValue
261Matrix<T, S>::at(TSigned row, TSigned column) const
262{
263 return storage_(mod(row, rows()), mod(column, columns()));
264}
265
266
267
268/** access the component value at position (@a row, @a column)
269 * (@a row, @a column) will be wrapped to range [0, this->rows()) x [0, this->columns()] by using a
270 * modulus operator
271 *
272 * @pre @c this must be an l-value (storage matrix).
273 */
274template <typename T, typename S> inline
275typename Matrix<T, S>::TReference
276Matrix<T, S>::at(TSigned row, TSigned column)
277{
278 LASS_META_ASSERT(TStorage::lvalue, this_is_not_an_lvalue);
279 return storage_(mod(row, rows()), mod(column, columns()));
280}
281
282
283
284/** return a row of matrix.
285 * @a index will be wrapped to range [0, this->rows()) by using a modulus operator
286 */
287template <typename T, typename S> inline
288typename Matrix<T, S>::ConstRow
289Matrix<T, S>::row(TSigned index) const
290{
291 return ConstRow(*this, mod(index, rows()));
292}
293
294
295
296/** return a row of matrix.
297 * @a index will be wrapped to range [0, this->rows()) by using a modulus operator.
298 * THIS MUST BE LVALUE (storage matrix).
299 */
300template <typename T, typename S> inline
301typename Matrix<T, S>::Row
302Matrix<T, S>::row(TSigned index)
303{
304 return Row(*this, mod(index, rows()));
305}
306
307
308
309/** return a column of matrix.
310 * @a index will be wrapped to range [0, this->columns()) by using a modulus operator
311 */
312template <typename T, typename S> inline
313typename Matrix<T, S>::ConstColumn
314Matrix<T, S>::column(TSigned index) const
315{
316 return ConstColumn(*this, mod(index, columns()));
317}
318
319
320
321/** return a column of matrix.
322 * @a index will be wrapped to range [0, this->columns()) by using a modulus operator
323 * THIS MUST BE LVALUE (storage matrix).
324 */
325template <typename T, typename S> inline
326typename Matrix<T, S>::Column
328{
329 return Column(*this, mod(index, columns()));
330}
331
332
333
334/** A weird way to get back the same object
335 *
336 * @par Complexity:
337 * O(1)
338 *
339 * @par Exception safety:
340 * no-fail
341 */
342template <typename T, typename S> inline
344{
345 return *this;
346}
347
348
349
350/** return a vector with all components negated
351 * (-a)(i, j) == -(a(i, j)).
352 *
353 * @par Complexity:
354 * O(1)
355 *
356 * @par Exception safety:
357 * no-fail
358 */
359template <typename T, typename S>
362{
363 typedef impl::MNeg<T, S> TExpression;
364 return Matrix<T, TExpression>(TExpression(storage_));
365}
366
367
368
369/** componentswise addition assignment of two matrices
370 *
371 * <i>Matrix Addition: Denote the sum of two matrices @n A and @n B (of the same dimensions) by
372 * @n C=A+B. The sum is defined by adding entries with the same indices @n Cij=Aij+Bij over all
373 * @n i and @n j.</i>
374 * http://mathworld.wolfram.com/MatrixAddition.html
375 *
376 * This method implements the assignment addition what reduces to @n Aij+=Bij over all @n i and
377 * @n j.
378 *
379 * @pre @c this must be an l-value (storage matrix).
380 *
381 * @par Complexity:
382 * O(this->rows() * this->columns())
383 *
384 * @throw an exception is thrown if @a *this and @a iB are not of the same dimensions
385 */
386template <typename T, typename S>
387template <typename S2>
389{
390 LASS_META_ASSERT(TStorage::lvalue, this_is_not_an_lvalue);
391 LASS_NUM_MATRIX_ENFORCE_EQUAL_DIMENSION(*this, other);
392 const S2& b = other.storage();
393 const TSize m = rows();
394 const TSize n = columns();
395 for (TSize i = 0; i < m; ++i)
396 {
397 for (TSize j = 0; j < n; ++j)
398 {
399 storage_(i, j) += b(i, j);
400 }
401 }
402 return *this;
403}
404
405
406
407/** componentswise subtraction assignment of two matrices
408 * This method is equivalent to @n this+=(-iB) .
409 *
410 * @sa Matrix<T>::operator+=
411 *
412 * @pre @c this must be an l-value (storage matrix).
413 *
414 * @par Complexity:
415 * O(this->rows() * this->columns())
416 *
417 * @throw an exception is thrown if @a *this and @a iB are not of the same dimensions
418 */
419template <typename T, typename S>
420template <typename S2>
422{
423 LASS_META_ASSERT(TStorage::lvalue, this_is_not_an_lvalue);
424 LASS_NUM_MATRIX_ENFORCE_EQUAL_DIMENSION(*this, other);
425 const S2& b = other.storage();
426 const TSize m = rows();
427 const TSize n = columns();
428 for (TSize i = 0; i < m; ++i)
429 {
430 for (TSize j = 0; j < n; ++j)
431 {
432 storage_(i, j) -= b(i, j);
433 }
434 }
435 return *this;
436}
437
438
439
440/** scalar multiplication assignment of matrix
441 *
442 * @pre @c this must be an l-value (storage matrix).
443 *
444 * @par Complexity:
445 * O(this->rows() * this->columns())
446 */
447template <typename T, typename S>
449{
450 LASS_META_ASSERT(TStorage::lvalue, this_is_not_an_lvalue);
451 const TSize m = rows();
452 const TSize n = columns();
453 for (TSize i = 0; i < m; ++i)
454 {
455 for (TSize j = 0; j < n; ++j)
456 {
457 storage_(i, j) *= scalar;
458 }
459 }
460 return *this;
461}
462
463
464
465/** scalar multiplication assignment of matrix
466 *
467 * @pre @c this must be an l-value (storage matrix).
468 */
469template <typename T, typename S>
471{
472 LASS_META_ASSERT(TStorage::lvalue, this_is_not_an_lvalue);
473 const TSize m = rows();
474 const TSize n = columns();
475 for (TSize i = 0; i < m; ++i)
476 {
477 for (TSize j = 0; j < n; ++j)
478 {
479 storage_(i, j) /= scalar;
480 }
481 }
482 return *this;
483}
484
485
486
487/** set this to a zero matrix of @a rows rows and @a columns columns.
488 * @sa Matrix<T>::isZero
489 *
490 * @pre this should be an lvalue
491 *
492 * @par Complexity:
493 * O(this->rows() * this->columns())
494 */
495template <typename T, typename S>
497{
498 LASS_META_ASSERT(TStorage::lvalue, this_is_not_an_lvalue);
499 storage_.resize(rows, columns);
500 for (TSize i = 0; i < rows; ++i)
501 {
502 for (TSize j = 0; j < columns; ++j)
503 {
504 storage_(i, j) = TNumTraits::zero;
505 }
506 }
507}
508
509
510
511/** set matrix to an identity matrix.
512 * @sa Matrix<T>::isIdentity
513 *
514 * @pre this should be an lvalue
515 *
516 * @par Complexity:
517 * O(this->rows() * this->columns())
518 */
519template <typename T, typename S>
521{
522 LASS_META_ASSERT(TStorage::lvalue, this_is_not_an_lvalue);
523 storage_.resize(iSize, iSize);
524 for (TSize i = 0; i < iSize; ++i)
525 {
526 for (TSize j = 0; j < iSize; ++j)
527 {
528 storage_(i, j) = i == j ? TNumTraits::one : TNumTraits::zero;
529 }
530 }
531}
532
533
534
535/** return true if this is a (0�0) matrix
536 *
537 * @par Complexity:
538 * O(1)
539 *
540 * @par Exception safety:
541 * no-fail
542 */
543template <typename T, typename S>
545{
546 return storage_.rows() == 0 || storage_.columns() == 0;
547}
548
549
550
551/** test if this matrix equals a zero matrix.
552 *
553 * <i>A zero matrix is an @n m�n matrix consisting of all 0s (MacDuffee 1943, p. 27), denoted @n 0.
554 * Zero matrices are sometimes also known as null matrices (Akivis and Goldberg 1972, p. 71).</i>
555 * http://mathworld.wolfram.com/ZeroMatrix.html
556 *
557 * an empty matrix is also a zero matrix.
558 *
559 * @par Complexity:
560 * O(this->rows() * this->columns())
561 */
562template <typename T, typename S>
564{
565 const TSize m = rows();
566 const TSize n = columns();
567 for (TSize i = 0; i < m; ++i)
568 {
569 for (TSize j = 0; j < n; ++j)
570 {
571 if (storage_(i, j) != TNumTraits::zero)
572 {
573 return false;
574 }
575 }
576 }
577 return true;
578}
579
580
581
582/** test if this matrix equals a identity matrix
583 *
584 * <i>The identity matrix is a the simplest nontrivial diagonal matrix, defined such that @n I(X)=X
585 * for all vectors @n X. An identity matrix may be denoted @n 1, @n I, or @n E (the latter being an
586 * abbreviation for the German term "Einheitsmatrix"; Courant and Hilbert 1989, p. 7). Identity
587 * matrices are sometimes also known as unit matrices (Akivis and Goldberg 1972, p. 71). The
588 * @n n�n identity matrix is given explicitly by @n Iij=dij for @n i, @n j = 1, 2, ..., n, where
589 * @n dij is the Kronecker delta.</i>
590 * http://mathworld.wolfram.com/IdentityMatrix.html
591 *
592 * an empty matrix is also an identity matrix.
593 *
594 * @par Complexity:
595 * O(this->rows() * this->columns())
596 */
597template <typename T, typename S>
599{
600 if (!isSquare())
601 {
602 return false;
603 }
604 const TSize m = rows();
605 const TSize n = columns();
606 for (TSize i = 0; i < m; ++i)
607 {
608 for (TSize j = 0; j < n; ++j)
609 {
610 if (storage_(i, j) != ((i == j) ? TNumTraits::one : TNumTraits::zero))
611 {
612 return false;
613 }
614 }
615 }
616 return true;
617}
618
619
620
621/** test if this matrix is an diagonal matrix
622 *
623 * <i>A diagonal matrix is a square matrix @n A of the form @n Aij=Ci*dij where @n dij is the
624 * Kronecker delta, @n Ci are constants, and @n i, @n j = 1, 2, ..., n, with is no implied
625 * summation over indices.</i>
626 * http://mathworld.wolfram.com/DiagonalMatrix.html
627 *
628 * @note both square zero matrices and identity matrices will yield true on this one.
629 *
630 * @par Complexity:
631 * O(this->rows() * this->columns())
632 */
633template <typename T, typename S>
635{
636 if (!isSquare())
637 {
638 return false;
639 }
640 const TSize m = rows();
641 const TSize n = columns();
642 for (TSize i = 0; i < m; ++i)
643 {
644 for (TSize j = 0; j < n; ++j)
645 {
646 if (i != j && storage_(i, j) != TNumTraits::zero)
647 {
648 return false;
649 }
650 }
651 }
652 return true;
653}
654
655
656
657/** return true if matrix has as many rows as columns
658 *
659 * @par Complexity:
660 * O(1)
661 */
662template <typename T, typename S>
664{
665 return storage_.rows() == storage_.columns();
666}
667
668
669
670/** return transposed matrix
671 *
672 * @par Complexity:
673 * O(1)
674 */
675template <typename T, typename S>
678{
679 typedef impl::MTrans<T, S> TExpression;
680 return Matrix<T, TExpression>(TExpression(storage_));
681}
682
683
684
685/** replace matrix by its inverse.
686 *
687 * If matrix has no inverse (this is singular), no exception is thrown. Instead, an empty matrix
688 * is made.
689 *
690 * @pre @c this must be an l-value (storage matrix).
691 *
692 * @result true if succeeded, false if not.
693 * @throw an exception is thrown if this is not a square matrix
694 */
695template <typename T, typename S>
697{
698 LASS_META_ASSERT(TStorage::lvalue, this_is_not_an_lvalue);
699 LASS_ENFORCE(isSquare());
700
701 const TSize size = rows();
702 Matrix<T> lu(*this);
703 std::vector<std::ptrdiff_t> index(size);
704 const std::ptrdiff_t n = static_cast<std::ptrdiff_t>(size);
705 int d;
706
707 if (!impl::ludecomp<T>(lu.storage().rowMajor(), index.begin(), n, d))
708 {
709 LASS_THROW_EX(util::SingularityError, "failed to invert matrix");
710 }
711
712 setIdentity(size);
713 for (std::ptrdiff_t i = 0; i < n; ++i)
714 {
715 impl::lusolve<T>(lu.storage().rowMajor(), index.begin(), column(i).begin(), n);
716 }
717}
718
719
720
721template <typename T, typename S> inline
722const typename Matrix<T, S>::TStorage&
723Matrix<T, S>::storage() const
724{
725 return storage_;
726}
727
728
729
730template <typename T, typename S> inline
731typename Matrix<T, S>::TStorage&
732Matrix<T, S>::storage()
733{
734 return storage_;
735}
736
737
738
739/** swap two matrices
740 *
741 * @pre @c this and @a other must be an l-value (storage matrix).
742 *
743 * @par Complexity:
744 * O(1)
745 *
746 * @par Exception safety:
747 * no-fail
748 */
749template <typename T, typename S> inline
751{
752 LASS_META_ASSERT(TStorage::lvalue, this_is_not_an_lvalue);
753 storage_.swap(other.storage_);
754}
755
756
757
758// --- protected -----------------------------------------------------------------------------------
759
760
761
762// --- private -------------------------------------------------------------------------------------
763
764
765
766// --- free ----------------------------------------------------------------------------------------
767
768/** @relates lass::num::Matrix
769 *
770 * @par Complexity:
771 * O(a.rows() * a.columns())
772 */
773template <typename T, typename S1, typename S2>
774bool operator==(const Matrix<T, S1>& a, const Matrix<T, S2>& b)
775{
776 if (a.rows() != b.rows() || a.columns() != b.columns())
777 {
778 return false;
779 }
780 typedef typename Matrix<T, S1>::TSize TSize;
781 const TSize m = a.rows();
782 const TSize n = a.columns();
783 for (TSize i = 0; i < m; ++i)
784 {
785 for (TSize j = 0; j < n; ++j)
786 {
787 if (a(i, j) != b(i, j))
788 {
789 return false;
790 }
791 }
792 }
793 return true;
794}
795
796
797
798/** @relates lass::num::Matrix
799 *
800 * @par Complexity:
801 * O(a.rows() * a.columns())
802 */
803template <typename T, typename S1, typename S2>
804bool operator!=(const Matrix<T, S1>& a, const Matrix<T, S2>& b)
805{
806 return !(a == b);
807}
808
809
810
811/** componentwise addition
812 * @relates lass::num::Matrix
813 *
814 * @par Complexity:
815 * O(1)
816 */
817template <typename T, typename S1, typename S2>
820{
821 LASS_NUM_MATRIX_ENFORCE_EQUAL_DIMENSION(a, b);
822 typedef impl::MAdd<T, S1, S2> TExpression;
823 return Matrix<T, TExpression>(TExpression(a.storage(), b.storage()));
824}
825
826
827
828/** componentwise addition
829 * @relates lass::num::Matrix
830 *
831 * @par Complexity:
832 * O(1)
833 */
834template <typename T, typename S1, typename S2>
837{
838 LASS_NUM_MATRIX_ENFORCE_EQUAL_DIMENSION(a, b);
839 typedef impl::MSub<T, S1, S2> TExpression;
840 return Matrix<T, TExpression>(TExpression(a.storage(), b.storage()));
841}
842
843
844
845/** Matrix multiplication
846 * @relates lass::num::Matrix
847 *
848 * <i>The product @n C of two matrices @n A and @n B is defined by @n Cik=Aij*Bjk, where @n j is
849 * summed over for all possible values of @n i and @n k. The implied summation over repeated
850 * indices without the presence of an explicit sum sign is called Einstein summation, and is
851 * commonly used in both matrix and tensor analysis. Therefore, in order for matrix multiplication
852 * to be defined, the dimensions of the matrices must satisfy @n (n�m)*(m�p)=(n�p) where @n (a�b)
853 * denotes a matrix with @n a rows and @n b columns.</i>
854 * http://mathworld.wolfram.com/MatrixMultiplication.html
855 *
856 * @throw an exception is throw in @a a and @a b don't meet the requirement
857 * @n a.columns()==b.rows() .
858 *
859 * @par Complexity:
860 * O(1)
861 */
862template <typename T, typename S1, typename S2>
865{
866 LASS_NUM_MATRIX_ENFORCE_ADJACENT_DIMENSION(a, b);
867 typedef impl::MProd<T, S1, S2> TExpression;
868 return Matrix<T, TExpression>(TExpression(a.storage(), b.storage()));
869}
870
871
872
873/** add @a a to all components of @a b
874 * @relates lass::num::Matrix
875 *
876 * @par Complexity:
877 * O(1)
878 */
879template <typename T, typename S>
881operator+(const T& a, const Matrix<T, S>& b)
882{
883 typedef impl::MAdd<T, impl::MScalar<T>, S> TExpression;
884 return Matrix<T, TExpression>(TExpression(
885 impl::MScalar<T>(a, b.rows(), b.cols()), b.storage()));
886}
887
888
889
890/** add @a a to all negated components of @a b
891 * @relates lass::num::Matrix
892 *
893 * @par Complexity:
894 * O(1)
895 */
896template <typename T, typename S>
898operator-(const T& a, const Matrix<T, S>& b)
899{
900 typedef impl::MSub<T, impl::MScalar<T>, S> TExpression;
901 return Matrix<T, TExpression>(TExpression(
902 impl::MScalar<T>(a, b.rows(), b.cols()), b.storage()));
903}
904
905
906
907/** multiply @a a with all components of @a b
908 * @relates lass::num::Matrix
909 *
910 * @par Complexity:
911 * O(1)
912 */
913template <typename T, typename S>
915operator*(const T& a, const Matrix<T, S>& b)
916{
917 typedef impl::MMul<T, impl::MScalar<T>, S> TExpression;
918 return Matrix<T, TExpression>(TExpression(
919 impl::MScalar<T>(a, b.rows(), b.columns()), b.storage()));
920}
921
922
923
924/** add @a b to all components of @a a
925 * @relates lass::num::Matrix
926 *
927 * @par Complexity:
928 * O(1)
929 */
930template <typename T, typename S>
932operator+(const Matrix<T, S>& a, typename Matrix<T, S>::TParam b)
933{
934 typedef impl::MAdd<T, S, impl::MScalar<T> > TExpression;
935 return Matrix<T, TExpression>(TExpression(
936 a.storage(), impl::MScalar<T>(b, a.rows(), a.cols())));
937}
938
939
940
941/** subtract @a b from all components of @a a
942 * @relates lass::num::Matrix
943 *
944 * @par Complexity:
945 * O(1)
946 */
947template <typename T, typename S>
949operator-(const Matrix<T, S>& a, typename Matrix<T, S>::TParam b)
950{
951 typedef impl::MSub<T, S, impl::MScalar<T> > TExpression;
952 return Matrix<T, TExpression>(TExpression(
953 a.storage(), impl::MScalar<T>(-b, a.rows(), a.cols())));
954}
955
956
957
958/** multiply all components of @a a with @a b.
959 * @relates lass::num::Matrix
960 *
961 * @par Complexity:
962 * O(1)
963 */
964template <typename T, typename S>
966operator*(const Matrix<T, S>& a, typename Matrix<T, S>::TParam b)
967{
968 typedef impl::MMul<T, S, impl::MScalar<T> > TExpression;
969 return Matrix<T, TExpression>(TExpression(
970 a.storage(), impl::MScalar<T>(b, a.rows(), a.columns())));
971}
972
973
974
975/** divide all components of @a a by @a b.
976 * @relates lass::num::Matrix
977 *
978 * @par Complexity:
979 * O(1)
980 */
981template <typename T, typename S>
983operator/(const Matrix<T, S>& a, typename Matrix<T, S>::TParam b)
984{
985 typedef impl::MMul<T, S, impl::MScalar<T> > TExpression;
986 return Matrix<T, TExpression>(TExpression(
987 a.storage(), impl::MScalar<T>(num::inv(b), a.rows(), a.columns())));
988}
989
990
991
992/** solve equation A * X = B
993 *
994 * @param a [in] matrix A
995 * @param bx [in,out] serves both as the input matrix B and the output matrix X.
996 * @param improve [in] if true, it will perform an extra iteration to improve the solution,
997 * but it comes at the cost of having to take an extra copy of @a a.
998 *
999 * @pre @a bx must be an l-value (storage matrix)
1000 *
1001 * @relates lass::num::Matrix
1002 * @throw an exception is thrown if dimensions don't match
1003 * (this->isSquare() && this->columns() == bx.rows())
1004 */
1005template <typename T, typename S, typename S2>
1006void solve(const Matrix<T, S>& a, Matrix<T, S2>& bx, bool improve)
1007{
1008 LASS_META_ASSERT(S2::lvalue, bx_isnt_an_lvalue);
1009 LASS_ENFORCE(a.isSquare());
1010 LASS_NUM_MATRIX_ENFORCE_ADJACENT_DIMENSION(a, bx);
1011
1012 const size_t n = a.rows();
1013 Matrix<T> lu(a);
1014 std::vector<std::ptrdiff_t> pivot(n);
1015 int d;
1016
1017 Matrix<T> aa;
1018 std::vector<T> bcol;
1019 if (improve)
1020 {
1021 aa = a;
1022 bcol.resize(n);
1023 }
1024
1025 if (!impl::ludecomp<T>(lu.storage().rowMajor(), pivot.begin(), static_cast<std::ptrdiff_t>(n), d))
1026 {
1027 LASS_THROW_EX(util::SingularityError, "failed to solve matrix equation");
1028 }
1029
1030 for (size_t i = 0; i < bx.columns(); ++i)
1031 {
1032 LASS_ASSERT(static_cast<int>(i) >= 0);
1033 typename Matrix<T, S2>::Column xcol = bx.column(static_cast<int>(i));
1034 if (improve)
1035 {
1036 for (size_t j = 0; j < n; ++j)
1037 {
1038 bcol[j] = xcol[j];
1039 }
1040 }
1041 impl::lusolve<T>(lu.storage().rowMajor(), pivot.begin(), xcol.begin(), static_cast<std::ptrdiff_t>(n));
1042 if (improve)
1043 {
1044 impl::lumprove<T>(aa.storage().rowMajor(), lu.storage().rowMajor(), pivot.begin(), bcol.begin(), xcol.begin(), static_cast<std::ptrdiff_t>(n));
1045 }
1046 }
1047}
1048
1049
1050
1051/** @relates lass::num::Matrix
1052 */
1053template <typename T, typename S, typename Char, typename Traits>
1054std::basic_ostream<Char, Traits>&
1055operator<<(std::basic_ostream<Char, Traits>& stream, const Matrix<T, S>& matrix)
1056{
1057 typedef typename Matrix<T, S>::TSize TSize;
1058 const TSize m = matrix.rows();
1059 const TSize n = matrix.columns();
1060
1061 LASS_ENFORCE_STREAM(stream) << "(";
1062 for (TSize i = 0; i < m; ++i)
1063 {
1064 if (i != 0)
1065 {
1066 LASS_ENFORCE_STREAM(stream) << ", ";
1067 }
1068 LASS_ENFORCE_STREAM(stream) << "(";
1069 if (n > 0)
1070 {
1071 LASS_ENFORCE_STREAM(stream) << matrix(i, 0);
1072 }
1073 for (TSize j = 1; j < n; ++j)
1074 {
1075 LASS_ENFORCE_STREAM(stream) << ", " << matrix(i, j);
1076 }
1077 LASS_ENFORCE_STREAM(stream) << ")";
1078 }
1079 LASS_ENFORCE_STREAM(stream) << ")";
1080 return stream;
1081}
1082
1083
1084
1085}
1086
1087}
1088
1089#endif
1090
1091// EOF
a dynamic sized n-dimensional matrix with expression templates
Definition matrix.h:70
bool isDiagonal() const
test if this matrix is an diagonal matrix
Definition matrix.inl:634
const Matrix< T, impl::MMul< T, impl::MScalar< T >, S > > operator*(const T &a, const Matrix< T, S > &b)
multiply a with all components of b
Definition matrix.inl:915
const Matrix< T, impl::MMul< T, S, impl::MScalar< T > > > operator/(const Matrix< T, S > &a, typename Matrix< T, S >::TParam b)
divide all components of a by b.
Definition matrix.inl:983
const Matrix< T, impl::MAdd< T, S, impl::MScalar< T > > > operator-(const Matrix< T, S > &a, typename Matrix< T, S >::TParam b)
subtract b from all components of a
Definition matrix.inl:949
void solve(const Matrix< T, S > &a, Matrix< T, S2 > &bx, bool improve)
solve equation A * X = B
Definition matrix.inl:1006
Matrix< T, S > & operator=(const Matrix< T2, S2 > &other)
assign storage/expression matrix to this (this should be a storage matrix).
Definition matrix.inl:164
const Matrix< T, impl::MAdd< T, S, impl::MScalar< T > > > operator+(const Matrix< T, S > &a, typename Matrix< T, S >::TParam b)
add b to all components of a
Definition matrix.inl:932
Matrix< T, S > & operator/=(TParam scalar)
scalar multiplication assignment of matrix
Definition matrix.inl:470
void setIdentity(TSize size)
set matrix to an identity matrix.
Definition matrix.inl:520
const Matrix< T, impl::MAdd< T, S1, S2 > > operator+(const Matrix< T, S1 > &a, const Matrix< T, S2 > &b)
componentwise addition
Definition matrix.inl:819
bool isIdentity() const
test if this matrix equals a identity matrix
Definition matrix.inl:598
Matrix< T, S > & operator*=(TParam scalar)
scalar multiplication assignment of matrix
Definition matrix.inl:448
Matrix< T, S > & operator-=(const Matrix< T, S2 > &other)
componentswise subtraction assignment of two matrices This method is equivalent to this+=(-iB) .
Definition matrix.inl:421
bool isSquare() const
return true if matrix has as many rows as columns
Definition matrix.inl:663
void invert()
replace matrix by its inverse.
Definition matrix.inl:696
const TValue at(TSigned row, TSigned column) const
return the component value at position (row, column) (row, column) will be wrapped to range [0,...
Definition matrix.inl:261
const Matrix< T, impl::MNeg< T, S > > operator-() const
return a vector with all components negated (-a)(i, j) == -(a(i, j)).
Definition matrix.inl:361
Matrix()
constructs an empty matrix
Definition matrix.inl:84
const TSize columns() const
return number of columns in matrix.
Definition matrix.inl:215
const Matrix< T, impl::MSub< T, impl::MScalar< T >, S > > operator-(const T &a, const Matrix< T, S > &b)
add a to all negated components of b
Definition matrix.inl:898
void setZero(TSize rows, TSize columns)
set this to a zero matrix of rows rows and columns columns.
Definition matrix.inl:496
const Matrix< T, S > & operator+() const
A weird way to get back the same object.
Definition matrix.inl:343
const Matrix< T, impl::MMul< T, S, impl::MScalar< T > > > operator*(const Matrix< T, S > &a, typename Matrix< T, S >::TParam b)
multiply all components of a with b.
Definition matrix.inl:966
const Matrix< T, impl::MProd< T, S1, S2 > > operator*(const Matrix< T, S1 > &a, const Matrix< T, S2 > &b)
Matrix multiplication.
Definition matrix.inl:864
const TSize rows() const
return number of rows in matrix.
Definition matrix.inl:196
const Matrix< T, impl::MAdd< T, impl::MScalar< T >, S > > operator+(const T &a, const Matrix< T, S > &b)
add a to all components of b
Definition matrix.inl:881
bool operator!=(const Matrix< T, S1 > &a, const Matrix< T, S2 > &b)
Definition matrix.inl:804
ConstRow row(TSigned index) const
return a row of matrix.
Definition matrix.inl:289
const Matrix< T, impl::MSub< T, S1, S2 > > operator-(const Matrix< T, S1 > &a, const Matrix< T, S2 > &b)
componentwise addition
Definition matrix.inl:836
const Matrix< T, impl::MTrans< T, S > > transposed() const
return transposed matrix
Definition matrix.inl:677
void swap(Matrix< T, S > &other)
swap two matrices
Definition matrix.inl:750
bool isEmpty() const
return true if this is a (0�0) matrix
Definition matrix.inl:544
ConstColumn column(TSigned index) const
return a column of matrix.
Definition matrix.inl:314
Matrix< T, S > & operator+=(const Matrix< T, S2 > &other)
componentswise addition assignment of two matrices
Definition matrix.inl:388
const TValue operator()(TSize row, TSize column) const
return the component value at position (row, column)
Definition matrix.inl:229
bool operator==(const Matrix< T, S1 > &a, const Matrix< T, S2 > &b)
Definition matrix.inl:774
bool isZero() const
test if this matrix equals a zero matrix.
Definition matrix.inl:563
T inv(const T &x)
return x ^ -1
Definition basic_ops.h:178
void lusolve(RandomIterator1 iMatrix, RandomIterator2 iIndex, RandomIterator3 ioColumn, std::ptrdiff_t iSize)
Solves the set of linear eqautions A X = B.
void lumprove(RandomIterator1 iMatrix, RandomIterator2 iMatrixLU, RandomIterator3 iIndex, RandomIterator4 iColumn, RandomIterator5 ioX, std::ptrdiff_t iSize)
Improves a solution vector X of the linear set of equations A X = B.
bool ludecomp(RandomIterator1 ioMatrix, RandomIterator2 oIndex, std::ptrdiff_t iSize, int &iD)
Given a complex matrix iA, this routine replaces it by the LU decomposition of a rowwise permutation ...
#define LASS_META_ASSERT(expression, message)
complite time static check
numeric types and traits.
Definition basic_ops.h:70
Library for Assembled Shared Sources.
Definition config.h:53