GeneralizedEigenvalueDecomposition.cs 44 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. namespace VisualMath.Accord.Math.Decompositions
  7. {
  8. using System;
  9. using VisualMath.Accord.Math;
  10. /// <summary>
  11. /// Determines the Generalized eigenvalues and eigenvectors of two real square matrices.
  12. /// </summary>
  13. /// <remarks>
  14. /// <para>
  15. /// A generalized eigenvalue problem is the problem of finding a vector <c>v</c> that
  16. /// obeys <c>A * v = λ * B * v</c> where <c>A</c> and <c>B</c> are matrices. If <c>v</c>
  17. /// obeys this equation, with some <c>λ</c>, then we call <c>v</c> the generalized eigenvector
  18. /// of <c>A</c> and <c>B</c>, and <c>λ</c> is called the generalized eigenvalue of <c>A</c>
  19. /// and <c>B</c> which corresponds to the generalized eigenvector <c>v</c>. The possible
  20. /// values of <c>λ</c>, must obey the identity <c>det(A - λ*B) = 0</c>.</para>
  21. /// <para>
  22. /// Part of this code has been adapted from the original EISPACK routines in Fortran.</para>
  23. ///
  24. /// <para>
  25. /// References:
  26. /// <list type="bullet">
  27. /// <item><description>
  28. /// <a href="http://en.wikipedia.org/wiki/Generalized_eigenvalue_problem#Generalized_eigenvalue_problem">
  29. /// http://en.wikipedia.org/wiki/Generalized_eigenvalue_problem#Generalized_eigenvalue_problem</a>
  30. /// </description></item>
  31. /// <item><description>
  32. /// <a href="http://www.netlib.org/eispack/">
  33. /// http://www.netlib.org/eispack/</a>
  34. /// </description></item>
  35. /// </list>
  36. /// </para>
  37. /// </remarks>
  38. public sealed class GeneralizedEigenvalueDecomposition
  39. {
  40. private int n;
  41. private double[] ar;
  42. private double[] ai;
  43. private double[] beta;
  44. private double[,] Z;
  45. /// <summary>Construct a generalized eigenvalue decomposition.</summary>
  46. /// <param name="a">The first matrix of the (A,B) matrix pencil.</param>
  47. /// <param name="b">The second matrix of the (A,B) matrix pencil.</param>
  48. public GeneralizedEigenvalueDecomposition(double[,] a, double[,] b)
  49. {
  50. if (a == null)
  51. throw new ArgumentNullException("a", "Matrix A cannot be null.");
  52. if (b == null)
  53. throw new ArgumentNullException("b", "Matrix B cannot be null.");
  54. if (a.GetLength(0) != a.GetLength(1))
  55. throw new ArgumentException("Matrix is not a square matrix.", "a");
  56. if (b.GetLength(0) != b.GetLength(1))
  57. throw new ArgumentException("Matrix is not a square matrix.", "b");
  58. if (a.GetLength(0) != b.GetLength(0) || a.GetLength(1) != b.GetLength(1))
  59. throw new ArgumentException("Matrix dimensions do not match", "b");
  60. n = a.GetLength(0);
  61. ar = new double[n];
  62. ai = new double[n];
  63. beta = new double[n];
  64. Z = new double[n, n];
  65. var A = (double[,])a.Clone();
  66. var B = (double[,])b.Clone();
  67. bool matz = true;
  68. int ierr = 0;
  69. // reduces A to upper hessenberg form and B to upper
  70. // triangular form using orthogonal transformations
  71. qzhes(n, A, B, matz, Z);
  72. // reduces the hessenberg matrix A to quasi-triangular form
  73. // using orthogonal transformations while maintaining the
  74. // triangular form of the B matrix.
  75. qzit(n, A, B, Special.DoubleEpsilon, matz, Z, ref ierr);
  76. // reduces the quasi-triangular matrix further, so that any
  77. // remaining 2-by-2 blocks correspond to pairs of complex
  78. // eigenvalues, and returns quantities whose ratios give the
  79. // generalized eigenvalues.
  80. qzval(n, A, B, ar, ai, beta, matz, Z);
  81. // computes the eigenvectors of the triangular problem and
  82. // transforms the results back to the original coordinate system.
  83. qzvec(n, A, B, ar, ai, beta, Z);
  84. }
  85. /// <summary>Returns the real parts of the alpha values.</summary>
  86. public double[] RealAlphas
  87. {
  88. get { return ar; }
  89. }
  90. /// <summary>Returns the imaginary parts of the alpha values.</summary>
  91. public double[] ImaginaryAlphas
  92. {
  93. get { return ai; }
  94. }
  95. /// <summary>Returns the beta values.</summary>
  96. public double[] Betas
  97. {
  98. get { return beta; }
  99. }
  100. /// <summary>
  101. /// Returns true if matrix B is singular.
  102. /// </summary>
  103. /// <remarks>
  104. /// This method checks if any of the generated betas is zero. It
  105. /// does not says that the problem is singular, but only that one
  106. /// of the matrices of the pencil (A,B) is singular.
  107. /// </remarks>
  108. public bool IsSingular
  109. {
  110. get
  111. {
  112. for (int i = 0; i < n; i++)
  113. if (beta[i] == 0)
  114. return true;
  115. return false;
  116. }
  117. }
  118. /// <summary>
  119. /// Returns true if the eigenvalue problem is degenerate (ill-posed).
  120. /// </summary>
  121. public bool IsDegenerate
  122. {
  123. get
  124. {
  125. for (int i = 0; i < n; i++)
  126. if (beta[i] == 0 && ar[i] == 0)
  127. return true;
  128. return false;
  129. }
  130. }
  131. /// <summary>Returns the real parts of the eigenvalues.</summary>
  132. /// <remarks>
  133. /// The eigenvalues are computed using the ratio alpha[i]/beta[i],
  134. /// which can lead to valid, but infinite eigenvalues.
  135. /// </remarks>
  136. public double[] RealEigenvalues
  137. {
  138. get
  139. {
  140. // ((alfr+i*alfi)/beta)
  141. double[] eval = new double[n];
  142. for (int i = 0; i < n; i++)
  143. eval[i] = ar[i] / beta[i];
  144. return eval;
  145. }
  146. }
  147. /// <summary>Returns the imaginary parts of the eigenvalues.</summary>
  148. /// <remarks>
  149. /// The eigenvalues are computed using the ratio alpha[i]/beta[i],
  150. /// which can lead to valid, but infinite eigenvalues.
  151. /// </remarks>
  152. public double[] ImaginaryEigenvalues
  153. {
  154. get
  155. {
  156. // ((alfr+i*alfi)/beta)
  157. double[] eval = new double[n];
  158. for (int i = 0; i < n; i++)
  159. eval[i] = ai[i] / beta[i];
  160. return eval;
  161. }
  162. }
  163. /// <summary>Returns the eigenvector matrix.</summary>
  164. public double[,] Eigenvectors
  165. {
  166. get
  167. {
  168. return Z;
  169. }
  170. }
  171. /// <summary>Returns the block diagonal eigenvalue matrix.</summary>
  172. public double[,] DiagonalMatrix
  173. {
  174. get
  175. {
  176. double[,] x = new double[n, n];
  177. for (int i = 0; i < n; i++)
  178. {
  179. for (int j = 0; j < n; j++)
  180. x[i, j] = 0.0;
  181. x[i, i] = ar[i] / beta[i];
  182. if (ai[i] > 0)
  183. x[i, i + 1] = ai[i] / beta[i];
  184. else if (ai[i] < 0)
  185. x[i, i - 1] = ai[i] / beta[i];
  186. }
  187. return x;
  188. }
  189. }
  190. #region EISPACK Routines
  191. /// <summary>
  192. /// Adaptation of the original Fortran QZHES routine from EISPACK.
  193. /// </summary>
  194. /// <remarks>
  195. /// This subroutine is the first step of the qz algorithm
  196. /// for solving generalized matrix eigenvalue problems,
  197. /// siam j. numer. anal. 10, 241-256(1973) by moler and stewart.
  198. ///
  199. /// This subroutine accepts a pair of real general matrices and
  200. /// reduces one of them to upper hessenberg form and the other
  201. /// to upper triangular form using orthogonal transformations.
  202. /// it is usually followed by qzit, qzval and, possibly, qzvec.
  203. ///
  204. /// For the full documentation, please check the original function.
  205. /// </remarks>
  206. private static int qzhes(int n, double[,] a, double[,] b, bool matz, double[,] z)
  207. {
  208. int i, j, k, l;
  209. double r, s, t;
  210. int l1;
  211. double u1, u2, v1, v2;
  212. int lb, nk1;
  213. double rho;
  214. if (matz)
  215. {
  216. // If we are interested in computing the
  217. // eigenvectors, set Z to identity(n,n)
  218. for (j = 0; j < n; ++j)
  219. {
  220. for (i = 0; i < n; ++i)
  221. z[i, j] = 0.0;
  222. z[j, j] = 1.0;
  223. }
  224. }
  225. // Reduce b to upper triangular form
  226. if (n <= 1) return 0;
  227. for (l = 0; l < n - 1; ++l)
  228. {
  229. l1 = l + 1;
  230. s = 0.0;
  231. for (i = l1; i < n; ++i)
  232. s += (System.Math.Abs(b[i, l]));
  233. if (s == 0.0) continue;
  234. s += (System.Math.Abs(b[l, l]));
  235. r = 0.0;
  236. for (i = l; i < n; ++i)
  237. {
  238. // Computing 2nd power
  239. b[i, l] /= s;
  240. r += b[i, l] * b[i, l];
  241. }
  242. r = Special.Sign(System.Math.Sqrt(r), b[l, l]);
  243. b[l, l] += r;
  244. rho = r * b[l, l];
  245. for (j = l1; j < n; ++j)
  246. {
  247. t = 0.0;
  248. for (i = l; i < n; ++i)
  249. t += b[i, l] * b[i, j];
  250. t = -t / rho;
  251. for (i = l; i < n; ++i)
  252. b[i, j] += t * b[i, l];
  253. }
  254. for (j = 0; j < n; ++j)
  255. {
  256. t = 0.0;
  257. for (i = l; i < n; ++i)
  258. t += b[i, l] * a[i, j];
  259. t = -t / rho;
  260. for (i = l; i < n; ++i)
  261. a[i, j] += t * b[i, l];
  262. }
  263. b[l, l] = -s * r;
  264. for (i = l1; i < n; ++i)
  265. b[i, l] = 0.0;
  266. }
  267. // Reduce a to upper hessenberg form, while keeping b triangular
  268. if (n == 2) return 0;
  269. for (k = 0; k < n - 2; ++k)
  270. {
  271. nk1 = n - 2 - k;
  272. // for l=n-1 step -1 until k+1 do
  273. for (lb = 0; lb < nk1; ++lb)
  274. {
  275. l = n - lb - 2;
  276. l1 = l + 1;
  277. // Zero a(l+1,k)
  278. s = (System.Math.Abs(a[l, k])) + (System.Math.Abs(a[l1, k]));
  279. if (s == 0.0) continue;
  280. u1 = a[l, k] / s;
  281. u2 = a[l1, k] / s;
  282. r = Special.Sign(Math.Sqrt(u1 * u1 + u2 * u2), u1);
  283. v1 = -(u1 + r) / r;
  284. v2 = -u2 / r;
  285. u2 = v2 / v1;
  286. for (j = k; j < n; ++j)
  287. {
  288. t = a[l, j] + u2 * a[l1, j];
  289. a[l, j] += t * v1;
  290. a[l1, j] += t * v2;
  291. }
  292. a[l1, k] = 0.0;
  293. for (j = l; j < n; ++j)
  294. {
  295. t = b[l, j] + u2 * b[l1, j];
  296. b[l, j] += t * v1;
  297. b[l1, j] += t * v2;
  298. }
  299. // Zero b(l+1,l)
  300. s = (System.Math.Abs(b[l1, l1])) + (System.Math.Abs(b[l1, l]));
  301. if (s == 0.0) continue;
  302. u1 = b[l1, l1] / s;
  303. u2 = b[l1, l] / s;
  304. r = Special.Sign(Math.Sqrt(u1 * u1 + u2 * u2), u1);
  305. v1 = -(u1 + r) / r;
  306. v2 = -u2 / r;
  307. u2 = v2 / v1;
  308. for (i = 0; i <= l1; ++i)
  309. {
  310. t = b[i, l1] + u2 * b[i, l];
  311. b[i, l1] += t * v1;
  312. b[i, l] += t * v2;
  313. }
  314. b[l1, l] = 0.0;
  315. for (i = 0; i < n; ++i)
  316. {
  317. t = a[i, l1] + u2 * a[i, l];
  318. a[i, l1] += t * v1;
  319. a[i, l] += t * v2;
  320. }
  321. if (matz)
  322. {
  323. for (i = 0; i < n; ++i)
  324. {
  325. t = z[i, l1] + u2 * z[i, l];
  326. z[i, l1] += t * v1;
  327. z[i, l] += t * v2;
  328. }
  329. }
  330. }
  331. }
  332. return 0;
  333. }
  334. /// <summary>
  335. /// Adaptation of the original Fortran QZIT routine from EISPACK.
  336. /// </summary>
  337. /// <remarks>
  338. /// This subroutine is the second step of the qz algorithm
  339. /// for solving generalized matrix eigenvalue problems,
  340. /// siam j. numer. anal. 10, 241-256(1973) by moler and stewart,
  341. /// as modified in technical note nasa tn d-7305(1973) by ward.
  342. ///
  343. /// This subroutine accepts a pair of real matrices, one of them
  344. /// in upper hessenberg form and the other in upper triangular form.
  345. /// it reduces the hessenberg matrix to quasi-triangular form using
  346. /// orthogonal transformations while maintaining the triangular form
  347. /// of the other matrix. it is usually preceded by qzhes and
  348. /// followed by qzval and, possibly, qzvec.
  349. ///
  350. /// For the full documentation, please check the original function.
  351. /// </remarks>
  352. private static int qzit(int n, double[,] a, double[,] b, double eps1, bool matz, double[,] z, ref int ierr)
  353. {
  354. int i, j, k, l = 0;
  355. double r, s, t, a1, a2, a3 = 0;
  356. int k1, k2, l1, ll;
  357. double u1, u2, u3;
  358. double v1, v2, v3;
  359. double a11, a12, a21, a22, a33, a34, a43, a44;
  360. double b11, b12, b22, b33, b34, b44;
  361. int na, en, ld;
  362. double ep;
  363. double sh = 0;
  364. int km1, lm1 = 0;
  365. double ani, bni;
  366. int ish, itn, its, enm2, lor1;
  367. double epsa, epsb, anorm = 0, bnorm = 0;
  368. int enorn;
  369. bool notlas;
  370. ierr = 0;
  371. #region Compute epsa and epsb
  372. for (i = 0; i < n; ++i)
  373. {
  374. ani = 0.0;
  375. bni = 0.0;
  376. if (i != 0)
  377. ani = (Math.Abs(a[i, (i - 1)]));
  378. for (j = i; j < n; ++j)
  379. {
  380. ani += Math.Abs(a[i, j]);
  381. bni += Math.Abs(b[i, j]);
  382. }
  383. if (ani > anorm) anorm = ani;
  384. if (bni > bnorm) bnorm = bni;
  385. }
  386. if (anorm == 0.0) anorm = 1.0;
  387. if (bnorm == 0.0) bnorm = 1.0;
  388. ep = eps1;
  389. if (ep == 0.0)
  390. {
  391. // Use roundoff level if eps1 is zero
  392. ep = Special.Epslon(1.0);
  393. }
  394. epsa = ep * anorm;
  395. epsb = ep * bnorm;
  396. #endregion
  397. // Reduce a to quasi-triangular form, while keeping b triangular
  398. lor1 = 0;
  399. enorn = n;
  400. en = n - 1;
  401. itn = n * 30;
  402. // Begin QZ step
  403. L60:
  404. if (en <= 1) goto L1001;
  405. if (!matz) enorn = en + 1;
  406. its = 0;
  407. na = en - 1;
  408. enm2 = na;
  409. L70:
  410. ish = 2;
  411. // Check for convergence or reducibility.
  412. for (ll = 0; ll <= en; ++ll)
  413. {
  414. lm1 = en - ll - 1;
  415. l = lm1 + 1;
  416. if (l + 1 == 1)
  417. goto L95;
  418. if ((Math.Abs(a[l, lm1])) <= epsa)
  419. break;
  420. }
  421. L90:
  422. a[l, lm1] = 0.0;
  423. if (l < na) goto L95;
  424. // 1-by-1 or 2-by-2 block isolated
  425. en = lm1;
  426. goto L60;
  427. // Check for small top of b
  428. L95:
  429. ld = l;
  430. L100:
  431. l1 = l + 1;
  432. b11 = b[l, l];
  433. if (Math.Abs(b11) > epsb) goto L120;
  434. b[l, l] = 0.0;
  435. s = (Math.Abs(a[l, l]) + Math.Abs(a[l1, l]));
  436. u1 = a[l, l] / s;
  437. u2 = a[l1, l] / s;
  438. r = Special.Sign(Math.Sqrt(u1 * u1 + u2 * u2), u1);
  439. v1 = -(u1 + r) / r;
  440. v2 = -u2 / r;
  441. u2 = v2 / v1;
  442. for (j = l; j < enorn; ++j)
  443. {
  444. t = a[l, j] + u2 * a[l1, j];
  445. a[l, j] += t * v1;
  446. a[l1, j] += t * v2;
  447. t = b[l, j] + u2 * b[l1, j];
  448. b[l, j] += t * v1;
  449. b[l1, j] += t * v2;
  450. }
  451. if (l != 0)
  452. a[l, lm1] = -a[l, lm1];
  453. lm1 = l;
  454. l = l1;
  455. goto L90;
  456. L120:
  457. a11 = a[l, l] / b11;
  458. a21 = a[l1, l] / b11;
  459. if (ish == 1) goto L140;
  460. // Iteration strategy
  461. if (itn == 0) goto L1000;
  462. if (its == 10) goto L155;
  463. // Determine type of shift
  464. b22 = b[l1, l1];
  465. if (Math.Abs(b22) < epsb) b22 = epsb;
  466. b33 = b[na, na];
  467. if (Math.Abs(b33) < epsb) b33 = epsb;
  468. b44 = b[en, en];
  469. if (Math.Abs(b44) < epsb) b44 = epsb;
  470. a33 = a[na, na] / b33;
  471. a34 = a[na, en] / b44;
  472. a43 = a[en, na] / b33;
  473. a44 = a[en, en] / b44;
  474. b34 = b[na, en] / b44;
  475. t = (a43 * b34 - a33 - a44) * .5;
  476. r = t * t + a34 * a43 - a33 * a44;
  477. if (r < 0.0) goto L150;
  478. // Determine single shift zeroth column of a
  479. ish = 1;
  480. r = Math.Sqrt(r);
  481. sh = -t + r;
  482. s = -t - r;
  483. if (Math.Abs(s - a44) < Math.Abs(sh - a44))
  484. sh = s;
  485. // Look for two consecutive small sub-diagonal elements of a.
  486. for (ll = ld; ll + 1 <= enm2; ++ll)
  487. {
  488. l = enm2 + ld - ll - 1;
  489. if (l == ld)
  490. goto L140;
  491. lm1 = l - 1;
  492. l1 = l + 1;
  493. t = a[l + 1, l + 1];
  494. if (Math.Abs(b[l, l]) > epsb)
  495. t -= sh * b[l, l];
  496. if (Math.Abs(a[l, lm1]) <= (Math.Abs(t / a[l1, l])) * epsa)
  497. goto L100;
  498. }
  499. L140:
  500. a1 = a11 - sh;
  501. a2 = a21;
  502. if (l != ld)
  503. a[l, lm1] = -a[l, lm1];
  504. goto L160;
  505. // Determine double shift zeroth column of a
  506. L150:
  507. a12 = a[l, l1] / b22;
  508. a22 = a[l1, l1] / b22;
  509. b12 = b[l, l1] / b22;
  510. a1 = ((a33 - a11) * (a44 - a11) - a34 * a43 + a43 * b34 * a11) / a21 + a12 - a11 * b12;
  511. a2 = a22 - a11 - a21 * b12 - (a33 - a11) - (a44 - a11) + a43 * b34;
  512. a3 = a[l1 + 1, l1] / b22;
  513. goto L160;
  514. // Ad hoc shift
  515. L155:
  516. a1 = 0.0;
  517. a2 = 1.0;
  518. a3 = 1.1605;
  519. L160:
  520. ++its;
  521. --itn;
  522. if (!matz) lor1 = ld;
  523. // Main loop
  524. for (k = l; k <= na; ++k)
  525. {
  526. notlas = k != na && ish == 2;
  527. k1 = k + 1;
  528. k2 = k + 2;
  529. km1 = Math.Max(k, l + 1) - 1; // Computing MAX
  530. ll = Math.Min(en, k1 + ish); // Computing MIN
  531. if (notlas) goto L190;
  532. // Zero a(k+1,k-1)
  533. if (k == l) goto L170;
  534. a1 = a[k, km1];
  535. a2 = a[k1, km1];
  536. L170:
  537. s = Math.Abs(a1) + Math.Abs(a2);
  538. if (s == 0.0) goto L70;
  539. u1 = a1 / s;
  540. u2 = a2 / s;
  541. r = Special.Sign(Math.Sqrt(u1 * u1 + u2 * u2), u1);
  542. v1 = -(u1 + r) / r;
  543. v2 = -u2 / r;
  544. u2 = v2 / v1;
  545. for (j = km1; j < enorn; ++j)
  546. {
  547. t = a[k, j] + u2 * a[k1, j];
  548. a[k, j] += t * v1;
  549. a[k1, j] += t * v2;
  550. t = b[k, j] + u2 * b[k1, j];
  551. b[k, j] += t * v1;
  552. b[k1, j] += t * v2;
  553. }
  554. if (k != l)
  555. a[k1, km1] = 0.0;
  556. goto L240;
  557. // Zero a(k+1,k-1) and a(k+2,k-1)
  558. L190:
  559. if (k == l) goto L200;
  560. a1 = a[k, km1];
  561. a2 = a[k1, km1];
  562. a3 = a[k2, km1];
  563. L200:
  564. s = Math.Abs(a1) + Math.Abs(a2) + Math.Abs(a3);
  565. if (s == 0.0) goto L260;
  566. u1 = a1 / s;
  567. u2 = a2 / s;
  568. u3 = a3 / s;
  569. r = Special.Sign(Math.Sqrt(u1 * u1 + u2 * u2 + u3 * u3), u1);
  570. v1 = -(u1 + r) / r;
  571. v2 = -u2 / r;
  572. v3 = -u3 / r;
  573. u2 = v2 / v1;
  574. u3 = v3 / v1;
  575. for (j = km1; j < enorn; ++j)
  576. {
  577. t = a[k, j] + u2 * a[k1, j] + u3 * a[k2, j];
  578. a[k, j] += t * v1;
  579. a[k1, j] += t * v2;
  580. a[k2, j] += t * v3;
  581. t = b[k, j] + u2 * b[k1, j] + u3 * b[k2, j];
  582. b[k, j] += t * v1;
  583. b[k1, j] += t * v2;
  584. b[k2, j] += t * v3;
  585. }
  586. if (k == l) goto L220;
  587. a[k1, km1] = 0.0;
  588. a[k2, km1] = 0.0;
  589. // Zero b(k+2,k+1) and b(k+2,k)
  590. L220:
  591. s = (Math.Abs(b[k2, k2])) + (Math.Abs(b[k2, k1])) + (Math.Abs(b[k2, k]));
  592. if (s == 0.0) goto L240;
  593. u1 = b[k2, k2] / s;
  594. u2 = b[k2, k1] / s;
  595. u3 = b[k2, k] / s;
  596. r = Special.Sign(Math.Sqrt(u1 * u1 + u2 * u2 + u3 * u3), u1);
  597. v1 = -(u1 + r) / r;
  598. v2 = -u2 / r;
  599. v3 = -u3 / r;
  600. u2 = v2 / v1;
  601. u3 = v3 / v1;
  602. for (i = lor1; i < ll + 1; ++i)
  603. {
  604. t = a[i, k2] + u2 * a[i, k1] + u3 * a[i, k];
  605. a[i, k2] += t * v1;
  606. a[i, k1] += t * v2;
  607. a[i, k] += t * v3;
  608. t = b[i, k2] + u2 * b[i, k1] + u3 * b[i, k];
  609. b[i, k2] += t * v1;
  610. b[i, k1] += t * v2;
  611. b[i, k] += t * v3;
  612. }
  613. b[k2, k] = 0.0;
  614. b[k2, k1] = 0.0;
  615. if (matz)
  616. {
  617. for (i = 0; i < n; ++i)
  618. {
  619. t = z[i, k2] + u2 * z[i, k1] + u3 * z[i, k];
  620. z[i, k2] += t * v1;
  621. z[i, k1] += t * v2;
  622. z[i, k] += t * v3;
  623. }
  624. }
  625. // Zero b(k+1,k)
  626. L240:
  627. s = (Math.Abs(b[k1, k1])) + (Math.Abs(b[k1, k]));
  628. if (s == 0.0) goto L260;
  629. u1 = b[k1, k1] / s;
  630. u2 = b[k1, k] / s;
  631. r = Special.Sign(Math.Sqrt(u1 * u1 + u2 * u2), u1);
  632. v1 = -(u1 + r) / r;
  633. v2 = -u2 / r;
  634. u2 = v2 / v1;
  635. for (i = lor1; i < ll + 1; ++i)
  636. {
  637. t = a[i, k1] + u2 * a[i, k];
  638. a[i, k1] += t * v1;
  639. a[i, k] += t * v2;
  640. t = b[i, k1] + u2 * b[i, k];
  641. b[i, k1] += t * v1;
  642. b[i, k] += t * v2;
  643. }
  644. b[k1, k] = 0.0;
  645. if (matz)
  646. {
  647. for (i = 0; i < n; ++i)
  648. {
  649. t = z[i, k1] + u2 * z[i, k];
  650. z[i, k1] += t * v1;
  651. z[i, k] += t * v2;
  652. }
  653. }
  654. L260:
  655. ;
  656. }
  657. goto L70; // End QZ step
  658. // Set error -- all eigenvalues have not converged after 30*n iterations
  659. L1000:
  660. ierr = en + 1;
  661. // Save epsb for use by qzval and qzvec
  662. L1001:
  663. if (n > 1)
  664. b[n - 1, 0] = epsb;
  665. return 0;
  666. }
  667. /// <summary>
  668. /// Adaptation of the original Fortran QZVAL routine from EISPACK.
  669. /// </summary>
  670. /// <remarks>
  671. /// This subroutine is the third step of the qz algorithm
  672. /// for solving generalized matrix eigenvalue problems,
  673. /// siam j. numer. anal. 10, 241-256(1973) by moler and stewart.
  674. ///
  675. /// This subroutine accepts a pair of real matrices, one of them
  676. /// in quasi-triangular form and the other in upper triangular form.
  677. /// it reduces the quasi-triangular matrix further, so that any
  678. /// remaining 2-by-2 blocks correspond to pairs of complex
  679. /// eigenvalues, and returns quantities whose ratios give the
  680. /// generalized eigenvalues. it is usually preceded by qzhes
  681. /// and qzit and may be followed by qzvec.
  682. ///
  683. /// For the full documentation, please check the original function.
  684. /// </remarks>
  685. private static int qzval(int n, double[,] a, double[,] b, double[] alfr, double[] alfi, double[] beta, bool matz, double[,] z)
  686. {
  687. int i, j;
  688. int na, en, nn;
  689. double c, d, e = 0;
  690. double r, s, t;
  691. double a1, a2, u1, u2, v1, v2;
  692. double a11, a12, a21, a22;
  693. double b11, b12, b22;
  694. double di, ei;
  695. double an = 0, bn;
  696. double cq, dr;
  697. double cz, ti, tr;
  698. double a1i, a2i, a11i, a12i, a22i, a11r, a12r, a22r;
  699. double sqi, ssi, sqr, szi, ssr, szr;
  700. double epsb = b[n - 1, 0];
  701. int isw = 1;
  702. // Find eigenvalues of quasi-triangular matrices.
  703. for (nn = 0; nn < n; ++nn)
  704. {
  705. en = n - nn - 1;
  706. na = en - 1;
  707. if (isw == 2) goto L505;
  708. if (en == 0) goto L410;
  709. if (a[en, na] != 0.0) goto L420;
  710. // 1-by-1 block, one real root
  711. L410:
  712. alfr[en] = a[en, en];
  713. if (b[en, en] < 0.0)
  714. {
  715. alfr[en] = -alfr[en];
  716. }
  717. beta[en] = (Math.Abs(b[en, en]));
  718. alfi[en] = 0.0;
  719. goto L510;
  720. // 2-by-2 block
  721. L420:
  722. if (Math.Abs(b[na, na]) <= epsb) goto L455;
  723. if (Math.Abs(b[en, en]) > epsb) goto L430;
  724. a1 = a[en, en];
  725. a2 = a[en, na];
  726. bn = 0.0;
  727. goto L435;
  728. L430:
  729. an = Math.Abs(a[na, na]) + Math.Abs(a[na, en]) + Math.Abs(a[en, na]) + Math.Abs(a[en, en]);
  730. bn = Math.Abs(b[na, na]) + Math.Abs(b[na, en]) + Math.Abs(b[en, en]);
  731. a11 = a[na, na] / an;
  732. a12 = a[na, en] / an;
  733. a21 = a[en, na] / an;
  734. a22 = a[en, en] / an;
  735. b11 = b[na, na] / bn;
  736. b12 = b[na, en] / bn;
  737. b22 = b[en, en] / bn;
  738. e = a11 / b11;
  739. ei = a22 / b22;
  740. s = a21 / (b11 * b22);
  741. t = (a22 - e * b22) / b22;
  742. if (Math.Abs(e) <= Math.Abs(ei))
  743. goto L431;
  744. e = ei;
  745. t = (a11 - e * b11) / b11;
  746. L431:
  747. c = (t - s * b12) * .5;
  748. d = c * c + s * (a12 - e * b12);
  749. if (d < 0.0) goto L480;
  750. // Two real roots. Zero both a(en,na) and b(en,na)
  751. e += c + Special.Sign(Math.Sqrt(d), c);
  752. a11 -= e * b11;
  753. a12 -= e * b12;
  754. a22 -= e * b22;
  755. if (Math.Abs(a11) + Math.Abs(a12) < Math.Abs(a21) + Math.Abs(a22))
  756. goto L432;
  757. a1 = a12;
  758. a2 = a11;
  759. goto L435;
  760. L432:
  761. a1 = a22;
  762. a2 = a21;
  763. // Choose and apply real z
  764. L435:
  765. s = Math.Abs(a1) + Math.Abs(a2);
  766. u1 = a1 / s;
  767. u2 = a2 / s;
  768. r = Special.Sign(Math.Sqrt(u1 * u1 + u2 * u2), u1);
  769. v1 = -(u1 + r) / r;
  770. v2 = -u2 / r;
  771. u2 = v2 / v1;
  772. for (i = 0; i <= en; ++i)
  773. {
  774. t = a[i, en] + u2 * a[i, na];
  775. a[i, en] += t * v1;
  776. a[i, na] += t * v2;
  777. t = b[i, en] + u2 * b[i, na];
  778. b[i, en] += t * v1;
  779. b[i, na] += t * v2;
  780. }
  781. if (matz)
  782. {
  783. for (i = 0; i < n; ++i)
  784. {
  785. t = z[i, en] + u2 * z[i, na];
  786. z[i, en] += t * v1;
  787. z[i, na] += t * v2;
  788. }
  789. }
  790. if (bn == 0.0) goto L475;
  791. if (an < System.Math.Abs(e) * bn) goto L455;
  792. a1 = b[na, na];
  793. a2 = b[en, na];
  794. goto L460;
  795. L455:
  796. a1 = a[na, na];
  797. a2 = a[en, na];
  798. // Choose and apply real q
  799. L460:
  800. s = System.Math.Abs(a1) + System.Math.Abs(a2);
  801. if (s == 0.0) goto L475;
  802. u1 = a1 / s;
  803. u2 = a2 / s;
  804. r = Special.Sign(Math.Sqrt(u1 * u1 + u2 * u2), u1);
  805. v1 = -(u1 + r) / r;
  806. v2 = -u2 / r;
  807. u2 = v2 / v1;
  808. for (j = na; j < n; ++j)
  809. {
  810. t = a[na, j] + u2 * a[en, j];
  811. a[na, j] += t * v1;
  812. a[en, j] += t * v2;
  813. t = b[na, j] + u2 * b[en, j];
  814. b[na, j] += t * v1;
  815. b[en, j] += t * v2;
  816. }
  817. L475:
  818. a[en, na] = 0.0;
  819. b[en, na] = 0.0;
  820. alfr[na] = a[na, na];
  821. alfr[en] = a[en, en];
  822. if (b[na, na] < 0.0)
  823. alfr[na] = -alfr[na];
  824. if (b[en, en] < 0.0)
  825. alfr[en] = -alfr[en];
  826. beta[na] = (System.Math.Abs(b[na, na]));
  827. beta[en] = (System.Math.Abs(b[en, en]));
  828. alfi[en] = 0.0;
  829. alfi[na] = 0.0;
  830. goto L505;
  831. // Two complex roots
  832. L480:
  833. e += c;
  834. ei = System.Math.Sqrt(-d);
  835. a11r = a11 - e * b11;
  836. a11i = ei * b11;
  837. a12r = a12 - e * b12;
  838. a12i = ei * b12;
  839. a22r = a22 - e * b22;
  840. a22i = ei * b22;
  841. if (System.Math.Abs(a11r) + System.Math.Abs(a11i) +
  842. System.Math.Abs(a12r) + System.Math.Abs(a12i) <
  843. System.Math.Abs(a21) + System.Math.Abs(a22r)
  844. + System.Math.Abs(a22i))
  845. goto L482;
  846. a1 = a12r;
  847. a1i = a12i;
  848. a2 = -a11r;
  849. a2i = -a11i;
  850. goto L485;
  851. L482:
  852. a1 = a22r;
  853. a1i = a22i;
  854. a2 = -a21;
  855. a2i = 0.0;
  856. // Choose complex z
  857. L485:
  858. cz = System.Math.Sqrt(a1 * a1 + a1i * a1i);
  859. if (cz == 0.0) goto L487;
  860. szr = (a1 * a2 + a1i * a2i) / cz;
  861. szi = (a1 * a2i - a1i * a2) / cz;
  862. r = System.Math.Sqrt(cz * cz + szr * szr + szi * szi);
  863. cz /= r;
  864. szr /= r;
  865. szi /= r;
  866. goto L490;
  867. L487:
  868. szr = 1.0;
  869. szi = 0.0;
  870. L490:
  871. if (an < (System.Math.Abs(e) + ei) * bn) goto L492;
  872. a1 = cz * b11 + szr * b12;
  873. a1i = szi * b12;
  874. a2 = szr * b22;
  875. a2i = szi * b22;
  876. goto L495;
  877. L492:
  878. a1 = cz * a11 + szr * a12;
  879. a1i = szi * a12;
  880. a2 = cz * a21 + szr * a22;
  881. a2i = szi * a22;
  882. // Choose complex q
  883. L495:
  884. cq = System.Math.Sqrt(a1 * a1 + a1i * a1i);
  885. if (cq == 0.0) goto L497;
  886. sqr = (a1 * a2 + a1i * a2i) / cq;
  887. sqi = (a1 * a2i - a1i * a2) / cq;
  888. r = System.Math.Sqrt(cq * cq + sqr * sqr + sqi * sqi);
  889. cq /= r;
  890. sqr /= r;
  891. sqi /= r;
  892. goto L500;
  893. L497:
  894. sqr = 1.0;
  895. sqi = 0.0;
  896. // Compute diagonal elements that would result if transformations were applied
  897. L500:
  898. ssr = sqr * szr + sqi * szi;
  899. ssi = sqr * szi - sqi * szr;
  900. i = 0;
  901. tr = cq * cz * a11 + cq * szr * a12 + sqr * cz * a21 + ssr * a22;
  902. ti = cq * szi * a12 - sqi * cz * a21 + ssi * a22;
  903. dr = cq * cz * b11 + cq * szr * b12 + ssr * b22;
  904. di = cq * szi * b12 + ssi * b22;
  905. goto L503;
  906. L502:
  907. i = 1;
  908. tr = ssr * a11 - sqr * cz * a12 - cq * szr * a21 + cq * cz * a22;
  909. ti = -ssi * a11 - sqi * cz * a12 + cq * szi * a21;
  910. dr = ssr * b11 - sqr * cz * b12 + cq * cz * b22;
  911. di = -ssi * b11 - sqi * cz * b12;
  912. L503:
  913. t = ti * dr - tr * di;
  914. j = na;
  915. if (t < 0.0)
  916. j = en;
  917. r = Math.Sqrt(dr * dr + di * di);
  918. beta[j] = bn * r;
  919. alfr[j] = an * (tr * dr + ti * di) / r;
  920. alfi[j] = an * t / r;
  921. if (i == 0) goto L502;
  922. L505:
  923. isw = 3 - isw;
  924. L510:
  925. ;
  926. }
  927. b[n - 1, 0] = epsb;
  928. return 0;
  929. }
  930. /// <summary>
  931. /// Adaptation of the original Fortran QZVEC routine from EISPACK.
  932. /// </summary>
  933. /// <remarks>
  934. /// This subroutine is the optional fourth step of the qz algorithm
  935. /// for solving generalized matrix eigenvalue problems,
  936. /// siam j. numer. anal. 10, 241-256(1973) by moler and stewart.
  937. ///
  938. /// This subroutine accepts a pair of real matrices, one of them in
  939. /// quasi-triangular form (in which each 2-by-2 block corresponds to
  940. /// a pair of complex eigenvalues) and the other in upper triangular
  941. /// form. It computes the eigenvectors of the triangular problem and
  942. /// transforms the results back to the original coordinate system.
  943. /// it is usually preceded by qzhes, qzit, and qzval.
  944. ///
  945. /// For the full documentation, please check the original function.
  946. /// </remarks>
  947. private static int qzvec(int n, double[,] a, double[,] b, double[] alfr, double[] alfi, double[] beta, double[,] z)
  948. {
  949. int i, j, k, m;
  950. int na, ii, en, jj, nn, enm2;
  951. double d, q;
  952. double r = 0, s = 0, t, w, x = 0, y, t1, t2, w1, x1 = 0, z1 = 0, di;
  953. double ra, dr, sa;
  954. double ti, rr, tr, zz = 0;
  955. double alfm, almi, betm, almr;
  956. double epsb = b[n - 1, 0];
  957. int isw = 1;
  958. // for en=n step -1 until 1 do --
  959. for (nn = 0; nn < n; ++nn)
  960. {
  961. en = n - nn - 1;
  962. na = en - 1;
  963. if (isw == 2) goto L795;
  964. if (alfi[en] != 0.0) goto L710;
  965. // Real vector
  966. m = en;
  967. b[en, en] = 1.0;
  968. if (na == -1) goto L800;
  969. alfm = alfr[m];
  970. betm = beta[m];
  971. // for i=en-1 step -1 until 1 do --
  972. for (ii = 0; ii <= na; ++ii)
  973. {
  974. i = en - ii - 1;
  975. w = betm * a[i, i] - alfm * b[i, i];
  976. r = 0.0;
  977. for (j = m; j <= en; ++j)
  978. r += (betm * a[i, j] - alfm * b[i, j]) * b[j, en];
  979. if (i == 0 || isw == 2)
  980. goto L630;
  981. if (betm * a[i, i - 1] == 0.0)
  982. goto L630;
  983. zz = w;
  984. s = r;
  985. goto L690;
  986. L630:
  987. m = i;
  988. if (isw == 2) goto L640;
  989. // Real 1-by-1 block
  990. t = w;
  991. if (w == 0.0)
  992. t = epsb;
  993. b[i, en] = -r / t;
  994. goto L700;
  995. // Real 2-by-2 block
  996. L640:
  997. x = betm * a[i, i + 1] - alfm * b[i, i + 1];
  998. y = betm * a[i + 1, i];
  999. q = w * zz - x * y;
  1000. t = (x * s - zz * r) / q;
  1001. b[i, en] = t;
  1002. if (Math.Abs(x) <= Math.Abs(zz)) goto L650;
  1003. b[i + 1, en] = (-r - w * t) / x;
  1004. goto L690;
  1005. L650:
  1006. b[i + 1, en] = (-s - y * t) / zz;
  1007. L690:
  1008. isw = 3 - isw;
  1009. L700:
  1010. ;
  1011. }
  1012. // End real vector
  1013. goto L800;
  1014. // Complex vector
  1015. L710:
  1016. m = na;
  1017. almr = alfr[m];
  1018. almi = alfi[m];
  1019. betm = beta[m];
  1020. // last vector component chosen imaginary so that eigenvector matrix is triangular
  1021. y = betm * a[en, na];
  1022. b[na, na] = -almi * b[en, en] / y;
  1023. b[na, en] = (almr * b[en, en] - betm * a[en, en]) / y;
  1024. b[en, na] = 0.0;
  1025. b[en, en] = 1.0;
  1026. enm2 = na;
  1027. if (enm2 == 0) goto L795;
  1028. // for i=en-2 step -1 until 1 do --
  1029. for (ii = 0; ii < enm2; ++ii)
  1030. {
  1031. i = na - ii - 1;
  1032. w = betm * a[i, i] - almr * b[i, i];
  1033. w1 = -almi * b[i, i];
  1034. ra = 0.0;
  1035. sa = 0.0;
  1036. for (j = m; j <= en; ++j)
  1037. {
  1038. x = betm * a[i, j] - almr * b[i, j];
  1039. x1 = -almi * b[i, j];
  1040. ra = ra + x * b[j, na] - x1 * b[j, en];
  1041. sa = sa + x * b[j, en] + x1 * b[j, na];
  1042. }
  1043. if (i == 0 || isw == 2) goto L770;
  1044. if (betm * a[i, i - 1] == 0.0) goto L770;
  1045. zz = w;
  1046. z1 = w1;
  1047. r = ra;
  1048. s = sa;
  1049. isw = 2;
  1050. goto L790;
  1051. L770:
  1052. m = i;
  1053. if (isw == 2) goto L780;
  1054. // Complex 1-by-1 block
  1055. tr = -ra;
  1056. ti = -sa;
  1057. L773:
  1058. dr = w;
  1059. di = w1;
  1060. // Complex divide (t1,t2) = (tr,ti) / (dr,di)
  1061. L775:
  1062. if (Math.Abs(di) > Math.Abs(dr)) goto L777;
  1063. rr = di / dr;
  1064. d = dr + di * rr;
  1065. t1 = (tr + ti * rr) / d;
  1066. t2 = (ti - tr * rr) / d;
  1067. switch (isw)
  1068. {
  1069. case 1: goto L787;
  1070. case 2: goto L782;
  1071. }
  1072. L777:
  1073. rr = dr / di;
  1074. d = dr * rr + di;
  1075. t1 = (tr * rr + ti) / d;
  1076. t2 = (ti * rr - tr) / d;
  1077. switch (isw)
  1078. {
  1079. case 1: goto L787;
  1080. case 2: goto L782;
  1081. }
  1082. // Complex 2-by-2 block
  1083. L780:
  1084. x = betm * a[i, i + 1] - almr * b[i, i + 1];
  1085. x1 = -almi * b[i, i + 1];
  1086. y = betm * a[i + 1, i];
  1087. tr = y * ra - w * r + w1 * s;
  1088. ti = y * sa - w * s - w1 * r;
  1089. dr = w * zz - w1 * z1 - x * y;
  1090. di = w * z1 + w1 * zz - x1 * y;
  1091. if (dr == 0.0 && di == 0.0)
  1092. dr = epsb;
  1093. goto L775;
  1094. L782:
  1095. b[i + 1, na] = t1;
  1096. b[i + 1, en] = t2;
  1097. isw = 1;
  1098. if (Math.Abs(y) > Math.Abs(w) + Math.Abs(w1))
  1099. goto L785;
  1100. tr = -ra - x * b[(i + 1), na] + x1 * b[(i + 1), en];
  1101. ti = -sa - x * b[(i + 1), en] - x1 * b[(i + 1), na];
  1102. goto L773;
  1103. L785:
  1104. t1 = (-r - zz * b[(i + 1), na] + z1 * b[(i + 1), en]) / y;
  1105. t2 = (-s - zz * b[(i + 1), en] - z1 * b[(i + 1), na]) / y;
  1106. L787:
  1107. b[i, na] = t1;
  1108. b[i, en] = t2;
  1109. L790:
  1110. ;
  1111. }
  1112. // End complex vector
  1113. L795:
  1114. isw = 3 - isw;
  1115. L800:
  1116. ;
  1117. }
  1118. // End back substitution. Transform to original coordinate system.
  1119. for (jj = 0; jj < n; ++jj)
  1120. {
  1121. j = n - jj - 1;
  1122. for (i = 0; i < n; ++i)
  1123. {
  1124. zz = 0.0;
  1125. for (k = 0; k <= j; ++k)
  1126. zz += z[i, k] * b[k, j];
  1127. z[i, j] = zz;
  1128. }
  1129. }
  1130. // Normalize so that modulus of largest component of each vector is 1.
  1131. // (isw is 1 initially from before)
  1132. for (j = 0; j < n; ++j)
  1133. {
  1134. d = 0.0;
  1135. if (isw == 2) goto L920;
  1136. if (alfi[j] != 0.0) goto L945;
  1137. for (i = 0; i < n; ++i)
  1138. {
  1139. if ((Math.Abs(z[i, j])) > d)
  1140. d = (Math.Abs(z[i, j]));
  1141. }
  1142. for (i = 0; i < n; ++i)
  1143. z[i, j] /= d;
  1144. goto L950;
  1145. L920:
  1146. for (i = 0; i < n; ++i)
  1147. {
  1148. r = System.Math.Abs(z[i, j - 1]) + System.Math.Abs(z[i, j]);
  1149. if (r != 0.0)
  1150. {
  1151. // Computing 2nd power
  1152. double u1 = z[i, j - 1] / r;
  1153. double u2 = z[i, j] / r;
  1154. r *= Math.Sqrt(u1 * u1 + u2 * u2);
  1155. }
  1156. if (r > d)
  1157. d = r;
  1158. }
  1159. for (i = 0; i < n; ++i)
  1160. {
  1161. z[i, j - 1] /= d;
  1162. z[i, j] /= d;
  1163. }
  1164. L945:
  1165. isw = 3 - isw;
  1166. L950:
  1167. ;
  1168. }
  1169. return 0;
  1170. }
  1171. #endregion
  1172. }
  1173. }