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