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