NDEVR
API Documentation
SVD.hpp
1#pragma once
2#include <NDEVR/Buffer.h>
3#include <NDEVR/Exception.h>
4#include <NDEVR/Translator.h>
5namespace NDEVR
6{
7 typedef Buffer<Buffer<double>> NdArray;
12 class SVD
13 {
14 public:
15 // =============================================================================
16 // Description:
21 explicit SVD(const NdArray& inMatrix)
22 : m_(inMatrix.size())
23 , n_(inMatrix[0].size())
24 , u_(inMatrix)
25 , eps_(std::numeric_limits<double>::epsilon())
26 {
27 v_.setSize(n_);
28 for (uint04 i = 0; i < n_; i++)
29 v_[i].setSize(n_);
30 s_.setSize(n_);
31 decompose();
32 reorder();
33 tsh_ = 0.5 * std::sqrt(m_ + n_ + 1.) * s_[0] * eps_;
34 }
35
36 // =============================================================================
37 // Description:
42 const NdArray& u() noexcept
43 {
44 return u_;
45 }
46
47 // =============================================================================
48 // Description:
53 const NdArray& v() noexcept
54 {
55 return v_;
56 }
57
58 // =============================================================================
59 // Description:
64 const Buffer<double>& s() noexcept
65 {
66 return s_;
67 }
68
69 // =============================================================================
70 // Description:
78 Buffer<double> solve(const Buffer<double>& inInput, double inThresh = -1.)
79 {
80 double ss{};
81
82 if (inInput.size() != m_)
83 {
84 throw Exception(_t("bad sizes."));
85 }
86
87 Buffer<double> returnArray;
88 returnArray.setSize(n_);
89
91 tmp.setSize(n_);
92
93 tsh_ = (inThresh >= 0. ? inThresh : 0.5 * std::sqrt(m_ + n_ + 1.) * s_[0] * eps_);
94
95 for (uint04 j = 0; j < n_; j++)
96 {
97 ss = 0.;
98 if (s_[j] > tsh_)
99 {
100 for (uint04 i = 0; i < m_; i++)
101 ss += u_[i][j] * inInput[i];
102 ss /= s_[j];
103 }
104 tmp[j] = ss;
105 }
106
107 for (uint04 j = 0; j < n_; j++)
108 {
109 ss = 0.;
110 for (uint04 jj = 0; jj < n_; jj++)
111 {
112 ss += v_[j][jj] * tmp[jj];
113 }
114
115 returnArray[j] = ss;
116 }
117
118 return returnArray;
119 }
120
121 private:
122 // =============================================================================
123 // Description:
131 static double SIGN(double inA, double inB) noexcept
132 {
133 return inB >= 0 ? (inA >= 0 ? inA : -inA) : (inA >= 0 ? -inA : inA);
134 }
135
136 // =============================================================================
137 // Description:
140 //
141 static bool essentiallyEqual(double a, double b)
142 {
143 if (abs(a - b) < std::numeric_limits<double>::epsilon())
144 return true;
145 return false;
146 }
147 void decompose()
148 {
149 bool flag{};
150 uint04 i{};
151 uint04 its{};
152 uint04 j{};
153 uint04 jj{};
154 uint04 k{};
155 uint04 l{};
156 uint04 nm{};
157
158 double anorm{};
159 double c{};
160 double f{};
161 double g{};
162 double h{};
163 double ss{};
164 double scale{};
165 double x{};
166 double y{};
167 double z{};
168
169 Buffer<double> rv1;
170 rv1.setSize(n_);
171
172 for (i = 0; i < n_; ++i)
173 {
174 l = i + 2;
175 rv1[i] = scale * g;
176 g = ss = scale = 0.;
177
178 if (i < m_)
179 {
180 for (k = i; k < m_; ++k)
181 {
182 scale += std::abs(u_[k][i]);
183 }
184
185 if (!essentiallyEqual(scale, 0.))
186 {
187 for (k = i; k < m_; ++k)
188 {
189 u_[k][i] /= scale;
190 ss += u_[k][i] * u_[k][i];
191 }
192
193 f = u_[i][i];
194 g = -SIGN(std::sqrt(ss), f);
195 h = f * g - ss;
196 u_[i][i] = f - g;
197
198 for (j = l - 1; j < n_; ++j)
199 {
200 for (ss = 0., k = i; k < m_; ++k)
201 {
202 ss += u_[k][i] * u_[k][j];
203 }
204
205 f = ss / h;
206
207 for (k = i; k < m_; ++k)
208 {
209 u_[k][j] += f * u_[k][i];
210 }
211 }
212
213 for (k = i; k < m_; ++k)
214 {
215 u_[k][i] *= scale;
216 }
217 }
218 }
219
220 s_[i] = scale * g;
221 g = ss = scale = 0.;
222
223 if (i + 1 <= m_ && i + 1 != n_)
224 {
225 for (k = l - 1; k < n_; ++k)
226 {
227 scale += std::abs(u_[i][k]);
228 }
229
230 if (!essentiallyEqual(scale, 0.))
231 {
232 for (k = l - 1; k < n_; ++k)
233 {
234 u_[i][k] /= scale;
235 ss += u_[i][k] * u_[i][k];
236 }
237
238 f = u_[i][l - 1];
239 g = -SIGN(std::sqrt(ss), f);
240 h = f * g - ss;
241 u_[i][l - 1] = f - g;
242
243 for (k = l - 1; k < n_; ++k)
244 {
245 rv1[k] = u_[i][k] / h;
246 }
247
248 for (j = l - 1; j < m_; ++j)
249 {
250 for (ss = 0., k = l - 1; k < n_; ++k)
251 {
252 ss += u_[j][k] * u_[i][k];
253 }
254
255 for (k = l - 1; k < n_; ++k)
256 {
257 u_[j][k] += ss * rv1[k];
258 }
259 }
260
261 for (k = l - 1; k < n_; ++k)
262 {
263 u_[i][k] *= scale;
264 }
265 }
266 }
267
268 anorm = std::max(anorm, (std::abs(s_[i]) + std::abs(rv1[i])));
269 }
270
271 for (i = n_ - 1; i != static_cast<uint04>(-1); --i)
272 {
273 if (i < n_ - 1)
274 {
275 if (!essentiallyEqual(g, 0.))
276 {
277 for (j = l; j < n_; ++j)
278 {
279 v_[j][i] = (u_[i][j] / u_[i][l]) / g;
280 }
281
282 for (j = l; j < n_; ++j)
283 {
284 for (ss = 0., k = l; k < n_; ++k)
285 {
286 ss += u_[i][k] * v_[k][j];
287 }
288
289 for (k = l; k < n_; ++k)
290 {
291 v_[k][j] += ss * v_[k][i];
292 }
293 }
294 }
295
296 for (j = l; j < n_; ++j)
297 {
298 v_[i][j] = v_[j][i] = 0.;
299 }
300 }
301
302 v_[i][i] = 1.;
303 g = rv1[i];
304 l = i;
305 }
306
307 for (i = std::min(m_, n_) - 1; i != static_cast<uint04>(-1); --i)
308 {
309 l = i + 1;
310 g = s_[i];
311
312 for (j = l; j < n_; ++j)
313 {
314 u_[i][j] = 0.;
315 }
316
317 if (!essentiallyEqual(g, 0.))
318 {
319 g = 1. / g;
320
321 for (j = l; j < n_; ++j)
322 {
323 for (ss = 0., k = l; k < m_; ++k)
324 {
325 ss += u_[k][i] * u_[k][j];
326 }
327
328 f = (ss / u_[i][i]) * g;
329
330 for (k = i; k < m_; ++k)
331 {
332 u_[k][j] += f * u_[k][i];
333 }
334 }
335
336 for (j = i; j < m_; ++j)
337 {
338 u_[j][i] *= g;
339 }
340 }
341 else
342 {
343 for (j = i; j < m_; ++j)
344 {
345 u_[j][i] = 0.;
346 }
347 }
348
349 ++u_[i][i];
350 }
351
352 for (k = n_ - 1; k != static_cast<uint04>(-1); --k)
353 {
354 for (its = 0; its < 30; ++its)
355 {
356 flag = true;
357 for (l = k; l != static_cast<uint04>(-1); --l)
358 {
359 nm = l - 1;
360 if (l == 0 || std::abs(rv1[l]) <= eps_ * anorm)
361 {
362 flag = false;
363 break;
364 }
365
366 if (std::abs(s_[nm]) <= eps_ * anorm)
367 {
368 break;
369 }
370 }
371
372 if (flag)
373 {
374 c = 0.;
375 ss = 1.;
376 for (i = l; i < k + 1; ++i)
377 {
378 f = ss * rv1[i];
379 rv1[i] = c * rv1[i];
380
381 if (std::abs(f) <= eps_ * anorm)
382 {
383 break;
384 }
385
386 g = s_[i];
387 h = pythag(f, g);
388 s_[i] = h;
389 h = 1. / h;
390 c = g * h;
391 ss = -f * h;
392
393 for (j = 0; j < m_; ++j)
394 {
395 y = u_[j][nm];
396 z = u_[j][i];
397 u_[j][nm] = y * c + z * ss;
398 u_[j][i] = z * c - y * ss;
399 }
400 }
401 }
402
403 z = s_[k];
404 if (l == k)
405 {
406 if (z < 0.)
407 {
408 s_[k] = -z;
409 for (j = 0; j < n_; ++j)
410 {
411 v_[j][k] = -v_[j][k];
412 }
413 }
414 break;
415 }
416
417 if (its == 29)
418 {
419 throw Exception(_t("no convergence in 30 svdcmp iterations"));
420 }
421
422 x = s_[l];
423 nm = k - 1;
424 y = s_[nm];
425 g = rv1[nm];
426 h = rv1[k];
427 f = ((y - z) * (y + z) + (g - h) * (g + h)) / (2. * h * y);
428 g = pythag(f, 1.);
429 f = ((x - z) * (x + z) + h * ((y / (f + SIGN(g, f))) - h)) / x;
430 c = ss = 1.;
431
432 for (j = l; j <= nm; j++)
433 {
434 i = j + 1;
435 g = rv1[i];
436 y = s_[i];
437 h = ss * g;
438 g = c * g;
439 z = pythag(f, h);
440 rv1[j] = z;
441 c = f / z;
442 ss = h / z;
443 f = x * c + g * ss;
444 g = g * c - x * ss;
445 h = y * ss;
446 y *= c;
447
448 for (jj = 0; jj < n_; ++jj)
449 {
450 x = v_[jj][j];
451 z = v_[jj][i];
452 v_[jj][j] = x * c + z * ss;
453 v_[jj][i] = z * c - x * ss;
454 }
455
456 z = pythag(f, h);
457 s_[j] = z;
458
459 if (!essentiallyEqual(z, 0.))
460 {
461 z = 1. / z;
462 c = f * z;
463 ss = h * z;
464 }
465
466 f = c * g + ss * y;
467 x = c * y - ss * g;
468
469 for (jj = 0; jj < m_; ++jj)
470 {
471 y = u_[jj][j];
472 z = u_[jj][i];
473 u_[jj][j] = y * c + z * ss;
474 u_[jj][i] = z * c - y * ss;
475 }
476 }
477 rv1[l] = 0.;
478 rv1[k] = f;
479 s_[k] = x;
480 }
481 }
482 }
483
484 // =============================================================================
485 // Description:
488 void reorder()
489 {
490 uint04 i = 0;
491 uint04 j = 0;
492 uint04 k = 0;
493 uint04 ss = 0;
494 uint04 inc = 1;
495
496 double sw{};
497 Buffer<double> su;
498 su.setSize(m_);
499 Buffer<double> sv;
500 sv.setSize(n_);
501
502 do
503 {
504 inc *= 3;
505 ++inc;
506 } while (inc <= n_);
507
508 do
509 {
510 inc /= 3;
511 for (i = inc; i < n_; ++i)
512 {
513 sw = s_[i];
514 for (k = 0; k < m_; ++k)
515 {
516 su[k] = u_[k][i];
517 }
518
519 for (k = 0; k < n_; ++k)
520 {
521 sv[k] = v_[k][i];
522 }
523
524 j = i;
525 while (s_[j - inc] < sw)
526 {
527 s_[j] = s_[j - inc];
528
529 for (k = 0; k < m_; ++k)
530 {
531 u_[k][j] = u_[k][j - inc];
532 }
533
534 for (k = 0; k < n_; ++k)
535 {
536 v_[k][j] = v_[k][j - inc];
537 }
538
539 j -= inc;
540
541 if (j < inc)
542 {
543 break;
544 }
545 }
546
547 s_[j] = sw;
548
549 for (k = 0; k < m_; ++k)
550 {
551 u_[k][j] = su[k];
552 }
553
554 for (k = 0; k < n_; ++k)
555 {
556 v_[k][j] = sv[k];
557 }
558 }
559 } while (inc > 1);
560
561 for (k = 0; k < n_; ++k)
562 {
563 ss = 0;
564
565 for (i = 0; i < m_; i++)
566 {
567 if (u_[i][k] < 0.)
568 {
569 ss++;
570 }
571 }
572
573 for (j = 0; j < n_; ++j)
574 {
575 if (v_[j][k] < 0.)
576 {
577 ss++;
578 }
579 }
580
581 if (ss > (m_ + n_) / 2)
582 {
583 for (i = 0; i < m_; ++i)
584 {
585 u_[i][k] = -u_[i][k];
586 }
587
588 for (j = 0; j < n_; ++j)
589 {
590 v_[j][k] = -v_[j][k];
591 }
592 }
593 }
594 }
595
596 // =============================================================================
597 // Description:
605 static double pythag(double inA, double inB) noexcept
606 {
607 const double absa = std::abs(inA);
608 const double absb = std::abs(inB);
609 return (absa > absb
610 ? absa * std::sqrt(1. + (absb / absa) * (absb / absa))
611 : (essentiallyEqual(absb, 0.) ? 0. : absb * std::sqrt(1. + (absb / absa) * (absb / absa))));
612 }
613 static Buffer<double> lstsq(const NdArray& inA, const Buffer<double>& inB, double inTolerance = 1e-12)
614 {
615 SVD svdSolver(inA);
616 const double threshold = inTolerance * svdSolver.s()[0];
617
618 return svdSolver.solve(inB, threshold);
619 }
620 private:
621 // ===============================Attributes====================================
622 const uint04 m_{};
623 const uint04 n_{};
624 NdArray u_{};
625 NdArray v_{};
626 Buffer<double> s_;
627 double eps_{};
628 double tsh_{};
629 };
630
631
632}
The equivelent of std::vector but with a bit more control.
Definition Buffer.hpp:58
Provides consistent interface to handle errors through the throw expression.
Definition Exception.hpp:47
const NdArray & v() noexcept
the resultant v matrix
Definition SVD.hpp:53
SVD(const NdArray &inMatrix)
Constructor.
Definition SVD.hpp:21
const NdArray & u() noexcept
the resultant u matrix
Definition SVD.hpp:42
Buffer< double > solve(const Buffer< double > &inInput, double inThresh=-1.)
solves the linear least squares problem
Definition SVD.hpp:78
const Buffer< double > & s() noexcept
the resultant w matrix
Definition SVD.hpp:64
The primary namespace for the NDEVR SDK.
constexpr Angle< t_angle_type > abs(const Angle< t_angle_type > &value)
Changes an input with a negative sign, to a positive sign.
uint32_t uint04
-Defines an alias representing a 4 byte, unsigned integer -Can represent exact integer values 0 throu...
STL namespace.