Coverage Report

Created: 2025-08-28 06:30

/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