当前位置:   article > 正文

机器学习知识点(十九)矩阵特征值分解基础知识及Java实现_eigenvalue decomposition problem

eigenvalue decomposition problem

1、特征值分解基础知识

矩阵乘法Y=AB的数学意义在于变换,以其中一个向量A为中心,则B的作用主要是使A发生伸缩或旋转变换。一个矩阵其实就是一个线性变换,因为一个矩阵乘以一个向量后得到的向量,其实就相当于将这个向量进行了线性变换。

如果说一个向量v是方阵A的特征向量,将一定可以表示成下面的形式:


    这时候λ就被称为特征向量v对应的特征值,一个矩阵的一组特征向量是一组正交向量。特征值分解是将一个矩阵分解成下面的形式:


其中Q是这个矩阵A的特征向量组成的矩阵,Σ是一个对角阵,每一个对角线上的元素就是一个特征值。一个变换方阵的所有特征向量组成了这个变换矩阵的一组基。所谓基,可以理解为坐标系的轴。平常用到直角坐标系,在线性代数中可以把这个坐标系扭曲、拉伸、旋转,称为基变换。可以按需求去设定基,但是基的轴之间必须是线性无关的,也就是保证坐标系的不同轴不要指向同一个方向或可以被别的轴组合而成。从线性空间的角度看,在一个定义了内积的线性空间里,对一个N阶对称方阵进行特征分解,就是产生了该空间的N个标准正交基,然后把矩阵投影到这N个基上。N个特征向量就是N个标准正交基,而特征值的模则代表矩阵在每个基上的投影长度。特征值越大,说明矩阵在对应的特征向量上的方差越大,功率越大,信息量越多。不过,特征值分解也有很多的局限,比如说变换的矩阵必须是方阵。

机器学习特征提取中,意思就是最大特征值对应的特征向量方向上包含最多的信息量,如果某几个特征值很小,说明这几个方向信息量很小,可以用来降维,也就是删除小特征值对应方向的数据,只保留大特征值方向对应的数据,这样做以后数据量减小,但有用信息量变化不大,PCA降维就是基于这种思路。特征值分解可以得到特征值与特征向量,特征值表示的是这个特征到底有多重要,而特征向量表示这个特征是什么,可以将每一个特征向量理解为一个线性的子空间。

2、Java实现

http://math.nist.gov/javanumerics/jama/Java矩阵计算包,下载Jama-1.0.3.jar引入工程。

下载Jama-1.0.3.zip研究源码。

1)  特征值分解测试类

 

  1. package sk.ml;
  2. import Jama.EigenvalueDecomposition;
  3. import Jama.Matrix;
  4. public class QRTest {
  5. //矩阵特征分解
  6. public static void main(String argv[]){
  7. double[] columnwise = {1.,2.,3.,4.,5.,6.,7.,8.,9.,10.,11.,12.};
  8. Matrix A = new Matrix(columnwise,4);//构造矩阵
  9. A.print(A.getColumnDimension(), A.getRowDimension());
  10. EigenvalueDecomposition Eig = A.eig();
  11. Matrix D = Eig.getD();
  12. Matrix V = Eig.getV();
  13. D.print(D.getColumnDimension(), D.getRowDimension());//打印特征值
  14. V.print(V.getColumnDimension(), V.getRowDimension());//打印特征向量
  15. }
  16. }

 

