/src/quantlib/ql/math/matrix.hpp
Line | Count | Source (jump to first uncovered line) |
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 | | #include <initializer_list> |
32 | | #include <iterator> |
33 | | |
34 | | namespace QuantLib { |
35 | | |
36 | | //! %Matrix used in linear algebra. |
37 | | /*! This class implements the concept of Matrix as used in linear |
38 | | algebra. As such, it is <b>not</b> meant to be used as a |
39 | | container. |
40 | | */ |
41 | | class Matrix { |
42 | | public: |
43 | | //! \name Constructors, destructor, and assignment |
44 | | //@{ |
45 | | //! creates a null matrix |
46 | | Matrix(); |
47 | | //! creates a matrix with the given dimensions |
48 | | Matrix(Size rows, Size columns); |
49 | | //! creates the matrix and fills it with <tt>value</tt> |
50 | | Matrix(Size rows, Size columns, Real value); |
51 | | //! creates the matrix and fills it with data from a range. |
52 | | /*! \warning if the range defined by [begin, end) is larger |
53 | | than the size of the matrix, a memory access violation |
54 | | might occur. It is up to the user to avoid this. |
55 | | */ |
56 | | template <class Iterator> |
57 | | Matrix(Size rows, Size columns, Iterator begin, Iterator end); |
58 | | Matrix(const Matrix&); |
59 | | Matrix(Matrix&&) noexcept; |
60 | | Matrix(std::initializer_list<std::initializer_list<Real>>); |
61 | 0 | ~Matrix() = default; |
62 | | |
63 | | Matrix& operator=(const Matrix&); |
64 | | Matrix& operator=(Matrix&&) noexcept; |
65 | | |
66 | | bool operator==(const Matrix&) const; |
67 | | bool operator!=(const Matrix&) const; |
68 | | //@} |
69 | | |
70 | | //! \name Algebraic operators |
71 | | /*! \pre all matrices involved in an algebraic expression must have |
72 | | the same size. |
73 | | */ |
74 | | //@{ |
75 | | const Matrix& operator+=(const Matrix&); |
76 | | const Matrix& operator-=(const Matrix&); |
77 | | const Matrix& operator*=(Real); |
78 | | const Matrix& operator/=(Real); |
79 | | //@} |
80 | | |
81 | | typedef Real* iterator; |
82 | | typedef const Real* const_iterator; |
83 | | typedef std::reverse_iterator<iterator> reverse_iterator; |
84 | | typedef std::reverse_iterator<const_iterator> const_reverse_iterator; |
85 | | typedef Real* row_iterator; |
86 | | typedef const Real* const_row_iterator; |
87 | | typedef std::reverse_iterator<row_iterator> reverse_row_iterator; |
88 | | typedef std::reverse_iterator<const_row_iterator> |
89 | | const_reverse_row_iterator; |
90 | | typedef step_iterator<iterator> column_iterator; |
91 | | typedef step_iterator<const_iterator> const_column_iterator; |
92 | | typedef std::reverse_iterator<column_iterator> |
93 | | reverse_column_iterator; |
94 | | typedef std::reverse_iterator<const_column_iterator> |
95 | | const_reverse_column_iterator; |
96 | | //! \name Iterator access |
97 | | //@{ |
98 | | const_iterator begin() const; |
99 | | iterator begin(); |
100 | | const_iterator end() const; |
101 | | iterator end(); |
102 | | const_reverse_iterator rbegin() const; |
103 | | reverse_iterator rbegin(); |
104 | | const_reverse_iterator rend() const; |
105 | | reverse_iterator rend(); |
106 | | const_row_iterator row_begin(Size i) const; |
107 | | row_iterator row_begin(Size i); |
108 | | const_row_iterator row_end(Size i) const; |
109 | | row_iterator row_end(Size i); |
110 | | const_reverse_row_iterator row_rbegin(Size i) const; |
111 | | reverse_row_iterator row_rbegin(Size i); |
112 | | const_reverse_row_iterator row_rend(Size i) const; |
113 | | reverse_row_iterator row_rend(Size i); |
114 | | const_column_iterator column_begin(Size i) const; |
115 | | column_iterator column_begin(Size i); |
116 | | const_column_iterator column_end(Size i) const; |
117 | | column_iterator column_end(Size i); |
118 | | const_reverse_column_iterator column_rbegin(Size i) const; |
119 | | reverse_column_iterator column_rbegin(Size i); |
120 | | const_reverse_column_iterator column_rend(Size i) const; |
121 | | reverse_column_iterator column_rend(Size i); |
122 | | //@} |
123 | | |
124 | | //! \name Element access |
125 | | //@{ |
126 | | const_row_iterator operator[](Size) const; |
127 | | const_row_iterator at(Size) const; |
128 | | row_iterator operator[](Size); |
129 | | row_iterator at(Size); |
130 | | Array diagonal() const; |
131 | | Real& operator()(Size i, Size j) const; |
132 | | //@} |
133 | | |
134 | | //! \name Inspectors |
135 | | //@{ |
136 | | Size rows() const; |
137 | | Size columns() const; |
138 | | bool empty() const; |
139 | | Size size1() const; |
140 | | Size size2() const; |
141 | | //@} |
142 | | |
143 | | //! \name Utilities |
144 | | //@{ |
145 | | void swap(Matrix&) noexcept; |
146 | | //@} |
147 | | private: |
148 | | std::unique_ptr<Real[]> data_; |
149 | | Size rows_ = 0, columns_ = 0; |
150 | | }; |
151 | | |
152 | | // algebraic operators |
153 | | |
154 | | /*! \relates Matrix */ |
155 | | Matrix operator+(const Matrix&, const Matrix&); |
156 | | /*! \relates Matrix */ |
157 | | Matrix operator+(const Matrix&, Matrix&&); |
158 | | /*! \relates Matrix */ |
159 | | Matrix operator+(Matrix&&, const Matrix&); |
160 | | /*! \relates Matrix */ |
161 | | Matrix operator+(Matrix&&, Matrix&&); |
162 | | /*! \relates Matrix */ |
163 | | Matrix operator-(const Matrix&); |
164 | | /*! \relates Matrix */ |
165 | | Matrix operator-(Matrix&&); |
166 | | /*! \relates Matrix */ |
167 | | Matrix operator-(const Matrix&, const Matrix&); |
168 | | /*! \relates Matrix */ |
169 | | Matrix operator-(const Matrix&, Matrix&&); |
170 | | /*! \relates Matrix */ |
171 | | Matrix operator-(Matrix&&, const Matrix&); |
172 | | /*! \relates Matrix */ |
173 | | Matrix operator-(Matrix&&, Matrix&&); |
174 | | /*! \relates Matrix */ |
175 | | Matrix operator*(const Matrix&, Real); |
176 | | /*! \relates Matrix */ |
177 | | Matrix operator*(Matrix&&, Real); |
178 | | /*! \relates Matrix */ |
179 | | Matrix operator*(Real, const Matrix&); |
180 | | /*! \relates Matrix */ |
181 | | Matrix operator*(Real, Matrix&&); |
182 | | /*! \relates Matrix */ |
183 | | Matrix operator/(const Matrix&, Real); |
184 | | /*! \relates Matrix */ |
185 | | Matrix operator/(Matrix&&, Real); |
186 | | |
187 | | // vectorial products |
188 | | |
189 | | /*! \relates Matrix */ |
190 | | Array operator*(const Array&, const Matrix&); |
191 | | /*! \relates Matrix */ |
192 | | Array operator*(const Matrix&, const Array&); |
193 | | /*! \relates Matrix */ |
194 | | Matrix operator*(const Matrix&, const Matrix&); |
195 | | |
196 | | // misc. operations |
197 | | |
198 | | /*! \relates Matrix */ |
199 | | Matrix transpose(const Matrix&); |
200 | | |
201 | | /*! \relates Matrix */ |
202 | | Matrix outerProduct(const Array& v1, const Array& v2); |
203 | | |
204 | | /*! \relates Matrix */ |
205 | | template <class Iterator1, class Iterator2> |
206 | | Matrix outerProduct(Iterator1 v1begin, Iterator1 v1end, Iterator2 v2begin, Iterator2 v2end); |
207 | | |
208 | | /*! \relates Matrix */ |
209 | | void swap(Matrix&, Matrix&) noexcept; |
210 | | |
211 | | /*! \relates Matrix */ |
212 | | std::ostream& operator<<(std::ostream&, const Matrix&); |
213 | | |
214 | | /*! \relates Matrix */ |
215 | | Matrix inverse(const Matrix& m); |
216 | | |
217 | | /*! \relates Matrix */ |
218 | | Real determinant(const Matrix& m); |
219 | | |
220 | | // inline definitions |
221 | | |
222 | 0 | inline Matrix::Matrix() : data_((Real*)nullptr) {} |
223 | | |
224 | | inline Matrix::Matrix(Size rows, Size columns) |
225 | 0 | : data_(rows * columns > 0 ? new Real[rows * columns] : (Real*)nullptr), rows_(rows), |
226 | 0 | columns_(columns) {} |
227 | | |
228 | | inline Matrix::Matrix(Size rows, Size columns, Real value) |
229 | 0 | : data_(rows * columns > 0 ? new Real[rows * columns] : (Real*)nullptr), rows_(rows), |
230 | 0 | columns_(columns) { |
231 | 0 | std::fill(begin(),end(),value); |
232 | 0 | } |
233 | | |
234 | | template <class Iterator> |
235 | | inline Matrix::Matrix(Size rows, Size columns, Iterator begin, Iterator end) |
236 | | : data_(rows * columns > 0 ? new Real[rows * columns] : (Real*)nullptr), rows_(rows), |
237 | | columns_(columns) { |
238 | | std::copy(begin, end, this->begin()); |
239 | | } |
240 | | |
241 | | inline Matrix::Matrix(const Matrix& from) |
242 | 0 | : data_(!from.empty() ? new Real[from.rows_ * from.columns_] : (Real*)nullptr), |
243 | 0 | rows_(from.rows_), columns_(from.columns_) { |
244 | | #if defined(QL_PATCH_MSVC) && defined(QL_DEBUG) |
245 | | if (!from.empty()) |
246 | | #endif |
247 | 0 | std::copy(from.begin(),from.end(),begin()); |
248 | 0 | } |
249 | | |
250 | | inline Matrix::Matrix(Matrix&& from) noexcept |
251 | 0 | : data_((Real*)nullptr) { |
252 | 0 | swap(from); |
253 | 0 | } |
254 | | |
255 | | inline Matrix::Matrix(std::initializer_list<std::initializer_list<Real>> data) |
256 | | : data_(data.size() == 0 || data.begin()->size() == 0 ? |
257 | | (Real*)nullptr : new Real[data.size() * data.begin()->size()]), |
258 | | rows_(data.size()), columns_(data.size() == 0 ? 0 : data.begin()->size()) { |
259 | | Size i=0; |
260 | | for (const auto& row : data) { |
261 | | #if defined(QL_EXTRA_SAFETY_CHECKS) |
262 | | QL_REQUIRE(row.size() == columns_, |
263 | | "a matrix needs the same number of elements for each row"); |
264 | | #endif |
265 | | std::copy(row.begin(), row.end(), row_begin(i)); |
266 | | ++i; |
267 | | } |
268 | | } |
269 | | |
270 | 0 | inline Matrix& Matrix::operator=(const Matrix& from) { |
271 | 0 | // strong guarantee |
272 | 0 | Matrix temp(from); |
273 | 0 | swap(temp); |
274 | 0 | return *this; |
275 | 0 | } |
276 | | |
277 | 0 | inline Matrix& Matrix::operator=(Matrix&& from) noexcept { |
278 | 0 | swap(from); |
279 | 0 | return *this; |
280 | 0 | } |
281 | | |
282 | 0 | inline bool Matrix::operator==(const Matrix& to) const { |
283 | 0 | return rows_ == to.rows_ && columns_ == to.columns_ && |
284 | 0 | std::equal(begin(), end(), to.begin()); |
285 | 0 | } |
286 | | |
287 | 0 | inline bool Matrix::operator!=(const Matrix& to) const { |
288 | 0 | return !this->operator==(to); |
289 | 0 | } |
290 | | |
291 | 0 | inline void Matrix::swap(Matrix& from) noexcept { |
292 | 0 | data_.swap(from.data_); |
293 | 0 | std::swap(rows_, from.rows_); |
294 | 0 | std::swap(columns_, from.columns_); |
295 | 0 | } |
296 | | |
297 | 0 | inline const Matrix& Matrix::operator+=(const Matrix& m) { |
298 | 0 | QL_REQUIRE(rows_ == m.rows_ && columns_ == m.columns_, |
299 | 0 | "matrices with different sizes (" << |
300 | 0 | m.rows_ << "x" << m.columns_ << ", " << |
301 | 0 | rows_ << "x" << columns_ << ") cannot be " |
302 | 0 | "added"); |
303 | 0 | std::transform(begin(), end(), m.begin(), begin(), std::plus<>()); |
304 | 0 | return *this; |
305 | 0 | } Unexecuted instantiation: QuantLib::Matrix::operator+=(QuantLib::Matrix const&) Unexecuted instantiation: QuantLib::Matrix::operator+=(QuantLib::Matrix const&) |
306 | | |
307 | 0 | inline const Matrix& Matrix::operator-=(const Matrix& m) { |
308 | 0 | QL_REQUIRE(rows_ == m.rows_ && columns_ == m.columns_, |
309 | 0 | "matrices with different sizes (" << |
310 | 0 | m.rows_ << "x" << m.columns_ << ", " << |
311 | 0 | rows_ << "x" << columns_ << ") cannot be " |
312 | 0 | "subtracted"); |
313 | 0 | std::transform(begin(), end(), m.begin(), begin(), std::minus<>()); |
314 | 0 | return *this; |
315 | 0 | } Unexecuted instantiation: QuantLib::Matrix::operator-=(QuantLib::Matrix const&) Unexecuted instantiation: QuantLib::Matrix::operator-=(QuantLib::Matrix const&) |
316 | | |
317 | 0 | inline const Matrix& Matrix::operator*=(Real x) { |
318 | 0 | std::transform(begin(), end(), begin(), [=](Real y) -> Real { return y * x; }); |
319 | 0 | return *this; |
320 | 0 | } |
321 | | |
322 | 0 | inline const Matrix& Matrix::operator/=(Real x) { |
323 | 0 | std::transform(begin(),end(),begin(), [=](Real y) -> Real { return y / x; }); |
324 | 0 | return *this; |
325 | 0 | } |
326 | | |
327 | 0 | inline Matrix::const_iterator Matrix::begin() const { |
328 | 0 | return data_.get(); |
329 | 0 | } |
330 | | |
331 | 0 | inline Matrix::iterator Matrix::begin() { |
332 | 0 | return data_.get(); |
333 | 0 | } |
334 | | |
335 | 0 | inline Matrix::const_iterator Matrix::end() const { |
336 | 0 | return data_.get()+rows_*columns_; |
337 | 0 | } |
338 | | |
339 | 0 | inline Matrix::iterator Matrix::end() { |
340 | 0 | return data_.get()+rows_*columns_; |
341 | 0 | } |
342 | | |
343 | 0 | inline Matrix::const_reverse_iterator Matrix::rbegin() const { |
344 | 0 | return const_reverse_iterator(end()); |
345 | 0 | } |
346 | | |
347 | 0 | inline Matrix::reverse_iterator Matrix::rbegin() { |
348 | 0 | return reverse_iterator(end()); |
349 | 0 | } |
350 | | |
351 | 0 | inline Matrix::const_reverse_iterator Matrix::rend() const { |
352 | 0 | return const_reverse_iterator(begin()); |
353 | 0 | } |
354 | | |
355 | 0 | inline Matrix::reverse_iterator Matrix::rend() { |
356 | 0 | return reverse_iterator(begin()); |
357 | 0 | } |
358 | | |
359 | | inline Matrix::const_row_iterator |
360 | 0 | Matrix::row_begin(Size i) const { |
361 | 0 | #if defined(QL_EXTRA_SAFETY_CHECKS) |
362 | 0 | QL_REQUIRE(i<rows_, |
363 | 0 | "row index (" << i << ") must be less than " << rows_ << |
364 | 0 | ": matrix cannot be accessed out of range"); |
365 | 0 | #endif |
366 | 0 | return data_.get()+columns_*i; |
367 | 0 | } |
368 | | |
369 | 0 | inline Matrix::row_iterator Matrix::row_begin(Size i) { |
370 | 0 | #if defined(QL_EXTRA_SAFETY_CHECKS) |
371 | 0 | QL_REQUIRE(i<rows_, |
372 | 0 | "row index (" << i << ") must be less than " << rows_ << |
373 | 0 | ": matrix cannot be accessed out of range"); |
374 | 0 | #endif |
375 | 0 | return data_.get()+columns_*i; |
376 | 0 | } |
377 | | |
378 | 0 | inline Matrix::const_row_iterator Matrix::row_end(Size i) const{ |
379 | 0 | #if defined(QL_EXTRA_SAFETY_CHECKS) |
380 | 0 | QL_REQUIRE(i<rows_, |
381 | 0 | "row index (" << i << ") must be less than " << rows_ << |
382 | 0 | ": matrix cannot be accessed out of range"); |
383 | 0 | #endif |
384 | 0 | return data_.get()+columns_*(i+1); |
385 | 0 | } |
386 | | |
387 | 0 | inline Matrix::row_iterator Matrix::row_end(Size i) { |
388 | 0 | #if defined(QL_EXTRA_SAFETY_CHECKS) |
389 | 0 | QL_REQUIRE(i<rows_, |
390 | 0 | "row index (" << i << ") must be less than " << rows_ << |
391 | 0 | ": matrix cannot be accessed out of range"); |
392 | 0 | #endif |
393 | 0 | return data_.get()+columns_*(i+1); |
394 | 0 | } |
395 | | |
396 | | inline Matrix::const_reverse_row_iterator |
397 | 0 | Matrix::row_rbegin(Size i) const { |
398 | 0 | return const_reverse_row_iterator(row_end(i)); |
399 | 0 | } |
400 | | |
401 | 0 | inline Matrix::reverse_row_iterator Matrix::row_rbegin(Size i) { |
402 | 0 | return reverse_row_iterator(row_end(i)); |
403 | 0 | } |
404 | | |
405 | | inline Matrix::const_reverse_row_iterator |
406 | 0 | Matrix::row_rend(Size i) const { |
407 | 0 | return const_reverse_row_iterator(row_begin(i)); |
408 | 0 | } |
409 | | |
410 | 0 | inline Matrix::reverse_row_iterator Matrix::row_rend(Size i) { |
411 | 0 | return reverse_row_iterator(row_begin(i)); |
412 | 0 | } |
413 | | |
414 | | inline Matrix::const_column_iterator |
415 | 0 | Matrix::column_begin(Size i) const { |
416 | 0 | #if defined(QL_EXTRA_SAFETY_CHECKS) |
417 | 0 | QL_REQUIRE(i<columns_, |
418 | 0 | "column index (" << i << ") must be less than " << columns_ << |
419 | 0 | ": matrix cannot be accessed out of range"); |
420 | 0 | #endif |
421 | 0 | return const_column_iterator(data_.get()+i,columns_); |
422 | 0 | } |
423 | | |
424 | 0 | inline Matrix::column_iterator Matrix::column_begin(Size i) { |
425 | 0 | #if defined(QL_EXTRA_SAFETY_CHECKS) |
426 | 0 | QL_REQUIRE(i<columns_, |
427 | 0 | "column index (" << i << ") must be less than " << columns_ << |
428 | 0 | ": matrix cannot be accessed out of range"); |
429 | 0 | #endif |
430 | 0 | return column_iterator(data_.get()+i,columns_); |
431 | 0 | } |
432 | | |
433 | | inline Matrix::const_column_iterator |
434 | 0 | Matrix::column_end(Size i) const { |
435 | 0 | #if defined(QL_EXTRA_SAFETY_CHECKS) |
436 | 0 | QL_REQUIRE(i<columns_, |
437 | 0 | "column index (" << i << ") must be less than " << columns_ << |
438 | 0 | ": matrix cannot be accessed out of range"); |
439 | 0 | #endif |
440 | 0 | return const_column_iterator(data_.get()+i+rows_*columns_,columns_); |
441 | 0 | } |
442 | | |
443 | 0 | inline Matrix::column_iterator Matrix::column_end(Size i) { |
444 | 0 | #if defined(QL_EXTRA_SAFETY_CHECKS) |
445 | 0 | QL_REQUIRE(i<columns_, |
446 | 0 | "column index (" << i << ") must be less than " << columns_ << |
447 | 0 | ": matrix cannot be accessed out of range"); |
448 | 0 | #endif |
449 | 0 | return column_iterator(data_.get()+i+rows_*columns_,columns_); |
450 | 0 | } |
451 | | |
452 | | inline Matrix::const_reverse_column_iterator |
453 | 0 | Matrix::column_rbegin(Size i) const { |
454 | 0 | return const_reverse_column_iterator(column_end(i)); |
455 | 0 | } |
456 | | |
457 | | inline Matrix::reverse_column_iterator |
458 | 0 | Matrix::column_rbegin(Size i) { |
459 | 0 | return reverse_column_iterator(column_end(i)); |
460 | 0 | } |
461 | | |
462 | | inline Matrix::const_reverse_column_iterator |
463 | 0 | Matrix::column_rend(Size i) const { |
464 | 0 | return const_reverse_column_iterator(column_begin(i)); |
465 | 0 | } |
466 | | |
467 | | inline Matrix::reverse_column_iterator |
468 | 0 | Matrix::column_rend(Size i) { |
469 | 0 | return reverse_column_iterator(column_begin(i)); |
470 | 0 | } |
471 | | |
472 | | inline Matrix::const_row_iterator |
473 | 0 | Matrix::operator[](Size i) const { |
474 | 0 | return row_begin(i); |
475 | 0 | } |
476 | | |
477 | | inline Matrix::const_row_iterator |
478 | 0 | Matrix::at(Size i) const { |
479 | 0 | QL_REQUIRE(i < rows_, "matrix access out of range"); |
480 | 0 | return row_begin(i); |
481 | 0 | } |
482 | | |
483 | 0 | inline Matrix::row_iterator Matrix::operator[](Size i) { |
484 | 0 | return row_begin(i); |
485 | 0 | } |
486 | | |
487 | 0 | inline Matrix::row_iterator Matrix::at(Size i) { |
488 | 0 | QL_REQUIRE(i < rows_, "matrix access out of range"); |
489 | 0 | return row_begin(i); |
490 | 0 | } |
491 | | |
492 | 0 | inline Array Matrix::diagonal() const { |
493 | 0 | Size arraySize = std::min<Size>(rows(), columns()); |
494 | 0 | Array tmp(arraySize); |
495 | 0 | for(Size i = 0; i < arraySize; i++) |
496 | 0 | tmp[i] = (*this)[i][i]; |
497 | 0 | return tmp; |
498 | 0 | } |
499 | | |
500 | 0 | inline Real &Matrix::operator()(Size i, Size j) const { |
501 | 0 | return data_[i*columns()+j]; |
502 | 0 | } |
503 | | |
504 | 0 | inline Size Matrix::rows() const { |
505 | 0 | return rows_; |
506 | 0 | } |
507 | | |
508 | 0 | inline Size Matrix::columns() const { |
509 | 0 | return columns_; |
510 | 0 | } |
511 | | |
512 | 0 | inline Size Matrix::size1() const { |
513 | 0 | return rows(); |
514 | 0 | } |
515 | | |
516 | 0 | inline Size Matrix::size2() const { |
517 | 0 | return columns(); |
518 | 0 | } |
519 | | |
520 | 0 | inline bool Matrix::empty() const { |
521 | 0 | return rows_ == 0 || columns_ == 0; |
522 | 0 | } |
523 | | |
524 | 0 | inline Matrix operator+(const Matrix& m1, const Matrix& m2) { |
525 | 0 | QL_REQUIRE(m1.rows() == m2.rows() && |
526 | 0 | m1.columns() == m2.columns(), |
527 | 0 | "matrices with different sizes (" << |
528 | 0 | m1.rows() << "x" << m1.columns() << ", " << |
529 | 0 | m2.rows() << "x" << m2.columns() << ") cannot be " |
530 | 0 | "added"); |
531 | 0 | Matrix temp(m1.rows(),m1.columns()); |
532 | 0 | std::transform(m1.begin(), m1.end(), m2.begin(), temp.begin(), std::plus<>()); |
533 | 0 | return temp; |
534 | 0 | } Unexecuted instantiation: QuantLib::operator+(QuantLib::Matrix const&, QuantLib::Matrix const&) Unexecuted instantiation: QuantLib::operator+(QuantLib::Matrix const&, QuantLib::Matrix const&) |
535 | | |
536 | 0 | inline Matrix operator+(const Matrix& m1, Matrix&& m2) { |
537 | 0 | QL_REQUIRE(m1.rows() == m2.rows() && |
538 | 0 | m1.columns() == m2.columns(), |
539 | 0 | "matrices with different sizes (" << |
540 | 0 | m1.rows() << "x" << m1.columns() << ", " << |
541 | 0 | m2.rows() << "x" << m2.columns() << ") cannot be " |
542 | 0 | "added"); |
543 | 0 | std::transform(m1.begin(), m1.end(), m2.begin(), m2.begin(), std::plus<>()); |
544 | 0 | return std::move(m2); |
545 | 0 | } Unexecuted instantiation: QuantLib::operator+(QuantLib::Matrix const&, QuantLib::Matrix&&) Unexecuted instantiation: QuantLib::operator+(QuantLib::Matrix const&, QuantLib::Matrix&&) |
546 | | |
547 | 0 | inline Matrix operator+(Matrix&& m1, const Matrix& m2) { |
548 | 0 | QL_REQUIRE(m1.rows() == m2.rows() && |
549 | 0 | m1.columns() == m2.columns(), |
550 | 0 | "matrices with different sizes (" << |
551 | 0 | m1.rows() << "x" << m1.columns() << ", " << |
552 | 0 | m2.rows() << "x" << m2.columns() << ") cannot be " |
553 | 0 | "added"); |
554 | 0 | std::transform(m1.begin(), m1.end(), m2.begin(), m1.begin(), std::plus<>()); |
555 | 0 | return std::move(m1); |
556 | 0 | } |
557 | | |
558 | 0 | inline Matrix operator+(Matrix&& m1, Matrix&& m2) { // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved) |
559 | 0 | QL_REQUIRE(m1.rows() == m2.rows() && |
560 | 0 | m1.columns() == m2.columns(), |
561 | 0 | "matrices with different sizes (" << |
562 | 0 | m1.rows() << "x" << m1.columns() << ", " << |
563 | 0 | m2.rows() << "x" << m2.columns() << ") cannot be " |
564 | 0 | "added"); |
565 | 0 | std::transform(m1.begin(), m1.end(), m2.begin(), m1.begin(), std::plus<>()); |
566 | 0 | return std::move(m1); |
567 | 0 | } |
568 | | |
569 | 0 | inline Matrix operator-(const Matrix& m1) { |
570 | 0 | Matrix temp(m1.rows(), m1.columns()); |
571 | 0 | std::transform(m1.begin(), m1.end(), temp.begin(), std::negate<>()); |
572 | 0 | return temp; |
573 | 0 | } |
574 | | |
575 | 0 | inline Matrix operator-(Matrix&& m1) { |
576 | 0 | std::transform(m1.begin(), m1.end(), m1.begin(), std::negate<>()); |
577 | 0 | return std::move(m1); |
578 | 0 | } |
579 | | |
580 | 0 | inline Matrix operator-(const Matrix& m1, const Matrix& m2) { |
581 | 0 | QL_REQUIRE(m1.rows() == m2.rows() && |
582 | 0 | m1.columns() == m2.columns(), |
583 | 0 | "matrices with different sizes (" << |
584 | 0 | m1.rows() << "x" << m1.columns() << ", " << |
585 | 0 | m2.rows() << "x" << m2.columns() << ") cannot be " |
586 | 0 | "subtracted"); |
587 | 0 | Matrix temp(m1.rows(),m1.columns()); |
588 | 0 | std::transform(m1.begin(), m1.end(), m2.begin(), temp.begin(), std::minus<>()); |
589 | 0 | return temp; |
590 | 0 | } Unexecuted instantiation: QuantLib::operator-(QuantLib::Matrix const&, QuantLib::Matrix const&) Unexecuted instantiation: QuantLib::operator-(QuantLib::Matrix const&, QuantLib::Matrix const&) |
591 | | |
592 | 0 | inline Matrix operator-(const Matrix& m1, Matrix&& m2) { |
593 | 0 | QL_REQUIRE(m1.rows() == m2.rows() && |
594 | 0 | m1.columns() == m2.columns(), |
595 | 0 | "matrices with different sizes (" << |
596 | 0 | m1.rows() << "x" << m1.columns() << ", " << |
597 | 0 | m2.rows() << "x" << m2.columns() << ") cannot be " |
598 | 0 | "subtracted"); |
599 | 0 | std::transform(m1.begin(), m1.end(), m2.begin(), m2.begin(), std::minus<>()); |
600 | 0 | return std::move(m2); |
601 | 0 | } Unexecuted instantiation: QuantLib::operator-(QuantLib::Matrix const&, QuantLib::Matrix&&) Unexecuted instantiation: QuantLib::operator-(QuantLib::Matrix const&, QuantLib::Matrix&&) |
602 | | |
603 | 0 | inline Matrix operator-(Matrix&& m1, const Matrix& m2) { |
604 | 0 | QL_REQUIRE(m1.rows() == m2.rows() && |
605 | 0 | m1.columns() == m2.columns(), |
606 | 0 | "matrices with different sizes (" << |
607 | 0 | m1.rows() << "x" << m1.columns() << ", " << |
608 | 0 | m2.rows() << "x" << m2.columns() << ") cannot be " |
609 | 0 | "subtracted"); |
610 | 0 | std::transform(m1.begin(), m1.end(), m2.begin(), m1.begin(), std::minus<>()); |
611 | 0 | return std::move(m1); |
612 | 0 | } Unexecuted instantiation: QuantLib::operator-(QuantLib::Matrix&&, QuantLib::Matrix const&) Unexecuted instantiation: QuantLib::operator-(QuantLib::Matrix&&, QuantLib::Matrix const&) |
613 | | |
614 | 0 | inline Matrix operator-(Matrix&& m1, Matrix&& m2) { // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved) |
615 | 0 | QL_REQUIRE(m1.rows() == m2.rows() && |
616 | 0 | m1.columns() == m2.columns(), |
617 | 0 | "matrices with different sizes (" << |
618 | 0 | m1.rows() << "x" << m1.columns() << ", " << |
619 | 0 | m2.rows() << "x" << m2.columns() << ") cannot be " |
620 | 0 | "subtracted"); |
621 | 0 | std::transform(m1.begin(), m1.end(), m2.begin(), m1.begin(), std::minus<>()); |
622 | 0 | return std::move(m1); |
623 | 0 | } |
624 | | |
625 | 0 | inline Matrix operator*(const Matrix& m, Real x) { |
626 | 0 | Matrix temp(m.rows(),m.columns()); |
627 | 0 | std::transform(m.begin(), m.end(), temp.begin(), [=](Real y) -> Real { return y * x; }); |
628 | 0 | return temp; |
629 | 0 | } |
630 | | |
631 | 0 | inline Matrix operator*(Matrix&& m, Real x) { |
632 | 0 | std::transform(m.begin(), m.end(), m.begin(), [=](Real y) -> Real { return y * x; }); |
633 | 0 | return std::move(m); |
634 | 0 | } |
635 | | |
636 | 0 | inline Matrix operator*(Real x, const Matrix& m) { |
637 | 0 | Matrix temp(m.rows(),m.columns()); |
638 | 0 | std::transform(m.begin(), m.end(), temp.begin(), [=](Real y) -> Real { return x * y; }); |
639 | 0 | return temp; |
640 | 0 | } |
641 | | |
642 | 0 | inline Matrix operator*(Real x, Matrix&& m) { |
643 | 0 | std::transform(m.begin(), m.end(), m.begin(), [=](Real y) -> Real { return x * y; }); |
644 | 0 | return std::move(m); |
645 | 0 | } |
646 | | |
647 | 0 | inline Matrix operator/(const Matrix& m, Real x) { |
648 | 0 | Matrix temp(m.rows(),m.columns()); |
649 | 0 | std::transform(m.begin(), m.end(), temp.begin(), [=](Real y) -> Real { return y / x; }); |
650 | 0 | return temp; |
651 | 0 | } |
652 | | |
653 | 0 | inline Matrix operator/(Matrix&& m, Real x) { |
654 | 0 | std::transform(m.begin(), m.end(), m.begin(), [=](Real y) -> Real { return y / x; }); |
655 | 0 | return std::move(m); |
656 | 0 | } |
657 | | |
658 | 0 | inline Array operator*(const Array& v, const Matrix& m) { |
659 | 0 | QL_REQUIRE(v.size() == m.rows(), |
660 | 0 | "vectors and matrices with different sizes (" |
661 | 0 | << v.size() << ", " << m.rows() << "x" << m.columns() << |
662 | 0 | ") cannot be multiplied"); |
663 | 0 | Array result(m.columns()); |
664 | 0 | for (Size i=0; i<result.size(); i++) |
665 | 0 | result[i] = |
666 | 0 | std::inner_product(v.begin(),v.end(), |
667 | 0 | m.column_begin(i),Real(0.0)); |
668 | 0 | return result; |
669 | 0 | } |
670 | | |
671 | 0 | inline Array operator*(const Matrix& m, const Array& v) { |
672 | 0 | QL_REQUIRE(v.size() == m.columns(), |
673 | 0 | "vectors and matrices with different sizes (" |
674 | 0 | << v.size() << ", " << m.rows() << "x" << m.columns() << |
675 | 0 | ") cannot be multiplied"); |
676 | 0 | Array result(m.rows()); |
677 | 0 | for (Size i=0; i<result.size(); i++) |
678 | 0 | result[i] = |
679 | 0 | std::inner_product(v.begin(),v.end(),m.row_begin(i),Real(0.0)); |
680 | 0 | return result; |
681 | 0 | } Unexecuted instantiation: QuantLib::operator*(QuantLib::Matrix const&, QuantLib::Array const&) Unexecuted instantiation: QuantLib::operator*(QuantLib::Matrix const&, QuantLib::Array const&) |
682 | | |
683 | 0 | inline Matrix operator*(const Matrix& m1, const Matrix& m2) { |
684 | 0 | QL_REQUIRE(m1.columns() == m2.rows(), |
685 | 0 | "matrices with different sizes (" << |
686 | 0 | m1.rows() << "x" << m1.columns() << ", " << |
687 | 0 | m2.rows() << "x" << m2.columns() << ") cannot be " |
688 | 0 | "multiplied"); |
689 | 0 | Matrix result(m1.rows(),m2.columns(),0.0); |
690 | 0 | for (Size i=0; i<result.rows(); ++i) { |
691 | 0 | for (Size k=0; k<m1.columns(); ++k) { |
692 | 0 | for (Size j=0; j<result.columns(); ++j) { |
693 | 0 | result[i][j] += m1[i][k]*m2[k][j]; |
694 | 0 | } |
695 | 0 | } |
696 | 0 | } |
697 | 0 | return result; |
698 | 0 | } Unexecuted instantiation: QuantLib::operator*(QuantLib::Matrix const&, QuantLib::Matrix const&) Unexecuted instantiation: QuantLib::operator*(QuantLib::Matrix const&, QuantLib::Matrix const&) |
699 | | |
700 | 0 | inline Matrix transpose(const Matrix& m) { |
701 | 0 | Matrix result(m.columns(),m.rows()); |
702 | 0 | #if defined(QL_PATCH_MSVC) && defined(QL_DEBUG) |
703 | 0 | if (!m.empty()) |
704 | 0 | #endif |
705 | 0 | for (Size i=0; i<m.rows(); i++) |
706 | 0 | std::copy(m.row_begin(i),m.row_end(i),result.column_begin(i)); |
707 | 0 | return result; |
708 | 0 | } |
709 | | |
710 | 0 | inline Matrix outerProduct(const Array& v1, const Array& v2) { |
711 | 0 | return outerProduct(v1.begin(), v1.end(), v2.begin(), v2.end()); |
712 | 0 | } |
713 | | |
714 | | template <class Iterator1, class Iterator2> |
715 | 0 | inline Matrix outerProduct(Iterator1 v1begin, Iterator1 v1end, Iterator2 v2begin, Iterator2 v2end) { |
716 | |
|
717 | 0 | Size size1 = std::distance(v1begin, v1end); |
718 | 0 | QL_REQUIRE(size1>0, "null first vector"); |
719 | | |
720 | 0 | Size size2 = std::distance(v2begin, v2end); |
721 | 0 | QL_REQUIRE(size2>0, "null second vector"); |
722 | | |
723 | 0 | Matrix result(size1, size2); |
724 | |
|
725 | 0 | for (Size i=0; v1begin!=v1end; i++, v1begin++) |
726 | 0 | std::transform(v2begin, v2end, result.row_begin(i), |
727 | 0 | [=](Real y) -> Real { return y * (*v1begin); }); Unexecuted instantiation: QuantLib::outerProduct<std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double const*> >(std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double const*>)::{lambda(double)#1}::operator()(double) const Unexecuted instantiation: QuantLib::outerProduct<std::__1::__wrap_iter<double*>, std::__1::__wrap_iter<double*> >(std::__1::__wrap_iter<double*>, std::__1::__wrap_iter<double*>, std::__1::__wrap_iter<double*>, std::__1::__wrap_iter<double*>)::{lambda(double)#1}::operator()(double) const |
728 | |
|
729 | 0 | return result; |
730 | 0 | } Unexecuted instantiation: QuantLib::Matrix QuantLib::outerProduct<double const*, double const*>(double const*, double const*, double const*, double const*) Unexecuted instantiation: QuantLib::Matrix QuantLib::outerProduct<std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double const*> >(std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double const*>) Unexecuted instantiation: QuantLib::Matrix QuantLib::outerProduct<std::__1::__wrap_iter<double*>, std::__1::__wrap_iter<double*> >(std::__1::__wrap_iter<double*>, std::__1::__wrap_iter<double*>, std::__1::__wrap_iter<double*>, std::__1::__wrap_iter<double*>) |
731 | | |
732 | 0 | inline void swap(Matrix& m1, Matrix& m2) noexcept { |
733 | 0 | m1.swap(m2); |
734 | 0 | } |
735 | | |
736 | 0 | inline std::ostream& operator<<(std::ostream& out, const Matrix& m) { |
737 | 0 | std::streamsize width = out.width(); |
738 | 0 | for (Size i=0; i<m.rows(); i++) { |
739 | 0 | out << "| "; |
740 | 0 | for (Size j=0; j<m.columns(); j++) |
741 | 0 | out << std::setw(int(width)) << m[i][j] << " "; |
742 | 0 | out << "|\n"; |
743 | 0 | } |
744 | 0 | return out; |
745 | 0 | } |
746 | | |
747 | | } |
748 | | |
749 | | |
750 | | #endif |