1 /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 
3 /*
4  Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl
5  Copyright (C) 2003, 2004, 2005, 2006 StatPro Italia srl
6  Copyright (C) 2003, 2004 Ferdinando Ametrano
7  Copyright (C) 2015 Michael von den Driesch
8  This file is part of QuantLib, a free-software/open-source library
9  for financial quantitative analysts and developers - http://quantlib.org/
10 
11  QuantLib is free software: you can redistribute it and/or modify it
12  under the terms of the QuantLib license.  You should have received a
13  copy of the license along with this program; if not, please email
14  <quantlib-dev@lists.sf.net>. The license is also available online at
15  <http://quantlib.org/license.shtml>.
16 
17  This program is distributed in the hope that it will be useful, but WITHOUT
18  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19  FOR A PARTICULAR PURPOSE.  See the license for more details.
20 */
21 
22 /*! \file matrix.hpp
23     \brief matrix used in linear algebra.
24 */
25 
26 #ifndef quantlib_matrix_hpp
27 #define quantlib_matrix_hpp
28 
29 #include <ql/math/array.hpp>
30 #include <ql/utilities/steppingiterator.hpp>
31 
32 namespace QuantLib {
33 
34     //! %Matrix used in linear algebra.
35     /*! This class implements the concept of Matrix as used in linear
36         algebra. As such, it is <b>not</b> meant to be used as a
37         container.
38     */
39     class Matrix {
40       public:
41         //! \name Constructors, destructor, and assignment
42         //@{
43         //! creates a null matrix
44         Matrix();
45         //! creates a matrix with the given dimensions
46         Matrix(Size rows, Size columns);
47         //! creates the matrix and fills it with <tt>value</tt>
48         Matrix(Size rows, Size columns, Real value);
49         //! creates the matrix and fills it with data from a range.
50         /*! \warning if the range defined by [begin, end) is larger
51             than the size of the matrix, a memory access violation
52             might occur.  It is up to the user to avoid this.
53         */
54         template <class Iterator>
55         Matrix(Size rows, Size columns, Iterator begin, Iterator end);
56         Matrix(const Matrix &);
57         Matrix(const Disposable<Matrix>&);
58         Matrix& operator=(const Matrix&);
59         Matrix& operator=(const Disposable<Matrix>&);
60         //@}
61 
62         //! \name Algebraic operators
63         /*! \pre all matrices involved in an algebraic expression must have
64                  the same size.
65         */
66         //@{
67         const Matrix& operator+=(const Matrix&);
68         const Matrix& operator-=(const Matrix&);
69         const Matrix& operator*=(Real);
70         const Matrix& operator/=(Real);
71         //@}
72 
73         typedef Real* iterator;
74         typedef const Real* const_iterator;
75         typedef boost::reverse_iterator<iterator> reverse_iterator;
76         typedef boost::reverse_iterator<const_iterator> const_reverse_iterator;
77         typedef Real* row_iterator;
78         typedef const Real* const_row_iterator;
79         typedef boost::reverse_iterator<row_iterator> reverse_row_iterator;
80         typedef boost::reverse_iterator<const_row_iterator>
81                                                 const_reverse_row_iterator;
82         typedef step_iterator<iterator> column_iterator;
83         typedef step_iterator<const_iterator> const_column_iterator;
84         typedef boost::reverse_iterator<column_iterator>
85                                                    reverse_column_iterator;
86         typedef boost::reverse_iterator<const_column_iterator>
87                                              const_reverse_column_iterator;
88         //! \name Iterator access
89         //@{
90         const_iterator begin() const;
91         iterator begin();
92         const_iterator end() const;
93         iterator end();
94         const_reverse_iterator rbegin() const;
95         reverse_iterator rbegin();
96         const_reverse_iterator rend() const;
97         reverse_iterator rend();
98         const_row_iterator row_begin(Size i) const;
99         row_iterator row_begin(Size i);
100         const_row_iterator row_end(Size i) const;
101         row_iterator row_end(Size i);
102         const_reverse_row_iterator row_rbegin(Size i) const;
103         reverse_row_iterator row_rbegin(Size i);
104         const_reverse_row_iterator row_rend(Size i) const;
105         reverse_row_iterator row_rend(Size i);
106         const_column_iterator column_begin(Size i) const;
107         column_iterator column_begin(Size i);
108         const_column_iterator column_end(Size i) const;
109         column_iterator column_end(Size i);
110         const_reverse_column_iterator column_rbegin(Size i) const;
111         reverse_column_iterator column_rbegin(Size i);
112         const_reverse_column_iterator column_rend(Size i) const;
113         reverse_column_iterator column_rend(Size i);
114         //@}
115 
116         //! \name Element access
117         //@{
118         const_row_iterator operator[](Size) const;
119         const_row_iterator at(Size) const;
120         row_iterator operator[](Size);
121         row_iterator at(Size);
122         Disposable<Array> diagonal() const;
123         Real& operator()(Size i, Size j) const;
124         //@}
125 
126         //! \name Inspectors
127         //@{
128         Size rows() const;
129         Size columns() const;
130         bool empty() const;
131         Size size1() const;
132         Size size2() const;
133         //@}
134 
135         //! \name Utilities
136         //@{
137         void swap(Matrix&);
138         //@}
139       private:
140         boost::scoped_array<Real> data_;
141         Size rows_, columns_;
142     };
143 
144     // algebraic operators
145 
146     /*! \relates Matrix */
147     Disposable<Matrix> operator+(const Matrix&, const Matrix&);
148     /*! \relates Matrix */
149     Disposable<Matrix> operator-(const Matrix&, const Matrix&);
150     /*! \relates Matrix */
151     Disposable<Matrix> operator*(const Matrix&, Real);
152     /*! \relates Matrix */
153     Disposable<Matrix> operator*(Real, const Matrix&);
154     /*! \relates Matrix */
155     Disposable<Matrix> operator/(const Matrix&, Real);
156 
157 
158     // vectorial products
159 
160     /*! \relates Matrix */
161     Disposable<Array> operator*(const Array&, const Matrix&);
162     /*! \relates Matrix */
163     Disposable<Array> operator*(const Matrix&, const Array&);
164     /*! \relates Matrix */
165     Disposable<Matrix> operator*(const Matrix&, const Matrix&);
166 
167     // misc. operations
168 
169     /*! \relates Matrix */
170     Disposable<Matrix> transpose(const Matrix&);
171 
172     /*! \relates Matrix */
173     Disposable<Matrix> outerProduct(const Array& v1, const Array& v2);
174 
175     /*! \relates Matrix */
176     template <class Iterator1, class Iterator2>
177     Disposable<Matrix>
178     outerProduct(Iterator1 v1begin, Iterator1 v1end, Iterator2 v2begin, Iterator2 v2end);
179 
180     /*! \relates Matrix */
181     void swap(Matrix&, Matrix&);
182 
183     /*! \relates Matrix */
184     std::ostream& operator<<(std::ostream&, const Matrix&);
185 
186     /*! \relates Matrix */
187     Disposable<Matrix> inverse(const Matrix& m);
188 
189     /*! \relates Matrix */
190     Real determinant(const Matrix& m);
191 
192     // inline definitions
193 
Matrix()194     inline Matrix::Matrix()
195     : data_((Real*)(0)), rows_(0), columns_(0) {}
196 
Matrix(Size rows,Size columns)197     inline Matrix::Matrix(Size rows, Size columns)
198     : data_(rows*columns > 0 ? new Real[rows*columns] : (Real*)(0)),
199       rows_(rows), columns_(columns) {}
200 
Matrix(Size rows,Size columns,Real value)201     inline Matrix::Matrix(Size rows, Size columns, Real value)
202     : data_(rows*columns > 0 ? new Real[rows*columns] : (Real*)(0)),
203       rows_(rows), columns_(columns) {
204         std::fill(begin(),end(),value);
205     }
206 
207     template <class Iterator>
Matrix(Size rows,Size columns,Iterator begin,Iterator end)208     inline Matrix::Matrix(Size rows, Size columns,
209                           Iterator begin, Iterator end)
210         : data_(rows * columns > 0 ? new Real[rows * columns] : (Real *)(0)),
211           rows_(rows), columns_(columns) {
212         std::copy(begin, end, this->begin());
213     }
214 
Matrix(const Matrix & from)215     inline Matrix::Matrix(const Matrix& from)
216     : data_(!from.empty() ? new Real[from.rows_*from.columns_] : (Real*)(0)),
217       rows_(from.rows_), columns_(from.columns_) {
218         #if defined(QL_PATCH_MSVC) && defined(QL_DEBUG)
219         if (!from.empty())
220         #endif
221         std::copy(from.begin(),from.end(),begin());
222     }
223 
Matrix(const Disposable<Matrix> & from)224     inline Matrix::Matrix(const Disposable<Matrix>& from)
225     : data_((Real*)(0)), rows_(0), columns_(0) {
226         swap(const_cast<Disposable<Matrix>&>(from));
227     }
228 
operator =(const Matrix & from)229     inline Matrix& Matrix::operator=(const Matrix& from) {
230         // strong guarantee
231         Matrix temp(from);
232         swap(temp);
233         return *this;
234     }
235 
operator =(const Disposable<Matrix> & from)236     inline Matrix& Matrix::operator=(const Disposable<Matrix>& from) {
237         swap(const_cast<Disposable<Matrix>&>(from));
238         return *this;
239     }
240 
swap(Matrix & from)241     inline void Matrix::swap(Matrix& from) {
242         using std::swap;
243         data_.swap(from.data_);
244         swap(rows_,from.rows_);
245         swap(columns_,from.columns_);
246     }
247 
operator +=(const Matrix & m)248     inline const Matrix& Matrix::operator+=(const Matrix& m) {
249         QL_REQUIRE(rows_ == m.rows_ && columns_ == m.columns_,
250                    "matrices with different sizes (" <<
251                    m.rows_ << "x" << m.columns_ << ", " <<
252                    rows_ << "x" << columns_ << ") cannot be "
253                    "added");
254         std::transform(begin(),end(),m.begin(),
255                        begin(),std::plus<Real>());
256         return *this;
257     }
258 
operator -=(const Matrix & m)259     inline const Matrix& Matrix::operator-=(const Matrix& m) {
260         QL_REQUIRE(rows_ == m.rows_ && columns_ == m.columns_,
261                    "matrices with different sizes (" <<
262                    m.rows_ << "x" << m.columns_ << ", " <<
263                    rows_ << "x" << columns_ << ") cannot be "
264                    "subtracted");
265         std::transform(begin(),end(),m.begin(),begin(),
266                        std::minus<Real>());
267         return *this;
268     }
269 
operator *=(Real x)270     inline const Matrix& Matrix::operator*=(Real x) {
271         std::transform(begin(),end(),begin(),
272                        multiply_by<Real>(x));
273         return *this;
274     }
275 
operator /=(Real x)276     inline const Matrix& Matrix::operator/=(Real x) {
277         std::transform(begin(),end(),begin(),
278                        divide_by<Real>(x));
279         return *this;
280     }
281 
begin() const282     inline Matrix::const_iterator Matrix::begin() const {
283         return data_.get();
284     }
285 
begin()286     inline Matrix::iterator Matrix::begin() {
287         return data_.get();
288     }
289 
end() const290     inline Matrix::const_iterator Matrix::end() const {
291         return data_.get()+rows_*columns_;
292     }
293 
end()294     inline Matrix::iterator Matrix::end() {
295         return data_.get()+rows_*columns_;
296     }
297 
rbegin() const298     inline Matrix::const_reverse_iterator Matrix::rbegin() const {
299         return const_reverse_iterator(end());
300     }
301 
rbegin()302     inline Matrix::reverse_iterator Matrix::rbegin() {
303         return reverse_iterator(end());
304     }
305 
rend() const306     inline Matrix::const_reverse_iterator Matrix::rend() const {
307         return const_reverse_iterator(begin());
308     }
309 
rend()310     inline Matrix::reverse_iterator Matrix::rend() {
311         return reverse_iterator(begin());
312     }
313 
314     inline Matrix::const_row_iterator
row_begin(Size i) const315     Matrix::row_begin(Size i) const {
316         #if defined(QL_EXTRA_SAFETY_CHECKS)
317         QL_REQUIRE(i<rows_,
318                    "row index (" << i << ") must be less than " << rows_ <<
319                    ": matrix cannot be accessed out of range");
320         #endif
321         return data_.get()+columns_*i;
322     }
323 
row_begin(Size i)324     inline Matrix::row_iterator Matrix::row_begin(Size i) {
325         #if defined(QL_EXTRA_SAFETY_CHECKS)
326         QL_REQUIRE(i<rows_,
327                    "row index (" << i << ") must be less than " << rows_ <<
328                    ": matrix cannot be accessed out of range");
329         #endif
330         return data_.get()+columns_*i;
331     }
332 
row_end(Size i) const333     inline Matrix::const_row_iterator Matrix::row_end(Size i) const{
334         #if defined(QL_EXTRA_SAFETY_CHECKS)
335         QL_REQUIRE(i<rows_,
336                    "row index (" << i << ") must be less than " << rows_ <<
337                    ": matrix cannot be accessed out of range");
338         #endif
339         return data_.get()+columns_*(i+1);
340     }
341 
row_end(Size i)342     inline Matrix::row_iterator Matrix::row_end(Size i) {
343         #if defined(QL_EXTRA_SAFETY_CHECKS)
344         QL_REQUIRE(i<rows_,
345                    "row index (" << i << ") must be less than " << rows_ <<
346                    ": matrix cannot be accessed out of range");
347         #endif
348         return data_.get()+columns_*(i+1);
349     }
350 
351     inline Matrix::const_reverse_row_iterator
row_rbegin(Size i) const352     Matrix::row_rbegin(Size i) const {
353         return const_reverse_row_iterator(row_end(i));
354     }
355 
row_rbegin(Size i)356     inline Matrix::reverse_row_iterator Matrix::row_rbegin(Size i) {
357         return reverse_row_iterator(row_end(i));
358     }
359 
360     inline Matrix::const_reverse_row_iterator
row_rend(Size i) const361     Matrix::row_rend(Size i) const {
362         return const_reverse_row_iterator(row_begin(i));
363     }
364 
row_rend(Size i)365     inline Matrix::reverse_row_iterator Matrix::row_rend(Size i) {
366         return reverse_row_iterator(row_begin(i));
367     }
368 
369     inline Matrix::const_column_iterator
column_begin(Size i) const370     Matrix::column_begin(Size i) const {
371         #if defined(QL_EXTRA_SAFETY_CHECKS)
372         QL_REQUIRE(i<columns_,
373                    "column index (" << i << ") must be less than " << columns_ <<
374                    ": matrix cannot be accessed out of range");
375         #endif
376         return const_column_iterator(data_.get()+i,columns_);
377     }
378 
column_begin(Size i)379     inline Matrix::column_iterator Matrix::column_begin(Size i) {
380         #if defined(QL_EXTRA_SAFETY_CHECKS)
381         QL_REQUIRE(i<columns_,
382                    "column index (" << i << ") must be less than " << columns_ <<
383                    ": matrix cannot be accessed out of range");
384         #endif
385         return column_iterator(data_.get()+i,columns_);
386     }
387 
388     inline Matrix::const_column_iterator
column_end(Size i) const389     Matrix::column_end(Size i) const {
390         #if defined(QL_EXTRA_SAFETY_CHECKS)
391         QL_REQUIRE(i<columns_,
392                    "column index (" << i << ") must be less than " << columns_ <<
393                    ": matrix cannot be accessed out of range");
394         #endif
395         return const_column_iterator(data_.get()+i+rows_*columns_,columns_);
396     }
397 
column_end(Size i)398     inline Matrix::column_iterator Matrix::column_end(Size i) {
399         #if defined(QL_EXTRA_SAFETY_CHECKS)
400         QL_REQUIRE(i<columns_,
401                    "column index (" << i << ") must be less than " << columns_ <<
402                    ": matrix cannot be accessed out of range");
403         #endif
404         return column_iterator(data_.get()+i+rows_*columns_,columns_);
405     }
406 
407     inline Matrix::const_reverse_column_iterator
column_rbegin(Size i) const408     Matrix::column_rbegin(Size i) const {
409         return const_reverse_column_iterator(column_end(i));
410     }
411 
412     inline Matrix::reverse_column_iterator
column_rbegin(Size i)413     Matrix::column_rbegin(Size i) {
414         return reverse_column_iterator(column_end(i));
415     }
416 
417     inline Matrix::const_reverse_column_iterator
column_rend(Size i) const418     Matrix::column_rend(Size i) const {
419         return const_reverse_column_iterator(column_begin(i));
420     }
421 
422     inline Matrix::reverse_column_iterator
column_rend(Size i)423     Matrix::column_rend(Size i) {
424         return reverse_column_iterator(column_begin(i));
425     }
426 
427     inline Matrix::const_row_iterator
operator [](Size i) const428     Matrix::operator[](Size i) const {
429         return row_begin(i);
430     }
431 
432     inline Matrix::const_row_iterator
at(Size i) const433     Matrix::at(Size i) const {
434         QL_REQUIRE(i < rows_, "matrix access out of range");
435         return row_begin(i);
436     }
437 
operator [](Size i)438     inline Matrix::row_iterator Matrix::operator[](Size i) {
439         return row_begin(i);
440     }
441 
at(Size i)442     inline Matrix::row_iterator Matrix::at(Size i) {
443         QL_REQUIRE(i < rows_, "matrix access out of range");
444         return row_begin(i);
445     }
446 
diagonal() const447     inline Disposable<Array> Matrix::diagonal() const {
448         Size arraySize = std::min<Size>(rows(), columns());
449         Array tmp(arraySize);
450         for(Size i = 0; i < arraySize; i++)
451             tmp[i] = (*this)[i][i];
452         return tmp;
453     }
454 
operator ()(Size i,Size j) const455     inline Real &Matrix::operator()(Size i, Size j) const {
456         return data_[i*columns()+j];
457     }
458 
rows() const459     inline Size Matrix::rows() const {
460         return rows_;
461     }
462 
columns() const463     inline Size Matrix::columns() const {
464         return columns_;
465     }
466 
size1() const467     inline Size Matrix::size1() const {
468         return rows();
469     }
470 
size2() const471     inline Size Matrix::size2() const {
472         return columns();
473     }
474 
empty() const475     inline bool Matrix::empty() const {
476         return rows_ == 0 || columns_ == 0;
477     }
478 
operator +(const Matrix & m1,const Matrix & m2)479     inline Disposable<Matrix> operator+(const Matrix& m1, const Matrix& m2) {
480         QL_REQUIRE(m1.rows() == m2.rows() &&
481                    m1.columns() == m2.columns(),
482                    "matrices with different sizes (" <<
483                    m1.rows() << "x" << m1.columns() << ", " <<
484                    m2.rows() << "x" << m2.columns() << ") cannot be "
485                    "added");
486         Matrix temp(m1.rows(),m1.columns());
487         std::transform(m1.begin(),m1.end(),m2.begin(),temp.begin(),
488                        std::plus<Real>());
489         return temp;
490     }
491 
operator -(const Matrix & m1,const Matrix & m2)492     inline Disposable<Matrix> operator-(const Matrix& m1, const Matrix& m2) {
493         QL_REQUIRE(m1.rows() == m2.rows() &&
494                    m1.columns() == m2.columns(),
495                    "matrices with different sizes (" <<
496                    m1.rows() << "x" << m1.columns() << ", " <<
497                    m2.rows() << "x" << m2.columns() << ") cannot be "
498                    "subtracted");
499         Matrix temp(m1.rows(),m1.columns());
500         std::transform(m1.begin(),m1.end(),m2.begin(),temp.begin(),
501                        std::minus<Real>());
502         return temp;
503     }
504 
operator *(const Matrix & m,Real x)505     inline Disposable<Matrix> operator*(const Matrix& m, Real x) {
506         Matrix temp(m.rows(),m.columns());
507         std::transform(m.begin(),m.end(),temp.begin(),
508                        multiply_by<Real>(x));
509         return temp;
510     }
511 
operator *(Real x,const Matrix & m)512     inline Disposable<Matrix> operator*(Real x, const Matrix& m) {
513         Matrix temp(m.rows(),m.columns());
514         std::transform(m.begin(),m.end(),temp.begin(),
515                        multiply_by<Real>(x));
516         return temp;
517     }
518 
operator /(const Matrix & m,Real x)519     inline Disposable<Matrix> operator/(const Matrix& m, Real x) {
520         Matrix temp(m.rows(),m.columns());
521         std::transform(m.begin(),m.end(),temp.begin(),
522                        divide_by<Real>(x));
523         return temp;
524     }
525 
operator *(const Array & v,const Matrix & m)526     inline Disposable<Array> operator*(const Array& v, const Matrix& m) {
527         QL_REQUIRE(v.size() == m.rows(),
528                    "vectors and matrices with different sizes ("
529                    << v.size() << ", " << m.rows() << "x" << m.columns() <<
530                    ") cannot be multiplied");
531         Array result(m.columns());
532         for (Size i=0; i<result.size(); i++)
533             result[i] =
534                 std::inner_product(v.begin(),v.end(),
535                                    m.column_begin(i),0.0);
536         return result;
537     }
538 
operator *(const Matrix & m,const Array & v)539     inline Disposable<Array> operator*(const Matrix& m, const Array& v) {
540         QL_REQUIRE(v.size() == m.columns(),
541                    "vectors and matrices with different sizes ("
542                    << v.size() << ", " << m.rows() << "x" << m.columns() <<
543                    ") cannot be multiplied");
544         Array result(m.rows());
545         for (Size i=0; i<result.size(); i++)
546             result[i] =
547                 std::inner_product(v.begin(),v.end(),m.row_begin(i),0.0);
548         return result;
549     }
550 
operator *(const Matrix & m1,const Matrix & m2)551     inline Disposable<Matrix> operator*(const Matrix& m1, const Matrix& m2) {
552         QL_REQUIRE(m1.columns() == m2.rows(),
553                    "matrices with different sizes (" <<
554                    m1.rows() << "x" << m1.columns() << ", " <<
555                    m2.rows() << "x" << m2.columns() << ") cannot be "
556                    "multiplied");
557         Matrix result(m1.rows(),m2.columns(),0.0);
558         for (Size i=0; i<result.rows(); ++i) {
559             for (Size k=0; k<m1.columns(); ++k) {
560                 for (Size j=0; j<result.columns(); ++j) {
561                     result[i][j] += m1[i][k]*m2[k][j];
562                 }
563             }
564         }
565         return result;
566     }
567 
transpose(const Matrix & m)568     inline Disposable<Matrix> transpose(const Matrix& m) {
569         Matrix result(m.columns(),m.rows());
570         #if defined(QL_PATCH_MSVC) && defined(QL_DEBUG)
571         if (!m.empty())
572         #endif
573         for (Size i=0; i<m.rows(); i++)
574             std::copy(m.row_begin(i),m.row_end(i),result.column_begin(i));
575         return result;
576     }
577 
outerProduct(const Array & v1,const Array & v2)578     inline Disposable<Matrix> outerProduct(const Array& v1, const Array& v2) {
579         return outerProduct(v1.begin(), v1.end(), v2.begin(), v2.end());
580     }
581 
582     template <class Iterator1, class Iterator2>
583     inline Disposable<Matrix>
outerProduct(Iterator1 v1begin,Iterator1 v1end,Iterator2 v2begin,Iterator2 v2end)584     outerProduct(Iterator1 v1begin, Iterator1 v1end, Iterator2 v2begin, Iterator2 v2end) {
585 
586         Size size1 = std::distance(v1begin, v1end);
587         QL_REQUIRE(size1>0, "null first vector");
588 
589         Size size2 = std::distance(v2begin, v2end);
590         QL_REQUIRE(size2>0, "null second vector");
591 
592         Matrix result(size1, size2);
593 
594         for (Size i=0; v1begin!=v1end; i++, v1begin++)
595             std::transform(v2begin, v2end, result.row_begin(i),
596                            multiply_by<Real>(*v1begin));
597 
598         return result;
599     }
600 
swap(Matrix & m1,Matrix & m2)601     inline void swap(Matrix& m1, Matrix& m2) {
602         m1.swap(m2);
603     }
604 
operator <<(std::ostream & out,const Matrix & m)605     inline std::ostream& operator<<(std::ostream& out, const Matrix& m) {
606         std::streamsize width = out.width();
607         for (Size i=0; i<m.rows(); i++) {
608             out << "| ";
609             for (Size j=0; j<m.columns(); j++)
610                 out << std::setw(int(width)) << m[i][j] << " ";
611             out << "|\n";
612         }
613         return out;
614     }
615 
616 }
617 
618 
619 #endif
620