2)  源码参考Matrix

 

  1. package Jama;
  2. import java.text.NumberFormat;
  3. import java.text.DecimalFormat;
  4. import java.text.DecimalFormatSymbols;
  5. import java.util.Locale;
  6. import java.text.FieldPosition;
  7. import java.io.PrintWriter;
  8. import java.io.BufferedReader;
  9. import java.io.StreamTokenizer;
  10. import Jama.util.*;
  11. /**
  12. Jama = Java Matrix class.
  13. <P>
  14. The Java Matrix Class provides the fundamental operations of numerical
  15. linear algebra. Various constructors create Matrices from two dimensional
  16. arrays of double precision floating point numbers. Various "gets" and
  17. "sets" provide access to submatrices and matrix elements. Several methods
  18. implement basic matrix arithmetic, including matrix addition and
  19. multiplication, matrix norms, and element-by-element array operations.
  20. Methods for reading and printing matrices are also included. All the
  21. operations in this version of the Matrix Class involve real matrices.
  22. Complex matrices may be handled in a future version.
  23. <P>
  24. Five fundamental matrix decompositions, which consist of pairs or triples
  25. of matrices, permutation vectors, and the like, produce results in five
  26. decomposition classes. These decompositions are accessed by the Matrix
  27. class to compute solutions of simultaneous linear equations, determinants,
  28. inverses and other matrix functions. The five decompositions are:
  29. <P><UL>
  30. <LI>Cholesky Decomposition of symmetric, positive definite matrices.
  31. <LI>LU Decomposition of rectangular matrices.
  32. <LI>QR Decomposition of rectangular matrices.
  33. <LI>Singular Value Decomposition of rectangular matrices.
  34. <LI>Eigenvalue Decomposition of both symmetric and nonsymmetric square matrices.
  35. </UL>
  36. <DL>
  37. <DT><B>Example of use:</B></DT>
  38. <P>
  39. <DD>Solve a linear system A x = b and compute the residual norm, ||b - A x||.
  40. <P><PRE>
  41. double[][] vals = {{1.,2.,3},{4.,5.,6.},{7.,8.,10.}};
  42. Matrix A = new Matrix(vals);
  43. Matrix b = Matrix.random(3,1);
  44. Matrix x = A.solve(b);
  45. Matrix r = A.times(x).minus(b);
  46. double rnorm = r.normInf();
  47. </PRE></DD>
  48. </DL>
  49. @author The MathWorks, Inc. and the National Institute of Standards and Technology.
  50. @version 5 August 1998
  51. */
  52. public class Matrix implements Cloneable, java.io.Serializable {
  53. /* ------------------------
  54. Class variables
  55. * ------------------------ */
  56. /** Array for internal storage of elements.
  57. @serial internal array storage.
  58. */
  59. private double[][] A;
  60. /** Row and column dimensions.
  61. @serial row dimension.
  62. @serial column dimension.
  63. */
  64. private int m, n;
  65. /* ------------------------
  66. Constructors
  67. * ------------------------ */
  68. /** Construct an m-by-n matrix of zeros.
  69. @param m Number of rows.
  70. @param n Number of colums.
  71. */
  72. public Matrix (int m, int n) {
  73. this.m = m;
  74. this.n = n;
  75. A = new double[m][n];
  76. }
  77. /** Construct an m-by-n constant matrix.
  78. @param m Number of rows.
  79. @param n Number of colums.
  80. @param s Fill the matrix with this scalar value.
  81. */
  82. public Matrix (int m, int n, double s) {
  83. this.m = m;
  84. this.n = n;
  85. A = new double[m][n];
  86. for (int i = 0; i < m; i++) {
  87. for (int j = 0; j < n; j++) {
  88. A[i][j] = s;
  89. }
  90. }
  91. }
  92. /** Construct a matrix from a 2-D array.
  93. @param A Two-dimensional array of doubles.
  94. @exception IllegalArgumentException All rows must have the same length
  95. @see #constructWithCopy
  96. */
  97. public Matrix (double[][] A) {
  98. m = A.length;
  99. n = A[0].length;
  100. for (int i = 0; i < m; i++) {
  101. if (A[i].length != n) {
  102. throw new IllegalArgumentException("All rows must have the same length.");
  103. }
  104. }
  105. this.A = A;
  106. }
  107. /** Construct a matrix quickly without checking arguments.
  108. @param A Two-dimensional array of doubles.
  109. @param m Number of rows.
  110. @param n Number of colums.
  111. */
  112. public Matrix (double[][] A, int m, int n) {
  113. this.A = A;
  114. this.m = m;
  115. this.n = n;
  116. }
  117. /** Construct a matrix from a one-dimensional packed array
  118. @param vals One-dimensional array of doubles, packed by columns (ala Fortran).
  119. @param m Number of rows.
  120. @exception IllegalArgumentException Array length must be a multiple of m.
  121. */
  122. public Matrix (double vals[], int m) {
  123. this.m = m;
  124. n = (m != 0 ? vals.length/m : 0);
  125. if (m*n != vals.length) {
  126. throw new IllegalArgumentException("Array length must be a multiple of m.");
  127. }
  128. A = new double[m][n];
  129. for (int i = 0; i < m; i++) {
  130. for (int j = 0; j < n; j++) {
  131. A[i][j] = vals[i+j*m];
  132. }
  133. }
  134. }
  135. /* ------------------------
  136. Public Methods
  137. * ------------------------ */
  138. /** Construct a matrix from a copy of a 2-D array.
  139. @param A Two-dimensional array of doubles.
  140. @exception IllegalArgumentException All rows must have the same length
  141. */
  142. public static Matrix constructWithCopy(double[][] A) {
  143. int m = A.length;
  144. int n = A[0].length;
  145. Matrix X = new Matrix(m,n);
  146. double[][] C = X.getArray();
  147. for (int i = 0; i < m; i++) {
  148. if (A[i].length != n) {
  149. throw new IllegalArgumentException
  150. ("All rows must have the same length.");
  151. }
  152. for (int j = 0; j < n; j++) {
  153. C[i][j] = A[i][j];
  154. }
  155. }
  156. return X;
  157. }
  158. /** Make a deep copy of a matrix
  159. */
  160. public Matrix copy () {
  161. Matrix X = new Matrix(m,n);
  162. double[][] C = X.getArray();
  163. for (int i = 0; i < m; i++) {
  164. for (int j = 0; j < n; j++) {
  165. C[i][j] = A[i][j];
  166. }
  167. }
  168. return X;
  169. }
  170. /** Clone the Matrix object.
  171. */
  172. public Object clone () {
  173. return this.copy();
  174. }
  175. /** Access the internal two-dimensional array.
  176. @return Pointer to the two-dimensional array of matrix elements.
  177. */
  178. public double[][] getArray () {
  179. return A;
  180. }
  181. /** Copy the internal two-dimensional array.
  182. @return Two-dimensional array copy of matrix elements.
  183. */
  184. public double[][] getArrayCopy () {
  185. double[][] C = new double[m][n];
  186. for (int i = 0; i < m; i++) {
  187. for (int j = 0; j < n; j++) {
  188. C[i][j] = A[i][j];
  189. }
  190. }
  191. return C;
  192. }
  193. /** Make a one-dimensional column packed copy of the internal array.
  194. @return Matrix elements packed in a one-dimensional array by columns.
  195. */
  196. public double[] getColumnPackedCopy () {
  197. double[] vals = new double[m*n];
  198. for (int i = 0; i < m; i++) {
  199. for (int j = 0; j < n; j++) {
  200. vals[i+j*m] = A[i][j];
  201. }
  202. }
  203. return vals;
  204. }
  205. /** Make a one-dimensional row packed copy of the internal array.
  206. @return Matrix elements packed in a one-dimensional array by rows.
  207. */
  208. public double[] getRowPackedCopy () {
  209. double[] vals = new double[m*n];
  210. for (int i = 0; i < m; i++) {
  211. for (int j = 0; j < n; j++) {
  212. vals[i*n+j] = A[i][j];
  213. }
  214. }
  215. return vals;
  216. }
  217. /** Get row dimension.
  218. @return m, the number of rows.
  219. */
  220. public int getRowDimension () {
  221. return m;
  222. }
  223. /** Get column dimension.
  224. @return n, the number of columns.
  225. */
  226. public int getColumnDimension () {
  227. return n;
  228. }
  229. /** Get a single element.
  230. @param i Row index.
  231. @param j Column index.
  232. @return A(i,j)
  233. @exception ArrayIndexOutOfBoundsException
  234. */
  235. public double get (int i, int j) {
  236. return A[i][j];
  237. }
  238. /** Get a submatrix.
  239. @param i0 Initial row index
  240. @param i1 Final row index
  241. @param j0 Initial column index
  242. @param j1 Final column index
  243. @return A(i0:i1,j0:j1)
  244. @exception ArrayIndexOutOfBoundsException Submatrix indices
  245. */
  246. public Matrix getMatrix (int i0, int i1, int j0, int j1) {
  247. Matrix X = new Matrix(i1-i0+1,j1-j0+1);
  248. double[][] B = X.getArray();
  249. try {
  250. for (int i = i0; i <= i1; i++) {
  251. for (int j = j0; j <= j1; j++) {
  252. B[i-i0][j-j0] = A[i][j];
  253. }
  254. }
  255. } catch(ArrayIndexOutOfBoundsException e) {
  256. throw new ArrayIndexOutOfBoundsException("Submatrix indices");
  257. }
  258. return X;
  259. }
  260. /** Get a submatrix.
  261. @param r Array of row indices.
  262. @param c Array of column indices.
  263. @return A(r(:),c(:))
  264. @exception ArrayIndexOutOfBoundsException Submatrix indices
  265. */
  266. public Matrix getMatrix (int[] r, int[] c) {
  267. Matrix X = new Matrix(r.length,c.length);
  268. double[][] B = X.getArray();
  269. try {
  270. for (int i = 0; i < r.length; i++) {
  271. for (int j = 0; j < c.length; j++) {
  272. B[i][j] = A[r[i]][c[j]];
  273. }
  274. }
  275. } catch(ArrayIndexOutOfBoundsException e) {
  276. throw new ArrayIndexOutOfBoundsException("Submatrix indices");
  277. }
  278. return X;
  279. }
  280. /** Get a submatrix.
  281. @param i0 Initial row index
  282. @param i1 Final row index
  283. @param c Array of column indices.
  284. @return A(i0:i1,c(:))
  285. @exception ArrayIndexOutOfBoundsException Submatrix indices
  286. */
  287. public Matrix getMatrix (int i0, int i1, int[] c) {
  288. Matrix X = new Matrix(i1-i0+1,c.length);
  289. double[][] B = X.getArray();
  290. try {
  291. for (int i = i0; i <= i1; i++) {
  292. for (int j = 0; j < c.length; j++) {
  293. B[i-i0][j] = A[i][c[j]];
  294. }
  295. }
  296. } catch(ArrayIndexOutOfBoundsException e) {
  297. throw new ArrayIndexOutOfBoundsException("Submatrix indices");
  298. }
  299. return X;
  300. }
  301. /** Get a submatrix.
  302. @param r Array of row indices.
  303. @param j0 Initial column index
  304. @param j1 Final column index
  305. @return A(r(:),j0:j1)
  306. @exception ArrayIndexOutOfBoundsException Submatrix indices
  307. */
  308. public Matrix getMatrix (int[] r, int j0, int j1) {
  309. Matrix X = new Matrix(r.length,j1-j0+1);
  310. double[][] B = X.getArray();
  311. try {
  312. for (int i = 0; i < r.length; i++) {
  313. for (int j = j0; j <= j1; j++) {
  314. B[i][j-j0] = A[r[i]][j];
  315. }
  316. }
  317. } catch(ArrayIndexOutOfBoundsException e) {
  318. throw new ArrayIndexOutOfBoundsException("Submatrix indices");
  319. }
  320. return X;
  321. }
  322. /** Set a single element.
  323. @param i Row index.
  324. @param j Column index.
  325. @param s A(i,j).
  326. @exception ArrayIndexOutOfBoundsException
  327. */
  328. public void set (int i, int j, double s) {
  329. A[i][j] = s;
  330. }
  331. /** Set a submatrix.
  332. @param i0 Initial row index
  333. @param i1 Final row index
  334. @param j0 Initial column index
  335. @param j1 Final column index
  336. @param X A(i0:i1,j0:j1)
  337. @exception ArrayIndexOutOfBoundsException Submatrix indices
  338. */
  339. public void setMatrix (int i0, int i1, int j0, int j1, Matrix X) {
  340. try {
  341. for (int i = i0; i <= i1; i++) {
  342. for (int j = j0; j <= j1; j++) {
  343. A[i][j] = X.get(i-i0,j-j0);
  344. }
  345. }
  346. } catch(ArrayIndexOutOfBoundsException e) {
  347. throw new ArrayIndexOutOfBoundsException("Submatrix indices");
  348. }
  349. }
  350. /** Set a submatrix.
  351. @param r Array of row indices.
  352. @param c Array of column indices.
  353. @param X A(r(:),c(:))
  354. @exception ArrayIndexOutOfBoundsException Submatrix indices
  355. */
  356. public void setMatrix (int[] r, int[] c, Matrix X) {
  357. try {
  358. for (int i = 0; i < r.length; i++) {
  359. for (int j = 0; j < c.length; j++) {
  360. A[r[i]][c[j]] = X.get(i,j);
  361. }
  362. }
  363. } catch(ArrayIndexOutOfBoundsException e) {
  364. throw new ArrayIndexOutOfBoundsException("Submatrix indices");
  365. }
  366. }
  367. /** Set a submatrix.
  368. @param r Array of row indices.
  369. @param j0 Initial column index
  370. @param j1 Final column index
  371. @param X A(r(:),j0:j1)
  372. @exception ArrayIndexOutOfBoundsException Submatrix indices
  373. */
  374. public void setMatrix (int[] r, int j0, int j1, Matrix X) {
  375. try {
  376. for (int i = 0; i < r.length; i++) {
  377. for (int j = j0; j <= j1; j++) {
  378. A[r[i]][j] = X.get(i,j-j0);
  379. }
  380. }
  381. } catch(ArrayIndexOutOfBoundsException e) {
  382. throw new ArrayIndexOutOfBoundsException("Submatrix indices");
  383. }
  384. }
  385. /** Set a submatrix.
  386. @param i0 Initial row index
  387. @param i1 Final row index
  388. @param c Array of column indices.
  389. @param X A(i0:i1,c(:))
  390. @exception ArrayIndexOutOfBoundsException Submatrix indices
  391. */
  392. public void setMatrix (int i0, int i1, int[] c, Matrix X) {
  393. try {
  394. for (int i = i0; i <= i1; i++) {
  395. for (int j = 0; j < c.length; j++) {
  396. A[i][c[j]] = X.get(i-i0,j);
  397. }
  398. }
  399. } catch(ArrayIndexOutOfBoundsException e) {
  400. throw new ArrayIndexOutOfBoundsException("Submatrix indices");
  401. }
  402. }
  403. /** Matrix transpose.
  404. @return A'
  405. */
  406. public Matrix transpose () {
  407. Matrix X = new Matrix(n,m);
  408. double[][] C = X.getArray();
  409. for (int i = 0; i < m; i++) {
  410. for (int j = 0; j < n; j++) {
  411. C[j][i] = A[i][j];
  412. }
  413. }
  414. return X;
  415. }
  416. /** One norm
  417. @return maximum column sum.
  418. */
  419. public double norm1 () {
  420. double f = 0;
  421. for (int j = 0; j < n; j++) {
  422. double s = 0;
  423. for (int i = 0; i < m; i++) {
  424. s += Math.abs(A[i][j]);
  425. }
  426. f = Math.max(f,s);
  427. }
  428. return f;
  429. }
  430. /** Two norm
  431. @return maximum singular value.
  432. */
  433. public double norm2 () {
  434. return (new SingularValueDecomposition(this).norm2());
  435. }
  436. /** Infinity norm
  437. @return maximum row sum.
  438. */
  439. public double normInf () {
  440. double f = 0;
  441. for (int i = 0; i < m; i++) {
  442. double s = 0;
  443. for (int j = 0; j < n; j++) {
  444. s += Math.abs(A[i][j]);
  445. }
  446. f = Math.max(f,s);
  447. }
  448. return f;
  449. }
  450. /** Frobenius norm
  451. @return sqrt of sum of squares of all elements.
  452. */
  453. public double normF () {
  454. double f = 0;
  455. for (int i = 0; i < m; i++) {
  456. for (int j = 0; j < n; j++) {
  457. f = Maths.hypot(f,A[i][j]);
  458. }
  459. }
  460. return f;
  461. }
  462. /** Unary minus
  463. @return -A
  464. */
  465. public Matrix uminus () {
  466. Matrix X = new Matrix(m,n);
  467. double[][] C = X.getArray();
  468. for (int i = 0; i < m; i++) {
  469. for (int j = 0; j < n; j++) {
  470. C[i][j] = -A[i][j];
  471. }
  472. }
  473. return X;
  474. }
  475. /** C = A + B
  476. @param B another matrix
  477. @return A + B
  478. */
  479. public Matrix plus (Matrix B) {
  480. checkMatrixDimensions(B);
  481. Matrix X = new Matrix(m,n);
  482. double[][] C = X.getArray();
  483. for (int i = 0; i < m; i++) {
  484. for (int j = 0; j < n; j++) {
  485. C[i][j] = A[i][j] + B.A[i][j];
  486. }
  487. }
  488. return X;
  489. }
  490. /** A = A + B
  491. @param B another matrix
  492. @return A + B
  493. */
  494. public Matrix plusEquals (Matrix B) {
  495. checkMatrixDimensions(B);
  496. for (int i = 0; i < m; i++) {
  497. for (int j = 0; j < n; j++) {
  498. A[i][j] = A[i][j] + B.A[i][j];
  499. }
  500. }
  501. return this;
  502. }
  503. /** C = A - B
  504. @param B another matrix
  505. @return A - B
  506. */
  507. public Matrix minus (Matrix B) {
  508. checkMatrixDimensions(B);
  509. Matrix X = new Matrix(m,n);
  510. double[][] C = X.getArray();
  511. for (int i = 0; i < m; i++) {
  512. for (int j = 0; j < n; j++) {
  513. C[i][j] = A[i][j] - B.A[i][j];
  514. }
  515. }
  516. return X;
  517. }
  518. /** A = A - B
  519. @param B another matrix
  520. @return A - B
  521. */
  522. public Matrix minusEquals (Matrix B) {
  523. checkMatrixDimensions(B);
  524. for (int i = 0; i < m; i++) {
  525. for (int j = 0; j < n; j++) {
  526. A[i][j] = A[i][j] - B.A[i][j];
  527. }
  528. }
  529. return this;
  530. }
  531. /** Element-by-element multiplication, C = A.*B
  532. @param B another matrix
  533. @return A.*B
  534. */
  535. public Matrix arrayTimes (Matrix B) {
  536. checkMatrixDimensions(B);
  537. Matrix X = new Matrix(m,n);
  538. double[][] C = X.getArray();
  539. for (int i = 0; i < m; i++) {
  540. for (int j = 0; j < n; j++) {
  541. C[i][j] = A[i][j] * B.A[i][j];
  542. }
  543. }
  544. return X;
  545. }
  546. /** Element-by-element multiplication in place, A = A.*B
  547. @param B another matrix
  548. @return A.*B
  549. */
  550. public Matrix arrayTimesEquals (Matrix B) {
  551. checkMatrixDimensions(B);
  552. for (int i = 0; i < m; i++) {
  553. for (int j = 0; j < n; j++) {
  554. A[i][j] = A[i][j] * B.A[i][j];
  555. }
  556. }
  557. return this;
  558. }
  559. /** Element-by-element right division, C = A./B
  560. @param B another matrix
  561. @return A./B
  562. */
  563. public Matrix arrayRightDivide (Matrix B) {
  564. checkMatrixDimensions(B);
  565. Matrix X = new Matrix(m,n);
  566. double[][] C = X.getArray();
  567. for (int i = 0; i < m; i++) {
  568. for (int j = 0; j < n; j++) {
  569. C[i][j] = A[i][j] / B.A[i][j];
  570. }
  571. }
  572. return X;
  573. }
  574. /** Element-by-element right division in place, A = A./B
  575. @param B another matrix
  576. @return A./B
  577. */
  578. public Matrix arrayRightDivideEquals (Matrix B) {
  579. checkMatrixDimensions(B);
  580. for (int i = 0; i < m; i++) {
  581. for (int j = 0; j < n; j++) {
  582. A[i][j] = A[i][j] / B.A[i][j];
  583. }
  584. }
  585. return this;
  586. }
  587. /** Element-by-element left division, C = A.\B
  588. @param B another matrix
  589. @return A.\B
  590. */
  591. public Matrix arrayLeftDivide (Matrix B) {
  592. checkMatrixDimensions(B);
  593. Matrix X = new Matrix(m,n);
  594. double[][] C = X.getArray();
  595. for (int i = 0; i < m; i++) {
  596. for (int j = 0; j < n; j++) {
  597. C[i][j] = B.A[i][j] / A[i][j];
  598. }
  599. }
  600. return X;
  601. }
  602. /** Element-by-element left division in place, A = A.\B
  603. @param B another matrix
  604. @return A.\B
  605. */
  606. public Matrix arrayLeftDivideEquals (Matrix B) {
  607. checkMatrixDimensions(B);
  608. for (int i = 0; i < m; i++) {
  609. for (int j = 0; j < n; j++) {
  610. A[i][j] = B.A[i][j] / A[i][j];
  611. }
  612. }
  613. return this;
  614. }
  615. /** Multiply a matrix by a scalar, C = s*A
  616. @param s scalar
  617. @return s*A
  618. */
  619. public Matrix times (double s) {
  620. Matrix X = new Matrix(m,n);
  621. double[][] C = X.getArray();
  622. for (int i = 0; i < m; i++) {
  623. for (int j = 0; j < n; j++) {
  624. C[i][j] = s*A[i][j];
  625. }
  626. }
  627. return X;
  628. }
  629. /** Multiply a matrix by a scalar in place, A = s*A
  630. @param s scalar
  631. @return replace A by s*A
  632. */
  633. public Matrix timesEquals (double s) {
  634. for (int i = 0; i < m; i++) {
  635. for (int j = 0; j < n; j++) {
  636. A[i][j] = s*A[i][j];
  637. }
  638. }
  639. return this;
  640. }
  641. /** Linear algebraic matrix multiplication, A * B
  642. @param B another matrix
  643. @return Matrix product, A * B
  644. @exception IllegalArgumentException Matrix inner dimensions must agree.
  645. */
  646. public Matrix times (Matrix B) {
  647. if (B.m != n) {
  648. throw new IllegalArgumentException("Matrix inner dimensions must agree.");
  649. }
  650. Matrix X = new Matrix(m,B.n);
  651. double[][] C = X.getArray();
  652. double[] Bcolj = new double[n];
  653. for (int j = 0; j < B.n; j++) {
  654. for (int k = 0; k < n; k++) {
  655. Bcolj[k] = B.A[k][j];
  656. }
  657. for (int i = 0; i < m; i++) {
  658. double[] Arowi = A[i];
  659. double s = 0;
  660. for (int k = 0; k < n; k++) {
  661. s += Arowi[k]*Bcolj[k];
  662. }
  663. C[i][j] = s;
  664. }
  665. }
  666. return X;
  667. }
  668. /** LU Decomposition
  669. @return LUDecomposition
  670. @see LUDecomposition
  671. */
  672. public LUDecomposition lu () {
  673. return new LUDecomposition(this);
  674. }
  675. /** QR Decomposition
  676. @return QRDecomposition
  677. @see QRDecomposition
  678. */
  679. public QRDecomposition qr () {
  680. return new QRDecomposition(this);
  681. }
  682. /** Cholesky Decomposition
  683. @return CholeskyDecomposition
  684. @see CholeskyDecomposition
  685. */
  686. public CholeskyDecomposition chol () {
  687. return new CholeskyDecomposition(this);
  688. }
  689. /** Singular Value Decomposition
  690. @return SingularValueDecomposition
  691. @see SingularValueDecomposition
  692. */
  693. public SingularValueDecomposition svd () {
  694. return new SingularValueDecomposition(this);
  695. }
  696. /** Eigenvalue Decomposition
  697. @return EigenvalueDecomposition
  698. @see EigenvalueDecomposition
  699. */
  700. public EigenvalueDecomposition eig () {
  701. return new EigenvalueDecomposition(this);
  702. }
  703. /** Solve A*X = B
  704. @param B right hand side
  705. @return solution if A is square, least squares solution otherwise
  706. */
  707. public Matrix solve (Matrix B) {
  708. return (m == n ? (new LUDecomposition(this)).solve(B) :
  709. (new QRDecomposition(this)).solve(B));
  710. }
  711. /** Solve X*A = B, which is also A'*X' = B'
  712. @param B right hand side
  713. @return solution if A is square, least squares solution otherwise.
  714. */
  715. public Matrix solveTranspose (Matrix B) {
  716. return transpose().solve(B.transpose());
  717. }
  718. /** Matrix inverse or pseudoinverse
  719. @return inverse(A) if A is square, pseudoinverse otherwise.
  720. */
  721. public Matrix inverse () {
  722. return solve(identity(m,m));
  723. }
  724. /** Matrix determinant
  725. @return determinant
  726. */
  727. public double det () {
  728. return new LUDecomposition(this).det();
  729. }
  730. /** Matrix rank
  731. @return effective numerical rank, obtained from SVD.
  732. */
  733. public int rank () {
  734. return new SingularValueDecomposition(this).rank();
  735. }
  736. /** Matrix condition (2 norm)
  737. @return ratio of largest to smallest singular value.
  738. */
  739. public double cond () {
  740. return new SingularValueDecomposition(this).cond();
  741. }
  742. /** Matrix trace.
  743. @return sum of the diagonal elements.
  744. */
  745. public double trace () {
  746. double t = 0;
  747. for (int i = 0; i < Math.min(m,n); i++) {
  748. t += A[i][i];
  749. }
  750. return t;
  751. }
  752. /** Generate matrix with random elements
  753. @param m Number of rows.
  754. @param n Number of colums.
  755. @return An m-by-n matrix with uniformly distributed random elements.
  756. */
  757. public static Matrix random (int m, int n) {
  758. Matrix A = new Matrix(m,n);
  759. double[][] X = A.getArray();
  760. for (int i = 0; i < m; i++) {
  761. for (int j = 0; j < n; j++) {
  762. X[i][j] = Math.random();
  763. }
  764. }
  765. return A;
  766. }
  767. /** Generate identity matrix
  768. @param m Number of rows.
  769. @param n Number of colums.
  770. @return An m-by-n matrix with ones on the diagonal and zeros elsewhere.
  771. */
  772. public static Matrix identity (int m, int n) {
  773. Matrix A = new Matrix(m,n);
  774. double[][] X = A.getArray();
  775. for (int i = 0; i < m; i++) {
  776. for (int j = 0; j < n; j++) {
  777. X[i][j] = (i == j ? 1.0 : 0.0);
  778. }
  779. }
  780. return A;
  781. }
  782. /** Print the matrix to stdout. Line the elements up in columns
  783. * with a Fortran-like 'Fw.d' style format.
  784. @param w Column width.
  785. @param d Number of digits after the decimal.
  786. */
  787. public void print (int w, int d) {
  788. print(new PrintWriter(System.out,true),w,d); }
  789. /** Print the matrix to the output stream. Line the elements up in
  790. * columns with a Fortran-like 'Fw.d' style format.
  791. @param output Output stream.
  792. @param w Column width.
  793. @param d Number of digits after the decimal.
  794. */
  795. public void print (PrintWriter output, int w, int d) {
  796. DecimalFormat format = new DecimalFormat();
  797. format.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.US));
  798. format.setMinimumIntegerDigits(1);
  799. format.setMaximumFractionDigits(d);
  800. format.setMinimumFractionDigits(d);
  801. format.setGroupingUsed(false);
  802. print(output,format,w+2);
  803. }
  804. /** Print the matrix to stdout. Line the elements up in columns.
  805. * Use the format object, and right justify within columns of width
  806. * characters.
  807. * Note that is the matrix is to be read back in, you probably will want
  808. * to use a NumberFormat that is set to US Locale.
  809. @param format A Formatting object for individual elements.
  810. @param width Field width for each column.
  811. @see java.text.DecimalFormat#setDecimalFormatSymbols
  812. */
  813. public void print (NumberFormat format, int width) {
  814. print(new PrintWriter(System.out,true),format,width); }
  815. // DecimalFormat is a little disappointing coming from Fortran or C's printf.
  816. // Since it doesn't pad on the left, the elements will come out different
  817. // widths. Consequently, we'll pass the desired column width in as an
  818. // argument and do the extra padding ourselves.
  819. /** Print the matrix to the output stream. Line the elements up in columns.
  820. * Use the format object, and right justify within columns of width
  821. * characters.
  822. * Note that is the matrix is to be read back in, you probably will want
  823. * to use a NumberFormat that is set to US Locale.
  824. @param output the output stream.
  825. @param format A formatting object to format the matrix elements
  826. @param width Column width.
  827. @see java.text.DecimalFormat#setDecimalFormatSymbols
  828. */
  829. public void print (PrintWriter output, NumberFormat format, int width) {
  830. output.println(); // start on new line.
  831. for (int i = 0; i < m; i++) {
  832. for (int j = 0; j < n; j++) {
  833. String s = format.format(A[i][j]); // format the number
  834. int padding = Math.max(1,width-s.length()); // At _least_ 1 space
  835. for (int k = 0; k < padding; k++)
  836. output.print(' ');
  837. output.print(s);
  838. }
  839. output.println();
  840. }
  841. output.println(); // end with blank line.
  842. }
  843. /** Read a matrix from a stream. The format is the same the print method,
  844. * so printed matrices can be read back in (provided they were printed using
  845. * US Locale). Elements are separated by
  846. * whitespace, all the elements for each row appear on a single line,
  847. * the last row is followed by a blank line.
  848. @param input the input stream.
  849. */
  850. public static Matrix read (BufferedReader input) throws java.io.IOException {
  851. StreamTokenizer tokenizer= new StreamTokenizer(input);
  852. // Although StreamTokenizer will parse numbers, it doesn't recognize
  853. // scientific notation (E or D); however, Double.valueOf does.
  854. // The strategy here is to disable StreamTokenizer's number parsing.
  855. // We'll only get whitespace delimited words, EOL's and EOF's.
  856. // These words should all be numbers, for Double.valueOf to parse.
  857. tokenizer.resetSyntax();
  858. tokenizer.wordChars(0,255);
  859. tokenizer.whitespaceChars(0, ' ');
  860. tokenizer.eolIsSignificant(true);
  861. java.util.Vector<Double> vD = new java.util.Vector<Double>();
  862. // Ignore initial empty lines
  863. while (tokenizer.nextToken() == StreamTokenizer.TT_EOL);
  864. if (tokenizer.ttype == StreamTokenizer.TT_EOF)
  865. throw new java.io.IOException("Unexpected EOF on matrix read.");
  866. do {
  867. vD.addElement(Double.valueOf(tokenizer.sval)); // Read & store 1st row.
  868. } while (tokenizer.nextToken() == StreamTokenizer.TT_WORD);
  869. int n = vD.size(); // Now we've got the number of columns!
  870. double row[] = new double[n];
  871. for (int j=0; j<n; j++) // extract the elements of the 1st row.
  872. row[j]=vD.elementAt(j).doubleValue();
  873. java.util.Vector<double[]> v = new java.util.Vector<double[]>();
  874. v.addElement(row); // Start storing rows instead of columns.
  875. while (tokenizer.nextToken() == StreamTokenizer.TT_WORD) {
  876. // While non-empty lines
  877. v.addElement(row = new double[n]);
  878. int j = 0;
  879. do {
  880. if (j >= n) throw new java.io.IOException
  881. ("Row " + v.size() + " is too long.");
  882. row[j++] = Double.valueOf(tokenizer.sval).doubleValue();
  883. } while (tokenizer.nextToken() == StreamTokenizer.TT_WORD);
  884. if (j < n) throw new java.io.IOException
  885. ("Row " + v.size() + " is too short.");
  886. }
  887. int m = v.size(); // Now we've got the number of rows.
  888. double[][] A = new double[m][];
  889. v.copyInto(A); // copy the rows out of the vector
  890. return new Matrix(A);
  891. }
  892. /* ------------------------
  893. Private Methods
  894. * ------------------------ */
  895. /** Check if size(A) == size(B) **/
  896. private void checkMatrixDimensions (Matrix B) {
  897. if (B.m != m || B.n != n) {
  898. throw new IllegalArgumentException("Matrix dimensions must agree.");
  899. }
  900. }
  901. private static final long serialVersionUID = 1;
  902. }

 

