1 |
gezelter |
1335 |
/* -*- 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 "math/svd.hpp" |
37 |
|
|
|
38 |
|
|
namespace oopse { |
39 |
|
|
|
40 |
|
|
namespace { |
41 |
|
|
|
42 |
|
|
/* returns hypotenuse of real (non-complex) scalars a and b by |
43 |
|
|
avoiding underflow/overflow |
44 |
|
|
using (a * sqrt( 1 + (b/a) * (b/a))), rather than |
45 |
|
|
sqrt(a*a + b*b). |
46 |
|
|
*/ |
47 |
|
|
Real hypot(const Real &a, const Real &b) { |
48 |
|
|
if (a == 0) { |
49 |
|
|
return std::fabs(b); |
50 |
|
|
} else { |
51 |
|
|
Real c = b/a; |
52 |
|
|
return std::fabs(a) * std::sqrt(1 + c*c); |
53 |
|
|
} |
54 |
|
|
} |
55 |
|
|
|
56 |
|
|
} |
57 |
|
|
|
58 |
|
|
|
59 |
|
|
SVD::SVD(const RectMatrix& M) { |
60 |
|
|
|
61 |
|
|
using std::swap; |
62 |
|
|
|
63 |
|
|
RectMatrix A; |
64 |
|
|
|
65 |
|
|
/* The implementation requires that rows > columns. |
66 |
|
|
If this is not the case, we decompose M^T instead. |
67 |
|
|
Swapping the resulting U and V gives the desired |
68 |
|
|
result for M as |
69 |
|
|
|
70 |
|
|
M^T = U S V^T (decomposition of M^T) |
71 |
|
|
|
72 |
|
|
M = (U S V^T)^T (transpose) |
73 |
|
|
|
74 |
|
|
M = (V^T^T S^T U^T) ((AB)^T = B^T A^T) |
75 |
|
|
|
76 |
|
|
M = V S U^T (idempotence of transposition, |
77 |
|
|
symmetry of diagonal matrix S) |
78 |
|
|
|
79 |
|
|
*/ |
80 |
|
|
|
81 |
|
|
if (M.rows() >= M.columns()) { |
82 |
|
|
A = M; |
83 |
|
|
transpose_ = false; |
84 |
|
|
} else { |
85 |
|
|
A = transpose(M); |
86 |
|
|
transpose_ = true; |
87 |
|
|
} |
88 |
|
|
|
89 |
|
|
m_ = A.rows(); |
90 |
|
|
n_ = A.columns(); |
91 |
|
|
|
92 |
|
|
// we're sure that m_ >= n_ |
93 |
|
|
|
94 |
|
|
s_ = Vector(n_); |
95 |
|
|
U_ = RectMatrix(m_,n_, 0.0); |
96 |
|
|
V_ = RectMatrix(n_,n_); |
97 |
|
|
Vector e(n_); |
98 |
|
|
Vector work(m_); |
99 |
|
|
int i, j, k; |
100 |
|
|
|
101 |
|
|
// Reduce A to bidiagonal form, storing the diagonal elements |
102 |
|
|
// in s and the super-diagonal elements in e. |
103 |
|
|
|
104 |
|
|
int nct = std::min(m_-1,n_); |
105 |
|
|
int nrt = std::max(0,n_-2); |
106 |
|
|
for (k = 0; k < std::max(nct,nrt); k++) { |
107 |
|
|
if (k < nct) { |
108 |
|
|
|
109 |
|
|
// Compute the transformation for the k-th column and |
110 |
|
|
// place the k-th diagonal in s[k]. |
111 |
|
|
// Compute 2-norm of k-th column without under/overflow. |
112 |
|
|
s_[k] = 0; |
113 |
|
|
for (i = k; i < m_; i++) { |
114 |
|
|
s_[k] = hypot(s_[k],A[i][k]); |
115 |
|
|
} |
116 |
|
|
if (s_[k] != 0.0) { |
117 |
|
|
if (A[k][k] < 0.0) { |
118 |
|
|
s_[k] = -s_[k]; |
119 |
|
|
} |
120 |
|
|
for (i = k; i < m_; i++) { |
121 |
|
|
A[i][k] /= s_[k]; |
122 |
|
|
} |
123 |
|
|
A[k][k] += 1.0; |
124 |
|
|
} |
125 |
|
|
s_[k] = -s_[k]; |
126 |
|
|
} |
127 |
|
|
for (j = k+1; j < n_; j++) { |
128 |
|
|
if ((k < nct) && (s_[k] != 0.0)) { |
129 |
|
|
|
130 |
|
|
// Apply the transformation. |
131 |
|
|
|
132 |
|
|
Real t = 0; |
133 |
|
|
for (i = k; i < m_; i++) { |
134 |
|
|
t += A[i][k]*A[i][j]; |
135 |
|
|
} |
136 |
|
|
t = -t/A[k][k]; |
137 |
|
|
for (i = k; i < m_; i++) { |
138 |
|
|
A[i][j] += t*A[i][k]; |
139 |
|
|
} |
140 |
|
|
} |
141 |
|
|
|
142 |
|
|
// Place the k-th row of A into e for the |
143 |
|
|
// subsequent calculation of the row transformation. |
144 |
|
|
|
145 |
|
|
e[j] = A[k][j]; |
146 |
|
|
} |
147 |
|
|
if (k < nct) { |
148 |
|
|
|
149 |
|
|
// Place the transformation in U for subsequent back |
150 |
|
|
// multiplication. |
151 |
|
|
|
152 |
|
|
for (i = k; i < m_; i++) { |
153 |
|
|
U_[i][k] = A[i][k]; |
154 |
|
|
} |
155 |
|
|
} |
156 |
|
|
if (k < nrt) { |
157 |
|
|
|
158 |
|
|
// Compute the k-th row transformation and place the |
159 |
|
|
// k-th super-diagonal in e[k]. |
160 |
|
|
// Compute 2-norm without under/overflow. |
161 |
|
|
e[k] = 0; |
162 |
|
|
for (i = k+1; i < n_; i++) { |
163 |
|
|
e[k] = hypot(e[k],e[i]); |
164 |
|
|
} |
165 |
|
|
if (e[k] != 0.0) { |
166 |
|
|
if (e[k+1] < 0.0) { |
167 |
|
|
e[k] = -e[k]; |
168 |
|
|
} |
169 |
|
|
for (i = k+1; i < n_; i++) { |
170 |
|
|
e[i] /= e[k]; |
171 |
|
|
} |
172 |
|
|
e[k+1] += 1.0; |
173 |
|
|
} |
174 |
|
|
e[k] = -e[k]; |
175 |
|
|
if ((k+1 < m_) & (e[k] != 0.0)) { |
176 |
|
|
|
177 |
|
|
// Apply the transformation. |
178 |
|
|
|
179 |
|
|
for (i = k+1; i < m_; i++) { |
180 |
|
|
work[i] = 0.0; |
181 |
|
|
} |
182 |
|
|
for (j = k+1; j < n_; j++) { |
183 |
|
|
for (i = k+1; i < m_; i++) { |
184 |
|
|
work[i] += e[j]*A[i][j]; |
185 |
|
|
} |
186 |
|
|
} |
187 |
|
|
for (j = k+1; j < n_; j++) { |
188 |
|
|
Real t = -e[j]/e[k+1]; |
189 |
|
|
for (i = k+1; i < m_; i++) { |
190 |
|
|
A[i][j] += t*work[i]; |
191 |
|
|
} |
192 |
|
|
} |
193 |
|
|
} |
194 |
|
|
|
195 |
|
|
// Place the transformation in V for subsequent |
196 |
|
|
// back multiplication. |
197 |
|
|
|
198 |
|
|
for (i = k+1; i < n_; i++) { |
199 |
|
|
V_[i][k] = e[i]; |
200 |
|
|
} |
201 |
|
|
} |
202 |
|
|
} |
203 |
|
|
|
204 |
|
|
// Set up the final bidiagonal matrix or order n. |
205 |
|
|
|
206 |
|
|
if (nct < n_) { |
207 |
|
|
s_[nct] = A[nct][nct]; |
208 |
|
|
} |
209 |
|
|
if (nrt+1 < n_) { |
210 |
|
|
e[nrt] = A[nrt][n_-1]; |
211 |
|
|
} |
212 |
|
|
e[n_-1] = 0.0; |
213 |
|
|
|
214 |
|
|
// generate U |
215 |
|
|
|
216 |
|
|
for (j = nct; j < n_; j++) { |
217 |
|
|
for (i = 0; i < m_; i++) { |
218 |
|
|
U_[i][j] = 0.0; |
219 |
|
|
} |
220 |
|
|
U_[j][j] = 1.0; |
221 |
|
|
} |
222 |
|
|
for (k = nct-1; k >= 0; --k) { |
223 |
|
|
if (s_[k] != 0.0) { |
224 |
|
|
for (j = k+1; j < n_; ++j) { |
225 |
|
|
Real t = 0; |
226 |
|
|
for (i = k; i < m_; i++) { |
227 |
|
|
t += U_[i][k]*U_[i][j]; |
228 |
|
|
} |
229 |
|
|
t = -t/U_[k][k]; |
230 |
|
|
for (i = k; i < m_; i++) { |
231 |
|
|
U_[i][j] += t*U_[i][k]; |
232 |
|
|
} |
233 |
|
|
} |
234 |
|
|
for (i = k; i < m_; i++ ) { |
235 |
|
|
U_[i][k] = -U_[i][k]; |
236 |
|
|
} |
237 |
|
|
U_[k][k] = 1.0 + U_[k][k]; |
238 |
|
|
for (i = 0; i < k-1; i++) { |
239 |
|
|
U_[i][k] = 0.0; |
240 |
|
|
} |
241 |
|
|
} else { |
242 |
|
|
for (i = 0; i < m_; i++) { |
243 |
|
|
U_[i][k] = 0.0; |
244 |
|
|
} |
245 |
|
|
U_[k][k] = 1.0; |
246 |
|
|
} |
247 |
|
|
} |
248 |
|
|
|
249 |
|
|
// generate V |
250 |
|
|
|
251 |
|
|
for (k = n_-1; k >= 0; --k) { |
252 |
|
|
if ((k < nrt) & (e[k] != 0.0)) { |
253 |
|
|
for (j = k+1; j < n_; ++j) { |
254 |
|
|
Real t = 0; |
255 |
|
|
for (i = k+1; i < n_; i++) { |
256 |
|
|
t += V_[i][k]*V_[i][j]; |
257 |
|
|
} |
258 |
|
|
t = -t/V_[k+1][k]; |
259 |
|
|
for (i = k+1; i < n_; i++) { |
260 |
|
|
V_[i][j] += t*V_[i][k]; |
261 |
|
|
} |
262 |
|
|
} |
263 |
|
|
} |
264 |
|
|
for (i = 0; i < n_; i++) { |
265 |
|
|
V_[i][k] = 0.0; |
266 |
|
|
} |
267 |
|
|
V_[k][k] = 1.0; |
268 |
|
|
} |
269 |
|
|
|
270 |
|
|
// Main iteration loop for the singular values. |
271 |
|
|
|
272 |
|
|
Integer p = n_, pp = p-1; |
273 |
|
|
Integer iter = 0; |
274 |
|
|
Real eps = std::pow(2.0,-52.0); |
275 |
|
|
while (p > 0) { |
276 |
|
|
Integer k; |
277 |
|
|
Integer kase; |
278 |
|
|
|
279 |
|
|
// Here is where a test for too many iterations would go. |
280 |
|
|
|
281 |
|
|
// This section of the program inspects for |
282 |
|
|
// negligible elements in the s and e arrays. On |
283 |
|
|
// completion the variables kase and k are set as follows. |
284 |
|
|
|
285 |
|
|
// kase = 1 if s(p) and e[k-1] are negligible and k<p |
286 |
|
|
// kase = 2 if s(k) is negligible and k<p |
287 |
|
|
// kase = 3 if e[k-1] is negligible, k<p, and |
288 |
|
|
// s(k), ..., s(p) are not negligible (qr step). |
289 |
|
|
// kase = 4 if e(p-1) is negligible (convergence). |
290 |
|
|
|
291 |
|
|
for (k = p-2; k >= -1; --k) { |
292 |
|
|
if (k == -1) { |
293 |
|
|
break; |
294 |
|
|
} |
295 |
|
|
if (std::fabs(e[k]) <= eps*(std::fabs(s_[k]) + |
296 |
|
|
std::fabs(s_[k+1]))) { |
297 |
|
|
e[k] = 0.0; |
298 |
|
|
break; |
299 |
|
|
} |
300 |
|
|
} |
301 |
|
|
if (k == p-2) { |
302 |
|
|
kase = 4; |
303 |
|
|
} else { |
304 |
|
|
Integer ks; |
305 |
|
|
for (ks = p-1; ks >= k; --ks) { |
306 |
|
|
if (ks == k) { |
307 |
|
|
break; |
308 |
|
|
} |
309 |
|
|
Real t = (ks != p ? std::fabs(e[ks]) : 0.) + |
310 |
|
|
(ks != k+1 ? std::fabs(e[ks-1]) : 0.); |
311 |
|
|
if (std::fabs(s_[ks]) <= eps*t) { |
312 |
|
|
s_[ks] = 0.0; |
313 |
|
|
break; |
314 |
|
|
} |
315 |
|
|
} |
316 |
|
|
if (ks == k) { |
317 |
|
|
kase = 3; |
318 |
|
|
} else if (ks == p-1) { |
319 |
|
|
kase = 1; |
320 |
|
|
} else { |
321 |
|
|
kase = 2; |
322 |
|
|
k = ks; |
323 |
|
|
} |
324 |
|
|
} |
325 |
|
|
k++; |
326 |
|
|
|
327 |
|
|
// Perform the task indicated by kase. |
328 |
|
|
|
329 |
|
|
switch (kase) { |
330 |
|
|
|
331 |
|
|
// Deflate negligible s(p). |
332 |
|
|
|
333 |
|
|
case 1: { |
334 |
|
|
Real f = e[p-2]; |
335 |
|
|
e[p-2] = 0.0; |
336 |
|
|
for (j = p-2; j >= k; --j) { |
337 |
|
|
Real t = hypot(s_[j],f); |
338 |
|
|
Real cs = s_[j]/t; |
339 |
|
|
Real sn = f/t; |
340 |
|
|
s_[j] = t; |
341 |
|
|
if (j != k) { |
342 |
|
|
f = -sn*e[j-1]; |
343 |
|
|
e[j-1] = cs*e[j-1]; |
344 |
|
|
} |
345 |
|
|
for (i = 0; i < n_; i++) { |
346 |
|
|
t = cs*V_[i][j] + sn*V_[i][p-1]; |
347 |
|
|
V_[i][p-1] = -sn*V_[i][j] + cs*V_[i][p-1]; |
348 |
|
|
V_[i][j] = t; |
349 |
|
|
} |
350 |
|
|
} |
351 |
|
|
} |
352 |
|
|
break; |
353 |
|
|
|
354 |
|
|
// Split at negligible s(k). |
355 |
|
|
|
356 |
|
|
case 2: { |
357 |
|
|
Real f = e[k-1]; |
358 |
|
|
e[k-1] = 0.0; |
359 |
|
|
for (j = k; j < p; j++) { |
360 |
|
|
Real t = hypot(s_[j],f); |
361 |
|
|
Real cs = s_[j]/t; |
362 |
|
|
Real sn = f/t; |
363 |
|
|
s_[j] = t; |
364 |
|
|
f = -sn*e[j]; |
365 |
|
|
e[j] = cs*e[j]; |
366 |
|
|
for (i = 0; i < m_; i++) { |
367 |
|
|
t = cs*U_[i][j] + sn*U_[i][k-1]; |
368 |
|
|
U_[i][k-1] = -sn*U_[i][j] + cs*U_[i][k-1]; |
369 |
|
|
U_[i][j] = t; |
370 |
|
|
} |
371 |
|
|
} |
372 |
|
|
} |
373 |
|
|
break; |
374 |
|
|
|
375 |
|
|
// Perform one qr step. |
376 |
|
|
|
377 |
|
|
case 3: { |
378 |
|
|
|
379 |
|
|
// Calculate the shift. |
380 |
|
|
Real scale = std::max( |
381 |
|
|
std::max( |
382 |
|
|
std::max( |
383 |
|
|
std::max(std::fabs(s_[p-1]), |
384 |
|
|
std::fabs(s_[p-2])), |
385 |
|
|
std::fabs(e[p-2])), |
386 |
|
|
std::fabs(s_[k])), |
387 |
|
|
std::fabs(e[k])); |
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 ? -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 RectMatrix& SVD::U() const { |
486 |
|
|
return (transpose_ ? V_ : U_); |
487 |
|
|
} |
488 |
|
|
|
489 |
|
|
const RectMatrix& SVD::V() const { |
490 |
|
|
return (transpose_ ? U_ : V_); |
491 |
|
|
} |
492 |
|
|
|
493 |
|
|
const Vector& SVD::singularValues() const { |
494 |
|
|
return s_; |
495 |
|
|
} |
496 |
|
|
|
497 |
|
|
RectMatrix 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() { |
509 |
|
|
return s_[0]; |
510 |
|
|
} |
511 |
|
|
|
512 |
|
|
Real SVD::cond() { |
513 |
|
|
return s_[0]/s_[n_-1]; |
514 |
|
|
} |
515 |
|
|
|
516 |
|
|
integer SVD::rank() { |
517 |
|
|
Real eps = std::pow(2.0,-52.0); |
518 |
|
|
Real tol = m_*s_[0]*eps; |
519 |
|
|
Integer r = 0; |
520 |
|
|
for (Size i = 0; i < s_.size(); i++) { |
521 |
|
|
if (s_[i] > tol) { |
522 |
|
|
r++; |
523 |
|
|
} |
524 |
|
|
} |
525 |
|
|
return r; |
526 |
|
|
} |
527 |
|
|
|
528 |
|
|
Vector SVD::solveFor(const Array& b) const{ |
529 |
|
|
RectMatrix W(n_, n_, 0.0); |
530 |
|
|
for (Size i=0; i<Size(n_); i++) |
531 |
|
|
W[i][i] = 1./s_[i]; |
532 |
|
|
|
533 |
|
|
RectMatrix inverse = V()* W * transpose(U()); |
534 |
|
|
Vector result = inverse * b; |
535 |
|
|
return result; |
536 |
|
|
} |
537 |
|
|
|
538 |
|
|
} |
539 |
|
|
|