SingularValueDecomposition.cs 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906
  1. using System.Collections;
  2. namespace VisualMath.Accord.Math.Decompositions
  3. {
  4. using System;
  5. /// <summary>
  6. /// Singular Value Decomposition for a rectangular matrix.
  7. /// </summary>
  8. /// <remarks>
  9. /// <para>
  10. /// For an m-by-n matrix <c>A</c> with <c>m >= n</c>, the singular value decomposition
  11. /// is an m-by-n orthogonal matrix <c>U</c>, an n-by-n diagonal matrix <c>S</c>, and
  12. /// an n-by-n orthogonal matrix <c>V</c> so that <c>A = U * S * V'</c>.
  13. /// The singular values, <c>sigma[k] = S[k,k]</c>, are ordered so that
  14. /// <c>sigma[0] >= sigma[1] >= ... >= sigma[n-1]</c>.</para>
  15. /// <para>
  16. /// The singular value decomposition always exists, so the constructor will
  17. /// never fail. The matrix condition number and the effective numerical
  18. /// rank can be computed from this decomposition.</para>
  19. /// <para>
  20. /// WARNING! Please be aware that if A has less rows than columns, it is better
  21. /// to compute the decomposition on the transpose of A and then swap the left
  22. /// and right eigenvectors. If the routine is computed on A directly, the diagonal
  23. /// of singular values may contain one or more zeros. The identity A = U * S * V'
  24. /// may still hold, however. To overcome this problem, pass true to the
  25. /// <see cref="SingularValueDecomposition(double[,], bool, bool, bool)">autoTranspose</see> argument of the class constructor.</para>
  26. /// <para>
  27. /// This routine computes the economy decomposition of A.</para>
  28. ///
  29. /// </remarks>
  30. public sealed class SingularValueDecomposition
  31. {
  32. private double[,] u;
  33. private double[,] v;
  34. private double[] s; // singular values
  35. private int m;
  36. private int n;
  37. private bool swapped;
  38. /// <summary>Returns the condition number <c>max(S) / min(S)</c>.</summary>
  39. public double Condition
  40. {
  41. get { return s[0] / s[System.Math.Min(m, n) - 1]; }
  42. }
  43. /// <summary>Returns the singularity threshold.</summary>
  44. public double Threshold
  45. {
  46. get { return Double.Epsilon * System.Math.Max(m, n) * s[0]; }
  47. }
  48. /// <summary>Returns the Two norm.</summary>
  49. public double TwoNorm
  50. {
  51. get { return s[0]; }
  52. }
  53. /// <summary>Returns the effective numerical matrix rank.</summary>
  54. /// <value>Number of non-negligible singular values.</value>
  55. public int Rank
  56. {
  57. get
  58. {
  59. double eps = System.Math.Pow(2.0, -52.0);
  60. double tol = System.Math.Max(m, n) * s[0] * eps;
  61. int r = 0;
  62. for (int i = 0; i < s.Length; i++)
  63. {
  64. if (s[i] > tol)
  65. r++;
  66. }
  67. return r;
  68. }
  69. }
  70. /// <summary>Returns the one-dimensional array of singular values.</summary>
  71. public double[] Diagonal
  72. {
  73. get { return this.s; }
  74. }
  75. /// <summary>Returns the block diagonal matrix of singular values.</summary>
  76. public double[,] DiagonalMatrix
  77. {
  78. get { return Matrix.Diagonal(s); }
  79. }
  80. /// <summary>Returns the V matrix of Singular Vectors.</summary>
  81. public double[,] RightSingularVectors
  82. {
  83. get { return v; }
  84. }
  85. /// <summary>Return the U matrix of Singular Vectors.</summary>
  86. public double[,] LeftSingularVectors
  87. {
  88. get { return u; }
  89. }
  90. /// <summary>Construct singular value decomposition.</summary>
  91. public SingularValueDecomposition(double[,] value)
  92. : this(value, true, true)
  93. {
  94. }
  95. /// <summary>Construct singular value decomposition.</summary>
  96. public SingularValueDecomposition(double[,] value, bool computeLeftSingularVectors, bool computeRightSingularVectors)
  97. : this(value, computeLeftSingularVectors, computeRightSingularVectors, false)
  98. {
  99. }
  100. /// <summary>Construct singular value decomposition.</summary>
  101. public SingularValueDecomposition(double[,] value, bool computeLeftSingularVectors, bool computeRightSingularVectors, bool autoTranspose)
  102. {
  103. if (value == null)
  104. {
  105. throw new ArgumentNullException("value", "Matrix cannot be null.");
  106. }
  107. double[,] a;
  108. m = value.GetLength(0); // rows
  109. n = value.GetLength(1); // cols
  110. double eps = System.Math.Pow(2.0, -52.0);
  111. double tiny = System.Math.Pow(2.0, -966.0);
  112. if (m < n) // Check if we are violating JAMA's assumption
  113. {
  114. if (!autoTranspose) // Yes, check if we should correct it
  115. {
  116. // Warning! This routine is not guaranteed to work when A has less rows
  117. // than columns. If this is the case, you should compute SVD on the
  118. // transpose of A and then swap the left and right eigenvectors.
  119. // However, as the solution found can still be useful, the exception below
  120. // will not be thrown, and only a warning will be output in the trace.
  121. // throw new ArgumentException("Matrix should have more rows than columns.");
  122. System.Diagnostics.Trace.WriteLine(
  123. "WARNING: Computing SVD on a matrix with more columns than rows.");
  124. // Proceed anyway
  125. a = (double[,])value.Clone();
  126. }
  127. else
  128. {
  129. // Transposing and swapping
  130. a = value.Transpose();
  131. m = value.GetLength(1);
  132. n = value.GetLength(0);
  133. swapped = true;
  134. }
  135. }
  136. else
  137. {
  138. a = (double[,])value.Clone(); // Input matrix is ok
  139. }
  140. int nu = System.Math.Min(m, n);
  141. s = new double[System.Math.Min(m + 1, n)];
  142. u = new double[m, nu];
  143. v = new double[n, n];
  144. double[] e = new double[n];
  145. double[] work = new double[m];
  146. bool wantu = computeLeftSingularVectors;
  147. bool wantv = computeRightSingularVectors;
  148. // Reduce A to bidiagonal form, storing the diagonal elements in s and the super-diagonal elements in e.
  149. int nct = System.Math.Min(m - 1, n);
  150. int nrt = System.Math.Max(0, System.Math.Min(n - 2, m));
  151. for (int k = 0; k < System.Math.Max(nct, nrt); k++)
  152. {
  153. if (k < nct)
  154. {
  155. // Compute the transformation for the k-th column and place the k-th diagonal in s[k].
  156. // Compute 2-norm of k-th column without under/overflow.
  157. s[k] = 0;
  158. for (int i = k; i < m; i++)
  159. {
  160. s[k] = Accord.Math.Tools.Hypotenuse(s[k], a[i, k]);
  161. }
  162. if (s[k] != 0.0)
  163. {
  164. if (a[k, k] < 0.0)
  165. {
  166. s[k] = -s[k];
  167. }
  168. for (int i = k; i < m; i++)
  169. {
  170. a[i, k] /= s[k];
  171. }
  172. a[k, k] += 1.0;
  173. }
  174. s[k] = -s[k];
  175. }
  176. unsafe
  177. {
  178. for (int j = k + 1; j < n; j++)
  179. {
  180. fixed (double* ptr_ak = &a[k, k], ptr_aj = &a[k, j])
  181. {
  182. if ((k < nct) & (s[k] != 0.0))
  183. {
  184. // Apply the transformation.
  185. double t = 0;
  186. double* ak = ptr_ak;
  187. double* aj = ptr_aj;
  188. for (int i = k; i < m; i++)
  189. {
  190. t += (*ak) * (*aj);
  191. ak += n; aj += n;
  192. }
  193. t = -t / *ptr_ak;
  194. ak = ptr_ak;
  195. aj = ptr_aj;
  196. for (int i = k; i < m; i++)
  197. {
  198. *aj += t * (*ak);
  199. ak += n; aj += n;
  200. }
  201. }
  202. // Place the k-th row of A into e for the subsequent calculation of the row transformation.
  203. e[j] = *ptr_aj;
  204. }
  205. }
  206. }
  207. if (wantu & (k < nct))
  208. {
  209. // Place the transformation in U for subsequent back
  210. // multiplication.
  211. for (int i = k; i < m; i++)
  212. u[i, k] = a[i, k];
  213. }
  214. if (k < nrt)
  215. {
  216. // Compute the k-th row transformation and place the k-th super-diagonal in e[k].
  217. // Compute 2-norm without under/overflow.
  218. e[k] = 0;
  219. for (int i = k + 1; i < n; i++)
  220. {
  221. e[k] = Accord.Math.Tools.Hypotenuse(e[k], e[i]);
  222. }
  223. if (e[k] != 0.0)
  224. {
  225. if (e[k + 1] < 0.0)
  226. e[k] = -e[k];
  227. for (int i = k + 1; i < n; i++)
  228. e[i] /= e[k];
  229. e[k + 1] += 1.0;
  230. }
  231. e[k] = -e[k];
  232. if ((k + 1 < m) & (e[k] != 0.0))
  233. {
  234. // Apply the transformation.
  235. for (int i = k + 1; i < m; i++)
  236. work[i] = 0.0;
  237. unsafe
  238. {
  239. fixed (double* ptr_a = a)
  240. {
  241. int k1 = k + 1;
  242. for (int i = k1; i < m; i++)
  243. {
  244. double* ai = ptr_a + (i * n) + k1;
  245. for (int j = k1; j < n; j++, ai++)
  246. {
  247. work[i] += e[j] * (*ai);
  248. }
  249. }
  250. for (int j = k1; j < n; j++)
  251. {
  252. double t = -e[j] / e[k1];
  253. double* aj = ptr_a + (k1 * n) + j;
  254. for (int i = k1; i < m; i++, aj += n)
  255. {
  256. *aj += t * work[i];
  257. }
  258. }
  259. }
  260. }
  261. }
  262. if (wantv)
  263. {
  264. // Place the transformation in V for subsequent back multiplication.
  265. for (int i = k + 1; i < n; i++)
  266. v[i, k] = e[i];
  267. }
  268. }
  269. }
  270. // Set up the final bidiagonal matrix or order p.
  271. int p = System.Math.Min(n, m + 1);
  272. if (nct < n) s[nct] = a[nct, nct];
  273. if (m < p) s[p - 1] = 0.0;
  274. if (nrt + 1 < p) e[nrt] = a[nrt, p - 1];
  275. e[p - 1] = 0.0;
  276. // If required, generate U.
  277. if (wantu)
  278. {
  279. for (int j = nct; j < nu; j++)
  280. {
  281. for (int i = 0; i < m; i++)
  282. u[i, j] = 0.0;
  283. u[j, j] = 1.0;
  284. }
  285. unsafe
  286. {
  287. for (int k = nct - 1; k >= 0; k--)
  288. {
  289. if (s[k] != 0.0)
  290. {
  291. fixed (double* ptr_uk = &u[k, k])
  292. {
  293. double* uk, uj;
  294. for (int j = k + 1; j < nu; j++)
  295. {
  296. fixed (double* ptr_uj = &u[k, j])
  297. {
  298. double t = 0;
  299. uk = ptr_uk;
  300. uj = ptr_uj;
  301. for (int i = k; i < m; i++)
  302. {
  303. t += *uk * *uj;
  304. uk += nu; uj += nu;
  305. }
  306. t = -t / *ptr_uk;
  307. uk = ptr_uk;
  308. uj = ptr_uj;
  309. for (int i = k; i < m; i++)
  310. {
  311. *uj += t * *uk;
  312. uk += nu; uj += nu;
  313. }
  314. }
  315. }
  316. uk = ptr_uk;
  317. for (int i = k; i < m; i++)
  318. {
  319. *uk = -(*uk);
  320. uk += nu;
  321. }
  322. u[k, k] = 1.0 + u[k, k];
  323. for (int i = 0; i < k - 1; i++)
  324. u[i, k] = 0.0;
  325. }
  326. }
  327. else
  328. {
  329. for (int i = 0; i < m; i++)
  330. u[i, k] = 0.0;
  331. u[k, k] = 1.0;
  332. }
  333. }
  334. }
  335. }
  336. // If required, generate V.
  337. if (wantv)
  338. {
  339. for (int k = n - 1; k >= 0; k--)
  340. {
  341. if ((k < nrt) & (e[k] != 0.0))
  342. {
  343. // TODO: The following is a pseudo correction to make SVD
  344. // work on matrices with n > m (less rows than columns).
  345. // For the proper correction, compute the decomposition of the
  346. // transpose of A and swap the left and right eigenvectors
  347. // Original line:
  348. // for (int j = k + 1; j < nu; j++)
  349. // Pseudo correction:
  350. // for (int j = k + 1; j < n; j++)
  351. for (int j = k + 1; j < n; j++) // pseudo-correction
  352. {
  353. unsafe
  354. {
  355. fixed (double* ptr_vk = &v[k + 1, k], ptr_vj = &v[k + 1, j])
  356. {
  357. double t = 0;
  358. double* vk = ptr_vk;
  359. double* vj = ptr_vj;
  360. for (int i = k + 1; i < n; i++)
  361. {
  362. t += *vk * *vj;
  363. vk += n; vj += n;
  364. }
  365. t = -t / *ptr_vk;
  366. vk = ptr_vk;
  367. vj = ptr_vj;
  368. for (int i = k + 1; i < n; i++)
  369. {
  370. *vj += t * *vk;
  371. vk += n; vj += n;
  372. }
  373. }
  374. }
  375. }
  376. }
  377. for (int i = 0; i < n; i++)
  378. v[i, k] = 0.0;
  379. v[k, k] = 1.0;
  380. }
  381. }
  382. // Main iteration loop for the singular values.
  383. int pp = p - 1;
  384. int iter = 0;
  385. while (p > 0)
  386. {
  387. int k, kase;
  388. // Here is where a test for too many iterations would go.
  389. // This section of the program inspects for
  390. // negligible elements in the s and e arrays. On
  391. // completion the variables kase and k are set as follows.
  392. // kase = 1 if s(p) and e[k-1] are negligible and k<p
  393. // kase = 2 if s(k) is negligible and k<p
  394. // kase = 3 if e[k-1] is negligible, k<p, and
  395. // s(k), ..., s(p) are not negligible (qr step).
  396. // kase = 4 if e(p-1) is negligible (convergence).
  397. for (k = p - 2; k >= -1; k--)
  398. {
  399. if (k == -1)
  400. break;
  401. if (System.Math.Abs(e[k]) <=
  402. tiny + eps * (System.Math.Abs(s[k]) + System.Math.Abs(s[k + 1])))
  403. {
  404. e[k] = 0.0;
  405. break;
  406. }
  407. }
  408. if (k == p - 2)
  409. {
  410. kase = 4;
  411. }
  412. else
  413. {
  414. int ks;
  415. for (ks = p - 1; ks >= k; ks--)
  416. {
  417. if (ks == k)
  418. break;
  419. double t = (ks != p ? System.Math.Abs(e[ks]) : 0.0) +
  420. (ks != k + 1 ? System.Math.Abs(e[ks - 1]) : 0.0);
  421. if (System.Math.Abs(s[ks]) <= tiny + eps * t)
  422. {
  423. s[ks] = 0.0;
  424. break;
  425. }
  426. }
  427. if (ks == k)
  428. kase = 3;
  429. else if (ks == p - 1)
  430. kase = 1;
  431. else
  432. {
  433. kase = 2;
  434. k = ks;
  435. }
  436. }
  437. k++;
  438. // Perform the task indicated by kase.
  439. switch (kase)
  440. {
  441. // Deflate negligible s(p).
  442. case 1:
  443. {
  444. double f = e[p - 2];
  445. e[p - 2] = 0.0;
  446. for (int j = p - 2; j >= k; j--)
  447. {
  448. double t = Accord.Math.Tools.Hypotenuse(s[j], f);
  449. double cs = s[j] / t;
  450. double sn = f / t;
  451. s[j] = t;
  452. if (j != k)
  453. {
  454. f = -sn * e[j - 1];
  455. e[j - 1] = cs * e[j - 1];
  456. }
  457. if (wantv)
  458. {
  459. for (int i = 0; i < n; i++)
  460. {
  461. t = cs * v[i, j] + sn * v[i, p - 1];
  462. v[i, p - 1] = -sn * v[i, j] + cs * v[i, p - 1];
  463. v[i, j] = t;
  464. }
  465. }
  466. }
  467. }
  468. break;
  469. // Split at negligible s(k).
  470. case 2:
  471. {
  472. double f = e[k - 1];
  473. e[k - 1] = 0.0;
  474. for (int j = k; j < p; j++)
  475. {
  476. double t = Accord.Math.Tools.Hypotenuse(s[j], f);
  477. double cs = s[j] / t;
  478. double sn = f / t;
  479. s[j] = t;
  480. f = -sn * e[j];
  481. e[j] = cs * e[j];
  482. if (wantu)
  483. {
  484. for (int i = 0; i < m; i++)
  485. {
  486. t = cs * u[i, j] + sn * u[i, k - 1];
  487. u[i, k - 1] = -sn * u[i, j] + cs * u[i, k - 1];
  488. u[i, j] = t;
  489. }
  490. }
  491. }
  492. }
  493. break;
  494. // Perform one qr step.
  495. case 3:
  496. {
  497. // Calculate the shift.
  498. double scale = System.Math.Max(System.Math.Max(System.Math.Max(System.Math.Max(System.Math.Abs(s[p - 1]), System.Math.Abs(s[p - 2])), System.Math.Abs(e[p - 2])), System.Math.Abs(s[k])), System.Math.Abs(e[k]));
  499. double sp = s[p - 1] / scale;
  500. double spm1 = s[p - 2] / scale;
  501. double epm1 = e[p - 2] / scale;
  502. double sk = s[k] / scale;
  503. double ek = e[k] / scale;
  504. double b = ((spm1 + sp) * (spm1 - sp) + epm1 * epm1) / 2.0;
  505. double c = (sp * epm1) * (sp * epm1);
  506. double shift = 0.0;
  507. if ((b != 0.0) | (c != 0.0))
  508. {
  509. if (b < 0.0)
  510. shift = -System.Math.Sqrt(b * b + c);
  511. else
  512. shift = System.Math.Sqrt(b * b + c);
  513. shift = c / (b + shift);
  514. }
  515. double f = (sk + sp) * (sk - sp) + shift;
  516. double g = sk * ek;
  517. // Chase zeros.
  518. for (int j = k; j < p - 1; j++)
  519. {
  520. double t = Accord.Math.Tools.Hypotenuse(f, g);
  521. double cs = f / t;
  522. double sn = g / t;
  523. if (j != k) e[j - 1] = t;
  524. f = cs * s[j] + sn * e[j];
  525. e[j] = cs * e[j] - sn * s[j];
  526. g = sn * s[j + 1];
  527. s[j + 1] = cs * s[j + 1];
  528. if (wantv)
  529. {
  530. unsafe
  531. {
  532. fixed (double* ptr_vj = &v[0, j])
  533. {
  534. double* vj = ptr_vj;
  535. double* vj1 = ptr_vj + 1;
  536. for (int i = 0; i < n; i++)
  537. {
  538. /*t = cs * v[i, j] + sn * v[i, j + 1];
  539. v[i, j + 1] = -sn * v[i, j] + cs * v[i, j + 1];
  540. v[i, j] = t;*/
  541. double vij = *vj;
  542. double vij1 = *vj1;
  543. t = cs * vij + sn * vij1;
  544. *vj1 = -sn * vij + cs * vij1;
  545. *vj = t;
  546. vj += n; vj1 += n;
  547. }
  548. }
  549. }
  550. }
  551. t = Accord.Math.Tools.Hypotenuse(f, g);
  552. cs = f / t;
  553. sn = g / t;
  554. s[j] = t;
  555. f = cs * e[j] + sn * s[j + 1];
  556. s[j + 1] = -sn * e[j] + cs * s[j + 1];
  557. g = sn * e[j + 1];
  558. e[j + 1] = cs * e[j + 1];
  559. if (wantu && (j < m - 1))
  560. {
  561. unsafe
  562. {
  563. fixed (double* ptr_uj = &u[0, j])
  564. {
  565. double* uj = ptr_uj;
  566. double* uj1 = ptr_uj + 1;
  567. for (int i = 0; i < m; i++)
  568. {
  569. /* t = cs * u[i, j] + sn * u[i, j + 1];
  570. u[i, j + 1] = -sn * u[i, j] + cs * u[i, j + 1];
  571. u[i, j] = t;*/
  572. double uij = *uj;
  573. double uij1 = *uj1;
  574. t = cs * uij + sn * uij1;
  575. *uj1 = -sn * uij + cs * uij1;
  576. *uj = t;
  577. uj += nu; uj1 += nu;
  578. }
  579. }
  580. }
  581. }
  582. }
  583. e[p - 2] = f;
  584. iter = iter + 1;
  585. }
  586. break;
  587. // Convergence.
  588. case 4:
  589. {
  590. // Make the singular values positive.
  591. if (s[k] <= 0.0)
  592. {
  593. s[k] = (s[k] < 0.0 ? -s[k] : 0.0);
  594. if (wantv)
  595. {
  596. for (int i = 0; i <= pp; i++)
  597. v[i, k] = -v[i, k];
  598. }
  599. }
  600. // Order the singular values.
  601. while (k < pp)
  602. {
  603. if (s[k] >= s[k + 1])
  604. break;
  605. double t = s[k];
  606. s[k] = s[k + 1];
  607. s[k + 1] = t;
  608. if (wantv && (k < n - 1))
  609. for (int i = 0; i < n; i++)
  610. {
  611. t = v[i, k + 1];
  612. v[i, k + 1] = v[i, k];
  613. v[i, k] = t;
  614. }
  615. if (wantu && (k < m - 1))
  616. for (int i = 0; i < m; i++)
  617. {
  618. t = u[i, k + 1];
  619. u[i, k + 1] = u[i, k];
  620. u[i, k] = t;
  621. }
  622. k++;
  623. }
  624. iter = 0;
  625. p--;
  626. }
  627. break;
  628. }
  629. }
  630. // If we are violating JAMA's assumption about
  631. // the input dimension, we need to swap u and v.
  632. if (swapped)
  633. {
  634. double[,] temp = this.u;
  635. this.u = this.v;
  636. this.v = temp;
  637. }
  638. }
  639. /// <summary>
  640. /// Solves a linear equation system of the form AX = B.
  641. /// </summary>
  642. /// <param name="value">Parameter B from the equation AX = B.</param>
  643. /// <returns>The solution X from equation AX = B.</returns>
  644. public double[,] Solve(double[,] value)
  645. {
  646. // Additionally an important property is that if there does not exists a solution
  647. // when the matrix A is singular but replacing 1/Li with 0 will provide a solution
  648. // that minimizes the residue |AX -Y|. SVD finds the least squares best compromise
  649. // solution of the linear equation system. Interestingly SVD can be also used in an
  650. // over-determined system where the number of equations exceeds that of the parameters.
  651. // L is a diagonal matrix with non-negative matrix elements having the same
  652. // dimension as A, Wi ? 0. The diagonal elements of L are the singular values of matrix A.
  653. double[,] Y = value;
  654. // Create L*, which is a diagonal matrix with elements
  655. // L*[i] = 1/L[i] if L[i] < e, else 0,
  656. // where e is the so-called singularity threshold.
  657. // In other words, if L[i] is zero or close to zero (smaller than e),
  658. // one must replace 1/L[i] with 0. The value of e depends on the precision
  659. // of the hardware. This method can be used to solve linear equations
  660. // systems even if the matrices are singular or close to singular.
  661. //singularity threshold
  662. double e = this.Threshold;
  663. int scols = s.Length;
  664. double[,] Ls = new double[scols, scols];
  665. for (int i = 0; i < s.Length; i++)
  666. {
  667. if (System.Math.Abs(s[i]) <= e)
  668. Ls[i, i] = 0.0;
  669. else Ls[i, i] = 1.0 / s[i];
  670. }
  671. //(V x L*) x Ut x Y
  672. double[,] VL = v.Multiply(Ls);
  673. //(V x L* x Ut) x Y
  674. int vrows = v.GetLength(0);
  675. int urows = u.GetLength(0);
  676. double[,] VLU = new double[vrows, urows];
  677. for (int i = 0; i < vrows; i++)
  678. {
  679. for (int j = 0; j < urows; j++)
  680. {
  681. double sum = 0;
  682. for (int k = 0; k < urows; k++)
  683. sum += VL[i, k] * u[j, k];
  684. VLU[i, j] = sum;
  685. }
  686. }
  687. //(V x L* x Ut x Y)
  688. return VLU.Multiply(Y);
  689. }
  690. /// <summary>
  691. /// Solves a linear equation system of the form Ax = b.
  692. /// </summary>
  693. /// <param name="value">The b from the equation Ax = b.</param>
  694. /// <returns>The x from equation Ax = b.</returns>
  695. public double[] Solve(double[] value)
  696. {
  697. // Additionally an important property is that if there does not exists a solution
  698. // when the matrix A is singular but replacing 1/Li with 0 will provide a solution
  699. // that minimizes the residue |AX -Y|. SVD finds the least squares best compromise
  700. // solution of the linear equation system. Interestingly SVD can be also used in an
  701. // over-determined system where the number of equations exceeds that of the parameters.
  702. // L is a diagonal matrix with non-negative matrix elements having the same
  703. // dimension as A, Wi ? 0. The diagonal elements of L are the singular values of matrix A.
  704. //singularity threshold
  705. double e = this.Threshold;
  706. double[] Y = value;
  707. // Create L*, which is a diagonal matrix with elements
  708. // L*i = 1/Li if Li = e, else 0,
  709. // where e is the so-called singularity threshold.
  710. // In other words, if Li is zero or close to zero (smaller than e),
  711. // one must replace 1/Li with 0. The value of e depends on the precision
  712. // of the hardware. This method can be used to solve linear equations
  713. // systems even if the matrices are singular or close to singular.
  714. int scols = s.Length;
  715. double[,] Ls = new double[scols, scols];
  716. for (int i = 0; i < s.Length; i++)
  717. {
  718. if (System.Math.Abs(s[i]) <= e)
  719. Ls[i, i] = 0;
  720. else Ls[i, i] = 1.0 / s[i];
  721. }
  722. //(V x L*) x Ut x Y
  723. double[,] VL = v.Multiply(Ls);
  724. //(V x L* x Ut) x Y
  725. int urows = u.GetLength(0);
  726. int vrows = v.GetLength(0);
  727. double[,] VLU = new double[vrows, urows];
  728. for (int i = 0; i < vrows; i++)
  729. {
  730. for (int j = 0; j < urows; j++)
  731. {
  732. double sum = 0;
  733. for (int k = 0; k < scols; k++)
  734. sum += VL[i, k] * u[j, k];
  735. VLU[i, j] = sum;
  736. }
  737. }
  738. //(V x L* x Ut x Y)
  739. return VLU.Multiply(Y);
  740. }
  741. /// <summary>
  742. /// Computes the (pseudo-)inverse of the matrix given to the Singular value decomposition.
  743. /// </summary>
  744. public double[,] Inverse()
  745. {
  746. double e = this.Threshold;
  747. // X = V*S^-1
  748. int vrows = v.GetLength(0);
  749. int vcols = v.GetLength(1);
  750. double[,] X = new double[vrows, s.Length];
  751. for (int i = 0; i < vrows; i++)
  752. {
  753. for (int j = 0; j < vcols; j++)
  754. {
  755. if (System.Math.Abs(s[j]) > e)
  756. X[i, j] = v[i, j] / s[j];
  757. }
  758. }
  759. // Y = X*U'
  760. int urows = u.GetLength(0);
  761. int ucols = u.GetLength(1);
  762. double[,] Y = new double[vrows, urows];
  763. for (int i = 0; i < vrows; i++)
  764. {
  765. for (int j = 0; j < urows; j++)
  766. {
  767. double sum = 0;
  768. for (int k = 0; k < ucols; k++)
  769. sum += X[i, k] * u[j, k];
  770. Y[i, j] = sum;
  771. }
  772. }
  773. return Y;
  774. }
  775. }
  776. }