3)源码参考EigenvalueDecomposition

可重点研读如何实现特征值分解。

  1. package Jama;
  2. import Jama.util.*;
  3. /** Eigenvalues and eigenvectors of a real matrix.
  4. <P>
  5. If A is symmetric, then A = V*D*V' where the eigenvalue matrix D is
  6. diagonal and the eigenvector matrix V is orthogonal.
  7. I.e. A = V.times(D.times(V.transpose())) and
  8. V.times(V.transpose()) equals the identity matrix.
  9. <P>
  10. If A is not symmetric, then the eigenvalue matrix D is block diagonal
  11. with the real eigenvalues in 1-by-1 blocks and any complex eigenvalues,
  12. lambda + i*mu, in 2-by-2 blocks, [lambda, mu; -mu, lambda]. The
  13. columns of V represent the eigenvectors in the sense that A*V = V*D,
  14. i.e. A.times(V) equals V.times(D). The matrix V may be badly
  15. conditioned, or even singular, so the validity of the equation
  16. A = V*D*inverse(V) depends upon V.cond().
  17. **/
  18. public class EigenvalueDecomposition implements java.io.Serializable {
  19. /* ------------------------
  20. Class variables
  21. * ------------------------ */
  22. /** Row and column dimension (square matrix).
  23. @serial matrix dimension.
  24. */
  25. private int n;
  26. /** Symmetry flag.
  27. @serial internal symmetry flag.
  28. */
  29. private boolean issymmetric;
  30. /** Arrays for internal storage of eigenvalues.
  31. @serial internal storage of eigenvalues.
  32. */
  33. private double[] d, e;
  34. /** Array for internal storage of eigenvectors.
  35. @serial internal storage of eigenvectors.
  36. */
  37. private double[][] V;
  38. /** Array for internal storage of nonsymmetric Hessenberg form.
  39. @serial internal storage of nonsymmetric Hessenberg form.
  40. */
  41. private double[][] H;
  42. /** Working storage for nonsymmetric algorithm.
  43. @serial working storage for nonsymmetric algorithm.
  44. */
  45. private double[] ort;
  46. /* ------------------------
  47. Private Methods
  48. * ------------------------ */
  49. // Symmetric Householder reduction to tridiagonal form.
  50. private void tred2 () {
  51. // This is derived from the Algol procedures tred2 by
  52. // Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
  53. // Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
  54. // Fortran subroutine in EISPACK.
  55. for (int j = 0; j < n; j++) {
  56. d[j] = V[n-1][j];
  57. }
  58. // Householder reduction to tridiagonal form.
  59. for (int i = n-1; i > 0; i--) {
  60. // Scale to avoid under/overflow.
  61. double scale = 0.0;
  62. double h = 0.0;
  63. for (int k = 0; k < i; k++) {
  64. scale = scale + Math.abs(d[k]);
  65. }
  66. if (scale == 0.0) {
  67. e[i] = d[i-1];
  68. for (int j = 0; j < i; j++) {
  69. d[j] = V[i-1][j];
  70. V[i][j] = 0.0;
  71. V[j][i] = 0.0;
  72. }
  73. } else {
  74. // Generate Householder vector.
  75. for (int k = 0; k < i; k++) {
  76. d[k] /= scale;
  77. h += d[k] * d[k];
  78. }
  79. double f = d[i-1];
  80. double g = Math.sqrt(h);
  81. if (f > 0) {
  82. g = -g;
  83. }
  84. e[i] = scale * g;
  85. h = h - f * g;
  86. d[i-1] = f - g;
  87. for (int j = 0; j < i; j++) {
  88. e[j] = 0.0;
  89. }
  90. // Apply similarity transformation to remaining columns.
  91. for (int j = 0; j < i; j++) {
  92. f = d[j];
  93. V[j][i] = f;
  94. g = e[j] + V[j][j] * f;
  95. for (int k = j+1; k <= i-1; k++) {
  96. g += V[k][j] * d[k];
  97. e[k] += V[k][j] * f;
  98. }
  99. e[j] = g;
  100. }
  101. f = 0.0;
  102. for (int j = 0; j < i; j++) {
  103. e[j] /= h;
  104. f += e[j] * d[j];
  105. }
  106. double hh = f / (h + h);
  107. for (int j = 0; j < i; j++) {
  108. e[j] -= hh * d[j];
  109. }
  110. for (int j = 0; j < i; j++) {
  111. f = d[j];
  112. g = e[j];
  113. for (int k = j; k <= i-1; k++) {
  114. V[k][j] -= (f * e[k] + g * d[k]);
  115. }
  116. d[j] = V[i-1][j];
  117. V[i][j] = 0.0;
  118. }
  119. }
  120. d[i] = h;
  121. }
  122. // Accumulate transformations.
  123. for (int i = 0; i < n-1; i++) {
  124. V[n-1][i] = V[i][i];
  125. V[i][i] = 1.0;
  126. double h = d[i+1];
  127. if (h != 0.0) {
  128. for (int k = 0; k <= i; k++) {
  129. d[k] = V[k][i+1] / h;
  130. }
  131. for (int j = 0; j <= i; j++) {
  132. double g = 0.0;
  133. for (int k = 0; k <= i; k++) {
  134. g += V[k][i+1] * V[k][j];
  135. }
  136. for (int k = 0; k <= i; k++) {
  137. V[k][j] -= g * d[k];
  138. }
  139. }
  140. }
  141. for (int k = 0; k <= i; k++) {
  142. V[k][i+1] = 0.0;
  143. }
  144. }
  145. for (int j = 0; j < n; j++) {
  146. d[j] = V[n-1][j];
  147. V[n-1][j] = 0.0;
  148. }
  149. V[n-1][n-1] = 1.0;
  150. e[0] = 0.0;
  151. }
  152. // Symmetric tridiagonal QL algorithm.
  153. private void tql2 () {
  154. // This is derived from the Algol procedures tql2, by
  155. // Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
  156. // Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
  157. // Fortran subroutine in EISPACK.
  158. for (int i = 1; i < n; i++) {
  159. e[i-1] = e[i];
  160. }
  161. e[n-1] = 0.0;
  162. double f = 0.0;
  163. double tst1 = 0.0;
  164. double eps = Math.pow(2.0,-52.0);
  165. for (int l = 0; l < n; l++) {
  166. // Find small subdiagonal element
  167. tst1 = Math.max(tst1,Math.abs(d[l]) + Math.abs(e[l]));
  168. int m = l;
  169. while (m < n) {
  170. if (Math.abs(e[m]) <= eps*tst1) {
  171. break;
  172. }
  173. m++;
  174. }
  175. // If m == l, d[l] is an eigenvalue,
  176. // otherwise, iterate.
  177. if (m > l) {
  178. int iter = 0;
  179. do {
  180. iter = iter + 1; // (Could check iteration count here.)
  181. // Compute implicit shift
  182. double g = d[l];
  183. double p = (d[l+1] - g) / (2.0 * e[l]);
  184. double r = Maths.hypot(p,1.0);
  185. if (p < 0) {
  186. r = -r;
  187. }
  188. d[l] = e[l] / (p + r);
  189. d[l+1] = e[l] * (p + r);
  190. double dl1 = d[l+1];
  191. double h = g - d[l];
  192. for (int i = l+2; i < n; i++) {
  193. d[i] -= h;
  194. }
  195. f = f + h;
  196. // Implicit QL transformation.
  197. p = d[m];
  198. double c = 1.0;
  199. double c2 = c;
  200. double c3 = c;
  201. double el1 = e[l+1];
  202. double s = 0.0;
  203. double s2 = 0.0;
  204. for (int i = m-1; i >= l; i--) {
  205. c3 = c2;
  206. c2 = c;
  207. s2 = s;
  208. g = c * e[i];
  209. h = c * p;
  210. r = Maths.hypot(p,e[i]);
  211. e[i+1] = s * r;
  212. s = e[i] / r;
  213. c = p / r;
  214. p = c * d[i] - s * g;
  215. d[i+1] = h + s * (c * g + s * d[i]);
  216. // Accumulate transformation.
  217. for (int k = 0; k < n; k++) {
  218. h = V[k][i+1];
  219. V[k][i+1] = s * V[k][i] + c * h;
  220. V[k][i] = c * V[k][i] - s * h;
  221. }
  222. }
  223. p = -s * s2 * c3 * el1 * e[l] / dl1;
  224. e[l] = s * p;
  225. d[l] = c * p;
  226. // Check for convergence.
  227. } while (Math.abs(e[l]) > eps*tst1);
  228. }
  229. d[l] = d[l] + f;
  230. e[l] = 0.0;
  231. }
  232. // Sort eigenvalues and corresponding vectors.
  233. for (int i = 0; i < n-1; i++) {
  234. int k = i;
  235. double p = d[i];
  236. for (int j = i+1; j < n; j++) {
  237. if (d[j] < p) {
  238. k = j;
  239. p = d[j];
  240. }
  241. }
  242. if (k != i) {
  243. d[k] = d[i];
  244. d[i] = p;
  245. for (int j = 0; j < n; j++) {
  246. p = V[j][i];
  247. V[j][i] = V[j][k];
  248. V[j][k] = p;
  249. }
  250. }
  251. }
  252. }
  253. // Nonsymmetric reduction to Hessenberg form.
  254. private void orthes () {
  255. // This is derived from the Algol procedures orthes and ortran,
  256. // by Martin and Wilkinson, Handbook for Auto. Comp.,
  257. // Vol.ii-Linear Algebra, and the corresponding
  258. // Fortran subroutines in EISPACK.
  259. int low = 0;
  260. int high = n-1;
  261. for (int m = low+1; m <= high-1; m++) {
  262. // Scale column.
  263. double scale = 0.0;
  264. for (int i = m; i <= high; i++) {
  265. scale = scale + Math.abs(H[i][m-1]);
  266. }
  267. if (scale != 0.0) {
  268. // Compute Householder transformation.
  269. double h = 0.0;
  270. for (int i = high; i >= m; i--) {
  271. ort[i] = H[i][m-1]/scale;
  272. h += ort[i] * ort[i];
  273. }
  274. double g = Math.sqrt(h);
  275. if (ort[m] > 0) {
  276. g = -g;
  277. }
  278. h = h - ort[m] * g;
  279. ort[m] = ort[m] - g;
  280. // Apply Householder similarity transformation
  281. // H = (I-u*u'/h)*H*(I-u*u')/h)
  282. for (int j = m; j < n; j++) {
  283. double f = 0.0;
  284. for (int i = high; i >= m; i--) {
  285. f += ort[i]*H[i][j];
  286. }
  287. f = f/h;
  288. for (int i = m; i <= high; i++) {
  289. H[i][j] -= f*ort[i];
  290. }
  291. }
  292. for (int i = 0; i <= high; i++) {
  293. double f = 0.0;
  294. for (int j = high; j >= m; j--) {
  295. f += ort[j]*H[i][j];
  296. }
  297. f = f/h;
  298. for (int j = m; j <= high; j++) {
  299. H[i][j] -= f*ort[j];
  300. }
  301. }
  302. ort[m] = scale*ort[m];
  303. H[m][m-1] = scale*g;
  304. }
  305. }
  306. // Accumulate transformations (Algol's ortran).
  307. for (int i = 0; i < n; i++) {
  308. for (int j = 0; j < n; j++) {
  309. V[i][j] = (i == j ? 1.0 : 0.0);
  310. }
  311. }
  312. for (int m = high-1; m >= low+1; m--) {
  313. if (H[m][m-1] != 0.0) {
  314. for (int i = m+1; i <= high; i++) {
  315. ort[i] = H[i][m-1];
  316. }
  317. for (int j = m; j <= high; j++) {
  318. double g = 0.0;
  319. for (int i = m; i <= high; i++) {
  320. g += ort[i] * V[i][j];
  321. }
  322. // Double division avoids possible underflow
  323. g = (g / ort[m]) / H[m][m-1];
  324. for (int i = m; i <= high; i++) {
  325. V[i][j] += g * ort[i];
  326. }
  327. }
  328. }
  329. }
  330. }
  331. // Complex scalar division.
  332. private transient double cdivr, cdivi;
  333. private void cdiv(double xr, double xi, double yr, double yi) {
  334. double r,d;
  335. if (Math.abs(yr) > Math.abs(yi)) {
  336. r = yi/yr;
  337. d = yr + r*yi;
  338. cdivr = (xr + r*xi)/d;
  339. cdivi = (xi - r*xr)/d;
  340. } else {
  341. r = yr/yi;
  342. d = yi + r*yr;
  343. cdivr = (r*xr + xi)/d;
  344. cdivi = (r*xi - xr)/d;
  345. }
  346. }
  347. // Nonsymmetric reduction from Hessenberg to real Schur form.
  348. private void hqr2 () {
  349. // This is derived from the Algol procedure hqr2,
  350. // by Martin and Wilkinson, Handbook for Auto. Comp.,
  351. // Vol.ii-Linear Algebra, and the corresponding
  352. // Fortran subroutine in EISPACK.
  353. // Initialize
  354. int nn = this.n;
  355. int n = nn-1;
  356. int low = 0;
  357. int high = nn-1;
  358. double eps = Math.pow(2.0,-52.0);
  359. double exshift = 0.0;
  360. double p=0,q=0,r=0,s=0,z=0,t,w,x,y;
  361. // Store roots isolated by balanc and compute matrix norm
  362. double norm = 0.0;
  363. for (int i = 0; i < nn; i++) {
  364. if (i < low | i > high) {
  365. d[i] = H[i][i];
  366. e[i] = 0.0;
  367. }
  368. for (int j = Math.max(i-1,0); j < nn; j++) {
  369. norm = norm + Math.abs(H[i][j]);
  370. }
  371. }
  372. // Outer loop over eigenvalue index
  373. int iter = 0;
  374. while (n >= low) {
  375. // Look for single small sub-diagonal element
  376. int l = n;
  377. while (l > low) {
  378. s = Math.abs(H[l-1][l-1]) + Math.abs(H[l][l]);
  379. if (s == 0.0) {
  380. s = norm;
  381. }
  382. if (Math.abs(H[l][l-1]) < eps * s) {
  383. break;
  384. }
  385. l--;
  386. }
  387. // Check for convergence
  388. // One root found
  389. if (l == n) {
  390. H[n][n] = H[n][n] + exshift;
  391. d[n] = H[n][n];
  392. e[n] = 0.0;
  393. n--;
  394. iter = 0;
  395. // Two roots found
  396. } else if (l == n-1) {
  397. w = H[n][n-1] * H[n-1][n];
  398. p = (H[n-1][n-1] - H[n][n]) / 2.0;
  399. q = p * p + w;
  400. z = Math.sqrt(Math.abs(q));
  401. H[n][n] = H[n][n] + exshift;
  402. H[n-1][n-1] = H[n-1][n-1] + exshift;
  403. x = H[n][n];
  404. // Real pair
  405. if (q >= 0) {
  406. if (p >= 0) {
  407. z = p + z;
  408. } else {
  409. z = p - z;
  410. }
  411. d[n-1] = x + z;
  412. d[n] = d[n-1];
  413. if (z != 0.0) {
  414. d[n] = x - w / z;
  415. }
  416. e[n-1] = 0.0;
  417. e[n] = 0.0;
  418. x = H[n][n-1];
  419. s = Math.abs(x) + Math.abs(z);
  420. p = x / s;
  421. q = z / s;
  422. r = Math.sqrt(p * p+q * q);
  423. p = p / r;
  424. q = q / r;
  425. // Row modification
  426. for (int j = n-1; j < nn; j++) {
  427. z = H[n-1][j];
  428. H[n-1][j] = q * z + p * H[n][j];
  429. H[n][j] = q * H[n][j] - p * z;
  430. }
  431. // Column modification
  432. for (int i = 0; i <= n; i++) {
  433. z = H[i][n-1];
  434. H[i][n-1] = q * z + p * H[i][n];
  435. H[i][n] = q * H[i][n] - p * z;
  436. }
  437. // Accumulate transformations
  438. for (int i = low; i <= high; i++) {
  439. z = V[i][n-1];
  440. V[i][n-1] = q * z + p * V[i][n];
  441. V[i][n] = q * V[i][n] - p * z;
  442. }
  443. // Complex pair
  444. } else {
  445. d[n-1] = x + p;
  446. d[n] = x + p;
  447. e[n-1] = z;
  448. e[n] = -z;
  449. }
  450. n = n - 2;
  451. iter = 0;
  452. // No convergence yet
  453. } else {
  454. // Form shift
  455. x = H[n][n];
  456. y = 0.0;
  457. w = 0.0;
  458. if (l < n) {
  459. y = H[n-1][n-1];
  460. w = H[n][n-1] * H[n-1][n];
  461. }
  462. // Wilkinson's original ad hoc shift
  463. if (iter == 10) {
  464. exshift += x;
  465. for (int i = low; i <= n; i++) {
  466. H[i][i] -= x;
  467. }
  468. s = Math.abs(H[n][n-1]) + Math.abs(H[n-1][n-2]);
  469. x = y = 0.75 * s;
  470. w = -0.4375 * s * s;
  471. }
  472. // MATLAB's new ad hoc shift
  473. if (iter == 30) {
  474. s = (y - x) / 2.0;
  475. s = s * s + w;
  476. if (s > 0) {
  477. s = Math.sqrt(s);
  478. if (y < x) {
  479. s = -s;
  480. }
  481. s = x - w / ((y - x) / 2.0 + s);
  482. for (int i = low; i <= n; i++) {
  483. H[i][i] -= s;
  484. }
  485. exshift += s;
  486. x = y = w = 0.964;
  487. }
  488. }
  489. iter = iter + 1; // (Could check iteration count here.)
  490. // Look for two consecutive small sub-diagonal elements
  491. int m = n-2;
  492. while (m >= l) {
  493. z = H[m][m];
  494. r = x - z;
  495. s = y - z;
  496. p = (r * s - w) / H[m+1][m] + H[m][m+1];
  497. q = H[m+1][m+1] - z - r - s;
  498. r = H[m+2][m+1];
  499. s = Math.abs(p) + Math.abs(q) + Math.abs(r);
  500. p = p / s;
  501. q = q / s;
  502. r = r / s;
  503. if (m == l) {
  504. break;
  505. }
  506. if (Math.abs(H[m][m-1]) * (Math.abs(q) + Math.abs(r)) <
  507. eps * (Math.abs(p) * (Math.abs(H[m-1][m-1]) + Math.abs(z) +
  508. Math.abs(H[m+1][m+1])))) {
  509. break;
  510. }
  511. m--;
  512. }
  513. for (int i = m+2; i <= n; i++) {
  514. H[i][i-2] = 0.0;
  515. if (i > m+2) {
  516. H[i][i-3] = 0.0;
  517. }
  518. }
  519. // Double QR step involving rows l:n and columns m:n
  520. for (int k = m; k <= n-1; k++) {
  521. boolean notlast = (k != n-1);
  522. if (k != m) {
  523. p = H[k][k-1];
  524. q = H[k+1][k-1];
  525. r = (notlast ? H[k+2][k-1] : 0.0);
  526. x = Math.abs(p) + Math.abs(q) + Math.abs(r);
  527. if (x == 0.0) {
  528. continue;
  529. }
  530. p = p / x;
  531. q = q / x;
  532. r = r / x;
  533. }
  534. s = Math.sqrt(p * p + q * q + r * r);
  535. if (p < 0) {
  536. s = -s;
  537. }
  538. if (s != 0) {
  539. if (k != m) {
  540. H[k][k-1] = -s * x;
  541. } else if (l != m) {
  542. H[k][k-1] = -H[k][k-1];
  543. }
  544. p = p + s;
  545. x = p / s;
  546. y = q / s;
  547. z = r / s;
  548. q = q / p;
  549. r = r / p;
  550. // Row modification
  551. for (int j = k; j < nn; j++) {
  552. p = H[k][j] + q * H[k+1][j];
  553. if (notlast) {
  554. p = p + r * H[k+2][j];
  555. H[k+2][j] = H[k+2][j] - p * z;
  556. }
  557. H[k][j] = H[k][j] - p * x;
  558. H[k+1][j] = H[k+1][j] - p * y;
  559. }
  560. // Column modification
  561. for (int i = 0; i <= Math.min(n,k+3); i++) {
  562. p = x * H[i][k] + y * H[i][k+1];
  563. if (notlast) {
  564. p = p + z * H[i][k+2];
  565. H[i][k+2] = H[i][k+2] - p * r;
  566. }
  567. H[i][k] = H[i][k] - p;
  568. H[i][k+1] = H[i][k+1] - p * q;
  569. }
  570. // Accumulate transformations
  571. for (int i = low; i <= high; i++) {
  572. p = x * V[i][k] + y * V[i][k+1];
  573. if (notlast) {
  574. p = p + z * V[i][k+2];
  575. V[i][k+2] = V[i][k+2] - p * r;
  576. }
  577. V[i][k] = V[i][k] - p;
  578. V[i][k+1] = V[i][k+1] - p * q;
  579. }
  580. } // (s != 0)
  581. } // k loop
  582. } // check convergence
  583. } // while (n >= low)
  584. // Backsubstitute to find vectors of upper triangular form
  585. if (norm == 0.0) {
  586. return;
  587. }
  588. for (n = nn-1; n >= 0; n--) {
  589. p = d[n];
  590. q = e[n];
  591. // Real vector
  592. if (q == 0) {
  593. int l = n;
  594. H[n][n] = 1.0;
  595. for (int i = n-1; i >= 0; i--) {
  596. w = H[i][i] - p;
  597. r = 0.0;
  598. for (int j = l; j <= n; j++) {
  599. r = r + H[i][j] * H[j][n];
  600. }
  601. if (e[i] < 0.0) {
  602. z = w;
  603. s = r;
  604. } else {
  605. l = i;
  606. if (e[i] == 0.0) {
  607. if (w != 0.0) {
  608. H[i][n] = -r / w;
  609. } else {
  610. H[i][n] = -r / (eps * norm);
  611. }
  612. // Solve real equations
  613. } else {
  614. x = H[i][i+1];
  615. y = H[i+1][i];
  616. q = (d[i] - p) * (d[i] - p) + e[i] * e[i];
  617. t = (x * s - z * r) / q;
  618. H[i][n] = t;
  619. if (Math.abs(x) > Math.abs(z)) {
  620. H[i+1][n] = (-r - w * t) / x;
  621. } else {
  622. H[i+1][n] = (-s - y * t) / z;
  623. }
  624. }
  625. // Overflow control
  626. t = Math.abs(H[i][n]);
  627. if ((eps * t) * t > 1) {
  628. for (int j = i; j <= n; j++) {
  629. H[j][n] = H[j][n] / t;
  630. }
  631. }
  632. }
  633. }
  634. // Complex vector
  635. } else if (q < 0) {
  636. int l = n-1;
  637. // Last vector component imaginary so matrix is triangular
  638. if (Math.abs(H[n][n-1]) > Math.abs(H[n-1][n])) {
  639. H[n-1][n-1] = q / H[n][n-1];
  640. H[n-1][n] = -(H[n][n] - p) / H[n][n-1];
  641. } else {
  642. cdiv(0.0,-H[n-1][n],H[n-1][n-1]-p,q);
  643. H[n-1][n-1] = cdivr;
  644. H[n-1][n] = cdivi;
  645. }
  646. H[n][n-1] = 0.0;
  647. H[n][n] = 1.0;
  648. for (int i = n-2; i >= 0; i--) {
  649. double ra,sa,vr,vi;
  650. ra = 0.0;
  651. sa = 0.0;
  652. for (int j = l; j <= n; j++) {
  653. ra = ra + H[i][j] * H[j][n-1];
  654. sa = sa + H[i][j] * H[j][n];
  655. }
  656. w = H[i][i] - p;
  657. if (e[i] < 0.0) {
  658. z = w;
  659. r = ra;
  660. s = sa;
  661. } else {
  662. l = i;
  663. if (e[i] == 0) {
  664. cdiv(-ra,-sa,w,q);
  665. H[i][n-1] = cdivr;
  666. H[i][n] = cdivi;
  667. } else {
  668. // Solve complex equations
  669. x = H[i][i+1];
  670. y = H[i+1][i];
  671. vr = (d[i] - p) * (d[i] - p) + e[i] * e[i] - q * q;
  672. vi = (d[i] - p) * 2.0 * q;
  673. if (vr == 0.0 & vi == 0.0) {
  674. vr = eps * norm * (Math.abs(w) + Math.abs(q) +
  675. Math.abs(x) + Math.abs(y) + Math.abs(z));
  676. }
  677. cdiv(x*r-z*ra+q*sa,x*s-z*sa-q*ra,vr,vi);
  678. H[i][n-1] = cdivr;
  679. H[i][n] = cdivi;
  680. if (Math.abs(x) > (Math.abs(z) + Math.abs(q))) {
  681. H[i+1][n-1] = (-ra - w * H[i][n-1] + q * H[i][n]) / x;
  682. H[i+1][n] = (-sa - w * H[i][n] - q * H[i][n-1]) / x;
  683. } else {
  684. cdiv(-r-y*H[i][n-1],-s-y*H[i][n],z,q);
  685. H[i+1][n-1] = cdivr;
  686. H[i+1][n] = cdivi;
  687. }
  688. }
  689. // Overflow control
  690. t = Math.max(Math.abs(H[i][n-1]),Math.abs(H[i][n]));
  691. if ((eps * t) * t > 1) {
  692. for (int j = i; j <= n; j++) {
  693. H[j][n-1] = H[j][n-1] / t;
  694. H[j][n] = H[j][n] / t;
  695. }
  696. }
  697. }
  698. }
  699. }
  700. }
  701. // Vectors of isolated roots
  702. for (int i = 0; i < nn; i++) {
  703. if (i < low | i > high) {
  704. for (int j = i; j < nn; j++) {
  705. V[i][j] = H[i][j];
  706. }
  707. }
  708. }
  709. // Back transformation to get eigenvectors of original matrix
  710. for (int j = nn-1; j >= low; j--) {
  711. for (int i = low; i <= high; i++) {
  712. z = 0.0;
  713. for (int k = low; k <= Math.min(j,high); k++) {
  714. z = z + V[i][k] * H[k][j];
  715. }
  716. V[i][j] = z;
  717. }
  718. }
  719. }
  720. /* ------------------------
  721. Constructor
  722. * ------------------------ */
  723. /** Check for symmetry, then construct the eigenvalue decomposition
  724. Structure to access D and V.
  725. @param Arg Square matrix
  726. */
  727. public EigenvalueDecomposition (Matrix Arg) {
  728. double[][] A = Arg.getArray();
  729. n = Arg.getColumnDimension();
  730. V = new double[n][n];
  731. d = new double[n];
  732. e = new double[n];
  733. issymmetric = true;
  734. for (int j = 0; (j < n) & issymmetric; j++) {
  735. for (int i = 0; (i < n) & issymmetric; i++) {
  736. issymmetric = (A[i][j] == A[j][i]);
  737. }
  738. }
  739. if (issymmetric) {
  740. for (int i = 0; i < n; i++) {
  741. for (int j = 0; j < n; j++) {
  742. V[i][j] = A[i][j];
  743. }
  744. }
  745. // Tridiagonalize.
  746. tred2();
  747. // Diagonalize.
  748. tql2();
  749. } else {
  750. H = new double[n][n];
  751. ort = new double[n];
  752. for (int j = 0; j < n; j++) {
  753. for (int i = 0; i < n; i++) {
  754. H[i][j] = A[i][j];
  755. }
  756. }
  757. // Reduce to Hessenberg form.
  758. orthes();
  759. // Reduce Hessenberg to real Schur form.
  760. hqr2();
  761. }
  762. }
  763. /* ------------------------
  764. Public Methods
  765. * ------------------------ */
  766. /** Return the eigenvector matrix
  767. @return V
  768. */
  769. public Matrix getV () {
  770. return new Matrix(V,n,n);
  771. }
  772. /** Return the real parts of the eigenvalues
  773. @return real(diag(D))
  774. */
  775. public double[] getRealEigenvalues () {
  776. return d;
  777. }
  778. /** Return the imaginary parts of the eigenvalues
  779. @return imag(diag(D))
  780. */
  781. public double[] getImagEigenvalues () {
  782. return e;
  783. }
  784. /** Return the block diagonal eigenvalue matrix
  785. @return D
  786. */
  787. public Matrix getD () {
  788. Matrix X = new Matrix(n,n);
  789. double[][] D = X.getArray();
  790. for (int i = 0; i < n; i++) {
  791. for (int j = 0; j < n; j++) {
  792. D[i][j] = 0.0;
  793. }
  794. D[i][i] = d[i];
  795. if (e[i] > 0) {
  796. D[i][i+1] = e[i];
  797. } else if (e[i] < 0) {
  798. D[i][i-1] = e[i];
  799. }
  800. }
  801. return X;
  802. }
  803. private static final long serialVersionUID = 1;
  804. }


声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/271813
推荐阅读
相关标签
  

闽ICP备14008679号