QuantLib: a free/open-source library for quantitative finance
fully annotated source code - version 1.38
Loading...
Searching...
No Matches
svd.cpp
Go to the documentation of this file.
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2003 Neil Firth
5
6 This file is part of QuantLib, a free-software/open-source library
7 for financial quantitative analysts and developers - http://quantlib.org/
8
9 QuantLib is free software: you can redistribute it and/or modify it
10 under the terms of the QuantLib license. You should have received a
11 copy of the license along with this program; if not, please email
12 <quantlib-dev@lists.sf.net>. The license is also available online at
13 <http://quantlib.org/license.shtml>.
14
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the license for more details.
18
19 Adapted from the TNT project
20 http://math.nist.gov/tnt/download.html
21
22 This software was developed at the National Institute of Standards
23 and Technology (NIST) by employees of the Federal Government in the
24 course of their official duties. Pursuant to title 17 Section 105
25 of the United States Code this software is not subject to copyright
26 protection and is in the public domain. NIST assumes no responsibility
27 whatsoever for its use by other parties, and makes no guarantees,
28 expressed or implied, about its quality, reliability, or any other
29 characteristic.
30
31 We would appreciate acknowledgement if the software is incorporated in
32 redistributable libraries or applications.
33*/
34
35
36#include <algorithm>
38
39namespace QuantLib {
40
41 namespace {
42
43 /* returns hypotenuse of real (non-complex) scalars a and b by
44 avoiding underflow/overflow
45 using (a * sqrt( 1 + (b/a) * (b/a))), rather than
46 sqrt(a*a + b*b).
47 */
48 Real hypot(const Real &a, const Real &b) {
49 if (a == 0) {
50 return std::fabs(b);
51 } else {
52 Real c = b/a;
53 return std::fabs(a) * std::sqrt(1 + c*c);
54 }
55 }
56
57 }
58
59
60 SVD::SVD(const Matrix& M) {
61
62 using std::swap;
63
64 Matrix A;
65
66 /* The implementation requires that rows > columns.
67 If this is not the case, we decompose M^T instead.
68 Swapping the resulting U and V gives the desired
69 result for M as
70
71 M^T = U S V^T (decomposition of M^T)
72
73 M = (U S V^T)^T (transpose)
74
75 M = (V^T^T S^T U^T) ((AB)^T = B^T A^T)
76
77 M = V S U^T (idempotence of transposition,
78 symmetry of diagonal matrix S)
79
80 */
81
82 if (M.rows() >= M.columns()) {
83 A = M;
84 transpose_ = false;
85 } else {
86 A = transpose(M);
87 transpose_ = true;
88 }
89
90 m_ = A.rows();
91 n_ = A.columns();
92
93 // we're sure that m_ >= n_
94
95 s_ = Array(n_);
96 U_ = Matrix(m_,n_, 0.0);
97 V_ = Matrix(n_,n_);
98 Array e(n_);
99 Array work(m_);
100 Integer i, j, k;
101
102 // Reduce A to bidiagonal form, storing the diagonal elements
103 // in s and the super-diagonal elements in e.
104
105 Integer nct = std::min(m_-1,n_);
106 Integer nrt = std::max(0,n_-2);
107 for (k = 0; k < std::max(nct,nrt); k++) {
108 if (k < nct) {
109
110 // Compute the transformation for the k-th column and
111 // place the k-th diagonal in s[k].
112 // Compute 2-norm of k-th column without under/overflow.
113 s_[k] = 0;
114 for (i = k; i < m_; i++) {
115 s_[k] = hypot(s_[k],A[i][k]);
116 }
117 if (s_[k] != 0.0) {
118 if (A[k][k] < 0.0) {
119 s_[k] = -s_[k];
120 }
121 for (i = k; i < m_; i++) {
122 A[i][k] /= s_[k];
123 }
124 A[k][k] += 1.0;
125 }
126 s_[k] = -s_[k];
127 }
128 for (j = k+1; j < n_; j++) {
129 if ((k < nct) && (s_[k] != 0.0)) {
130
131 // Apply the transformation.
132
133 Real t = 0;
134 for (i = k; i < m_; i++) {
135 t += A[i][k]*A[i][j];
136 }
137 t = -t/A[k][k];
138 for (i = k; i < m_; i++) {
139 A[i][j] += t*A[i][k];
140 }
141 }
142
143 // Place the k-th row of A into e for the
144 // subsequent calculation of the row transformation.
145
146 e[j] = A[k][j];
147 }
148 if (k < nct) {
149
150 // Place the transformation in U for subsequent back
151 // multiplication.
152
153 for (i = k; i < m_; i++) {
154 U_[i][k] = A[i][k];
155 }
156 }
157 if (k < nrt) {
158
159 // Compute the k-th row transformation and place the
160 // k-th super-diagonal in e[k].
161 // Compute 2-norm without under/overflow.
162 e[k] = 0;
163 for (i = k+1; i < n_; i++) {
164 e[k] = hypot(e[k],e[i]);
165 }
166 if (e[k] != 0.0) {
167 if (e[k+1] < 0.0) {
168 e[k] = -e[k];
169 }
170 for (i = k+1; i < n_; i++) {
171 e[i] /= e[k];
172 }
173 e[k+1] += 1.0;
174 }
175 e[k] = -e[k];
176 if ((k+1 < m_) && (e[k] != 0.0)) {
177
178 // Apply the transformation.
179
180 for (i = k+1; i < m_; i++) {
181 work[i] = 0.0;
182 }
183 for (j = k+1; j < n_; j++) {
184 for (i = k+1; i < m_; i++) {
185 work[i] += e[j]*A[i][j];
186 }
187 }
188 for (j = k+1; j < n_; j++) {
189 Real t = -e[j]/e[k+1];
190 for (i = k+1; i < m_; i++) {
191 A[i][j] += t*work[i];
192 }
193 }
194 }
195
196 // Place the transformation in V for subsequent
197 // back multiplication.
198
199 for (i = k+1; i < n_; i++) {
200 V_[i][k] = e[i];
201 }
202 }
203 }
204
205 // Set up the final bidiagonal matrix or order n.
206
207 if (nct < n_) {
208 s_[nct] = A[nct][nct];
209 }
210 if (nrt+1 < n_) {
211 e[nrt] = A[nrt][n_-1];
212 }
213 e[n_-1] = 0.0;
214
215 // generate U
216
217 for (j = nct; j < n_; j++) {
218 for (i = 0; i < m_; i++) {
219 U_[i][j] = 0.0;
220 }
221 U_[j][j] = 1.0;
222 }
223 for (k = nct-1; k >= 0; --k) {
224 if (s_[k] != 0.0) {
225 for (j = k+1; j < n_; ++j) {
226 Real t = 0;
227 for (i = k; i < m_; i++) {
228 t += U_[i][k]*U_[i][j];
229 }
230 t = -t/U_[k][k];
231 for (i = k; i < m_; i++) {
232 U_[i][j] += t*U_[i][k];
233 }
234 }
235 for (i = k; i < m_; i++ ) {
236 U_[i][k] = -U_[i][k];
237 }
238 U_[k][k] = 1.0 + U_[k][k];
239 for (i = 0; i < k-1; i++) {
240 U_[i][k] = 0.0;
241 }
242 } else {
243 for (i = 0; i < m_; i++) {
244 U_[i][k] = 0.0;
245 }
246 U_[k][k] = 1.0;
247 }
248 }
249
250 // generate V
251
252 for (k = n_-1; k >= 0; --k) {
253 if ((k < nrt) && (e[k] != 0.0)) {
254 for (j = k+1; j < n_; ++j) {
255 Real t = 0;
256 for (i = k+1; i < n_; i++) {
257 t += V_[i][k]*V_[i][j];
258 }
259 t = -t/V_[k+1][k];
260 for (i = k+1; i < n_; i++) {
261 V_[i][j] += t*V_[i][k];
262 }
263 }
264 }
265 for (i = 0; i < n_; i++) {
266 V_[i][k] = 0.0;
267 }
268 V_[k][k] = 1.0;
269 }
270
271 // Main iteration loop for the singular values.
272
273 Integer p = n_, pp = p-1;
274 Integer iter = 0;
275 Real eps = std::pow(2.0,-52.0);
276 while (p > 0) {
277 Integer k;
278 Integer kase;
279
280 // Here is where a test for too many iterations would go.
281
282 // This section of the program inspects for
283 // negligible elements in the s and e arrays. On
284 // completion the variables kase and k are set as follows.
285
286 // kase = 1 if s(p) and e[k-1] are negligible and k<p
287 // kase = 2 if s(k) is negligible and k<p
288 // kase = 3 if e[k-1] is negligible, k<p, and
289 // s(k), ..., s(p) are not negligible (qr step).
290 // kase = 4 if e(p-1) is negligible (convergence).
291
292 for (k = p-2; k >= -1; --k) {
293 if (k == -1) {
294 break;
295 }
296 if (std::fabs(e[k]) <= eps*(std::fabs(s_[k]) +
297 std::fabs(s_[k+1]))) {
298 e[k] = 0.0;
299 break;
300 }
301 }
302 if (k == p-2) {
303 kase = 4;
304 } else {
305 Integer ks;
306 for (ks = p-1; ks >= k; --ks) {
307 if (ks == k) {
308 break;
309 }
310 Real t = (ks != p ? Real(std::fabs(e[ks])) : 0.) +
311 (ks != k+1 ? Real(std::fabs(e[ks-1])) : 0.);
312 if (std::fabs(s_[ks]) <= eps*t) {
313 s_[ks] = 0.0;
314 break;
315 }
316 }
317 if (ks == k) {
318 kase = 3;
319 } else if (ks == p-1) {
320 kase = 1;
321 } else {
322 kase = 2;
323 k = ks;
324 }
325 }
326 k++;
327
328 // Perform the task indicated by kase.
329
330 switch (kase) { // NOLINT(bugprone-switch-missing-default-case)
331
332 // Deflate negligible s(p).
333
334 case 1: {
335 Real f = e[p-2];
336 e[p-2] = 0.0;
337 for (j = p-2; j >= k; --j) {
338 Real t = hypot(s_[j],f);
339 Real cs = s_[j]/t;
340 Real sn = f/t;
341 s_[j] = t;
342 if (j != k) {
343 f = -sn*e[j-1];
344 e[j-1] = cs*e[j-1];
345 }
346 for (i = 0; i < n_; i++) {
347 t = cs*V_[i][j] + sn*V_[i][p-1];
348 V_[i][p-1] = -sn*V_[i][j] + cs*V_[i][p-1];
349 V_[i][j] = t;
350 }
351 }
352 }
353 break;
354
355 // Split at negligible s(k).
356
357 case 2: {
358 Real f = e[k-1];
359 e[k-1] = 0.0;
360 for (j = k; j < p; j++) {
361 Real t = hypot(s_[j],f);
362 Real cs = s_[j]/t;
363 Real sn = f/t;
364 s_[j] = t;
365 f = -sn*e[j];
366 e[j] = cs*e[j];
367 for (i = 0; i < m_; i++) {
368 t = cs*U_[i][j] + sn*U_[i][k-1];
369 U_[i][k-1] = -sn*U_[i][j] + cs*U_[i][k-1];
370 U_[i][j] = t;
371 }
372 }
373 }
374 break;
375
376 // Perform one qr step.
377
378 case 3: {
379
380 // Calculate the shift.
381 Real scale = std::max({
382 std::fabs(s_[p-1]),
383 std::fabs(s_[p-2]),
384 std::fabs(e[p-2]),
385 std::fabs(s_[k]),
386 std::fabs(e[k])
387 });
388 Real sp = s_[p-1]/scale;
389 Real spm1 = s_[p-2]/scale;
390 Real epm1 = e[p-2]/scale;
391 Real sk = s_[k]/scale;
392 Real ek = e[k]/scale;
393 Real b = ((spm1 + sp)*(spm1 - sp) + epm1*epm1)/2.0;
394 Real c = (sp*epm1)*(sp*epm1);
395 Real shift = 0.0;
396 if ((b != 0.0) || (c != 0.0)) {
397 shift = std::sqrt(b*b + c);
398 if (b < 0.0) {
399 shift = -shift;
400 }
401 shift = c/(b + shift);
402 }
403 Real f = (sk + sp)*(sk - sp) + shift;
404 Real g = sk*ek;
405
406 // Chase zeros.
407
408 for (j = k; j < p-1; j++) {
409 Real t = hypot(f,g);
410 Real cs = f/t;
411 Real sn = g/t;
412 if (j != k) {
413 e[j-1] = t;
414 }
415 f = cs*s_[j] + sn*e[j];
416 e[j] = cs*e[j] - sn*s_[j];
417 g = sn*s_[j+1];
418 s_[j+1] = cs*s_[j+1];
419 for (i = 0; i < n_; i++) {
420 t = cs*V_[i][j] + sn*V_[i][j+1];
421 V_[i][j+1] = -sn*V_[i][j] + cs*V_[i][j+1];
422 V_[i][j] = t;
423 }
424 t = hypot(f,g);
425 cs = f/t;
426 sn = g/t;
427 s_[j] = t;
428 f = cs*e[j] + sn*s_[j+1];
429 s_[j+1] = -sn*e[j] + cs*s_[j+1];
430 g = sn*e[j+1];
431 e[j+1] = cs*e[j+1];
432 if (j < m_-1) {
433 for (i = 0; i < m_; i++) {
434 t = cs*U_[i][j] + sn*U_[i][j+1];
435 U_[i][j+1] = -sn*U_[i][j] + cs*U_[i][j+1];
436 U_[i][j] = t;
437 }
438 }
439 }
440 e[p-2] = f;
441 iter = iter + 1;
442 }
443 break;
444
445 // Convergence.
446
447 case 4: {
448
449 // Make the singular values positive.
450
451 if (s_[k] <= 0.0) {
452 s_[k] = (s_[k] < 0.0 ? Real(-s_[k]) : 0.0);
453 for (i = 0; i <= pp; i++) {
454 V_[i][k] = -V_[i][k];
455 }
456 }
457
458 // Order the singular values.
459
460 while (k < pp) {
461 if (s_[k] >= s_[k+1]) {
462 break;
463 }
464 swap(s_[k], s_[k+1]);
465 if (k < n_-1) {
466 for (i = 0; i < n_; i++) {
467 swap(V_[i][k], V_[i][k+1]);
468 }
469 }
470 if (k < m_-1) {
471 for (i = 0; i < m_; i++) {
472 swap(U_[i][k], U_[i][k+1]);
473 }
474 }
475 k++;
476 }
477 iter = 0;
478 --p;
479 }
480 break;
481 }
482 }
483 }
484
485 const Matrix& SVD::U() const {
486 return (transpose_ ? V_ : U_);
487 }
488
489 const Matrix& SVD::V() const {
490 return (transpose_ ? U_ : V_);
491 }
492
493 const Array& SVD::singularValues() const {
494 return s_;
495 }
496
497 Matrix SVD::S() const {
498 Matrix S(n_,n_);
499 for (Size i = 0; i < Size(n_); i++) {
500 for (Size j = 0; j < Size(n_); j++) {
501 S[i][j] = 0.0;
502 }
503 S[i][i] = s_[i];
504 }
505 return S;
506 }
507
508 Real SVD::norm2() const {
509 return s_[0];
510 }
511
512 Real SVD::cond() const {
513 return s_[0]/s_[n_-1];
514 }
515
516 Size SVD::rank() const {
517 constexpr auto eps = QL_EPSILON;
518 Real tol = m_*s_[0]*eps;
519 Size r = 0;
520 for (Real i : s_) {
521 if (i > tol) {
522 r++;
523 }
524 }
525 return r;
526 }
527
528 Array SVD::solveFor(const Array& b) const{
529 Matrix W(n_, n_, 0.0);
530 const Size numericalRank = this->rank();
531 for (Size i=0; i<numericalRank; i++)
532 W[i][i] = 1./s_[i];
533
534 Matrix inverse = V()* W * transpose(U());
535 return inverse * b;
536 }
537
538}
539
1-D array used in linear algebra.
Definition: array.hpp:52
Matrix used in linear algebra.
Definition: matrix.hpp:41
Size rows() const
Definition: matrix.hpp:504
Size columns() const
Definition: matrix.hpp:508
const Matrix & V() const
Definition: svd.cpp:489
const Array & singularValues() const
Definition: svd.cpp:493
Matrix S() const
Definition: svd.cpp:497
Matrix U_
Definition: svd.hpp:69
const Matrix & U() const
Definition: svd.cpp:485
Array s_
Definition: svd.hpp:70
Real norm2() const
Definition: svd.cpp:508
Array solveFor(const Array &) const
Definition: svd.cpp:528
bool transpose_
Definition: svd.hpp:72
Size rank() const
Definition: svd.cpp:516
Matrix V_
Definition: svd.hpp:69
SVD(const Matrix &)
Definition: svd.cpp:60
Real cond() const
Definition: svd.cpp:512
Integer m_
Definition: svd.hpp:71
Integer n_
Definition: svd.hpp:71
const DefaultType & t
std::function< Real(Real)> b
#define QL_EPSILON
Definition: qldefines.hpp:178
QL_REAL Real
real number
Definition: types.hpp:50
QL_INTEGER Integer
integer number
Definition: types.hpp:35
std::size_t Size
size of a container
Definition: types.hpp:58
Definition: any.hpp:37
void swap(Array &v, Array &w) noexcept
Definition: array.hpp:891
Matrix transpose(const Matrix &m)
Definition: matrix.hpp:700
Matrix inverse(const Matrix &m)
Definition: matrix.cpp:44
ext::shared_ptr< YieldTermStructure > r
singular value decomposition