eigen.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. //-----------------------------------------------------------------------------
  2. //
  3. // Compute eigenvalues and eigenvectors
  4. //
  5. // Input: stack[tos - 1] symmetric matrix
  6. //
  7. // Output: D diagnonal matrix
  8. //
  9. // Q eigenvector matrix
  10. //
  11. // D and Q have the property that
  12. //
  13. // A == dot(transpose(Q),D,Q)
  14. //
  15. // where A is the original matrix.
  16. //
  17. // The eigenvalues are on the diagonal of D.
  18. //
  19. // The eigenvectors are row vectors in Q.
  20. //
  21. // The eigenvalue relation
  22. //
  23. // A X = lambda X
  24. //
  25. // can be checked as follows:
  26. //
  27. // lambda = D[1,1]
  28. //
  29. // X = Q[1]
  30. //
  31. // dot(A,X) - lambda X
  32. //
  33. //-----------------------------------------------------------------------------
  34. #include "stdafx.h"
  35. #include "defs.h"
  36. #define D(i, j) yydd[n * (i) + (j)]
  37. #define Q(i, j) yyqq[n * (i) + (j)]
  38. extern void copy_tensor(void);
  39. static void eigen(int);
  40. static int check_arg(void);
  41. static int step(void);
  42. static void step2(int, int);
  43. static int n;
  44. static double *yydd, *yyqq;
  45. void
  46. eval_eigen(void)
  47. {
  48. if (check_arg() == 0)
  49. stop("eigen: argument is not a square matrix");
  50. eigen(EIGEN);
  51. p1 = usr_symbol("D");
  52. set_binding(p1, p2);
  53. p1 = usr_symbol("Q");
  54. set_binding(p1, p3);
  55. push(symbol(NIL));
  56. }
  57. void
  58. eval_eigenval(void)
  59. {
  60. if (check_arg() == 0) {
  61. push_symbol(EIGENVAL);
  62. push(p1);
  63. list(2);
  64. return;
  65. }
  66. eigen(EIGENVAL);
  67. push(p2);
  68. }
  69. void
  70. eval_eigenvec(void)
  71. {
  72. if (check_arg() == 0) {
  73. push_symbol(EIGENVEC);
  74. push(p1);
  75. list(2);
  76. return;
  77. }
  78. eigen(EIGENVEC);
  79. push(p3);
  80. }
  81. static int
  82. check_arg(void)
  83. {
  84. int i, j;
  85. push(cadr(p1));
  86. eval();
  87. yyfloat();
  88. eval();
  89. p1 = pop();
  90. if (!istensor(p1))
  91. return 0;
  92. if (p1->u.tensor->ndim != 2 || p1->u.tensor->dim[0] != p1->u.tensor->dim[1])
  93. stop("eigen: argument is not a square matrix");
  94. n = p1->u.tensor->dim[0];
  95. for (i = 0; i < n; i++)
  96. for (j = 0; j < n; j++)
  97. if (!isdouble(p1->u.tensor->elem[n * i + j]))
  98. stop("eigen: matrix is not numerical");
  99. for (i = 0; i < n - 1; i++)
  100. for (j = i + 1; j < n; j++)
  101. if (fabs(p1->u.tensor->elem[n * i + j]->u.d - p1->u.tensor->elem[n * j + i]->u.d) > 1e-10)
  102. stop("eigen: matrix is not symmetrical");
  103. return 1;
  104. }
  105. //-----------------------------------------------------------------------------
  106. //
  107. // Input: p1 matrix
  108. //
  109. // Output: p2 eigenvalues
  110. //
  111. // p3 eigenvectors
  112. //
  113. //-----------------------------------------------------------------------------
  114. static void
  115. eigen(int op)
  116. {
  117. int i, j;
  118. // malloc working vars
  119. yydd = (double *) malloc(n * n * sizeof (double));
  120. if (yydd == NULL)
  121. stop("malloc failure");
  122. yyqq = (double *) malloc(n * n * sizeof (double));
  123. if (yyqq == NULL)
  124. stop("malloc failure");
  125. // initialize D
  126. for (i = 0; i < n; i++) {
  127. D(i, i) = p1->u.tensor->elem[n * i + i]->u.d;
  128. for (j = i + 1; j < n; j++) {
  129. D(i, j) = p1->u.tensor->elem[n * i + j]->u.d;
  130. D(j, i) = p1->u.tensor->elem[n * i + j]->u.d;
  131. }
  132. }
  133. // initialize Q
  134. for (i = 0; i < n; i++) {
  135. Q(i, i) = 1.0;
  136. for (j = i + 1; j < n; j++) {
  137. Q(i, j) = 0.0;
  138. Q(j, i) = 0.0;
  139. }
  140. }
  141. // step up to 100 times
  142. for (i = 0; i < 100; i++)
  143. if (step() == 0)
  144. break;
  145. if (i == 100)
  146. printstr("\nnote: eigen did not converge");
  147. // p2 = D
  148. if (op == EIGEN || op == EIGENVAL) {
  149. push(p1);
  150. copy_tensor();
  151. p2 = pop();
  152. for (i = 0; i < n; i++) {
  153. for (j = 0; j < n; j++) {
  154. push_double(D(i, j));
  155. p2->u.tensor->elem[n * i + j] = pop();
  156. }
  157. }
  158. }
  159. // p3 = Q
  160. if (op == EIGEN || op == EIGENVEC) {
  161. push(p1);
  162. copy_tensor();
  163. p3 = pop();
  164. for (i = 0; i < n; i++) {
  165. for (j = 0; j < n; j++) {
  166. push_double(Q(i, j));
  167. p3->u.tensor->elem[n * i + j] = pop();
  168. }
  169. }
  170. }
  171. // free working vars
  172. free(yydd);
  173. free(yyqq);
  174. }
  175. //-----------------------------------------------------------------------------
  176. //
  177. // Example: p = 1, q = 3
  178. //
  179. // c 0 s 0
  180. //
  181. // 0 1 0 0
  182. // G =
  183. // -s 0 c 0
  184. //
  185. // 0 0 0 1
  186. //
  187. // The effect of multiplying G times A is...
  188. //
  189. // row 1 of A = c (row 1 of A ) + s (row 3 of A )
  190. // n+1 n n
  191. //
  192. // row 3 of A = c (row 3 of A ) - s (row 1 of A )
  193. // n+1 n n
  194. //
  195. // In terms of components the overall effect is...
  196. //
  197. // row 1 = c row 1 + s row 3
  198. //
  199. // A[1,1] = c A[1,1] + s A[3,1]
  200. //
  201. // A[1,2] = c A[1,2] + s A[3,2]
  202. //
  203. // A[1,3] = c A[1,3] + s A[3,3]
  204. //
  205. // A[1,4] = c A[1,4] + s A[3,4]
  206. //
  207. // row 3 = c row 3 - s row 1
  208. //
  209. // A[3,1] = c A[3,1] - s A[1,1]
  210. //
  211. // A[3,2] = c A[3,2] - s A[1,2]
  212. //
  213. // A[3,3] = c A[3,3] - s A[1,3]
  214. //
  215. // A[3,4] = c A[3,4] - s A[1,4]
  216. //
  217. // T
  218. // The effect of multiplying A times G is...
  219. //
  220. // col 1 of A = c (col 1 of A ) + s (col 3 of A )
  221. // n+1 n n
  222. //
  223. // col 3 of A = c (col 3 of A ) - s (col 1 of A )
  224. // n+1 n n
  225. //
  226. // In terms of components the overall effect is...
  227. //
  228. // col 1 = c col 1 + s col 3
  229. //
  230. // A[1,1] = c A[1,1] + s A[1,3]
  231. //
  232. // A[2,1] = c A[2,1] + s A[2,3]
  233. //
  234. // A[3,1] = c A[3,1] + s A[3,3]
  235. //
  236. // A[4,1] = c A[4,1] + s A[4,3]
  237. //
  238. // col 3 = c col 3 - s col 1
  239. //
  240. // A[1,3] = c A[1,3] - s A[1,1]
  241. //
  242. // A[2,3] = c A[2,3] - s A[2,1]
  243. //
  244. // A[3,3] = c A[3,3] - s A[3,1]
  245. //
  246. // A[4,3] = c A[4,3] - s A[4,1]
  247. //
  248. // What we want to do is just compute the upper triangle of A since we
  249. // know the lower triangle is identical.
  250. //
  251. // In other words, we just want to update components A[i,j] where i < j.
  252. //
  253. //-----------------------------------------------------------------------------
  254. //
  255. // Example: p = 2, q = 5
  256. //
  257. // p q
  258. //
  259. // j=1 j=2 j=3 j=4 j=5 j=6
  260. //
  261. // i=1 . A[1,2] . . A[1,5] .
  262. //
  263. // p i=2 A[2,1] A[2,2] A[2,3] A[2,4] A[2,5] A[2,6]
  264. //
  265. // i=3 . A[3,2] . . A[3,5] .
  266. //
  267. // i=4 . A[4,2] . . A[4,5] .
  268. //
  269. // q i=5 A[5,1] A[5,2] A[5,3] A[5,4] A[5,5] A[5,6]
  270. //
  271. // i=6 . A[6,2] . . A[6,5] .
  272. //
  273. //-----------------------------------------------------------------------------
  274. //
  275. // This is what B = GA does:
  276. //
  277. // row 2 = c row 2 + s row 5
  278. //
  279. // B[2,1] = c * A[2,1] + s * A[5,1]
  280. // B[2,2] = c * A[2,2] + s * A[5,2]
  281. // B[2,3] = c * A[2,3] + s * A[5,3]
  282. // B[2,4] = c * A[2,4] + s * A[5,4]
  283. // B[2,5] = c * A[2,5] + s * A[5,5]
  284. // B[2,6] = c * A[2,6] + s * A[5,6]
  285. //
  286. // row 5 = c row 5 - s row 2
  287. //
  288. // B[5,1] = c * A[5,1] + s * A[2,1]
  289. // B[5,2] = c * A[5,2] + s * A[2,2]
  290. // B[5,3] = c * A[5,3] + s * A[2,3]
  291. // B[5,4] = c * A[5,4] + s * A[2,4]
  292. // B[5,5] = c * A[5,5] + s * A[2,5]
  293. // B[5,6] = c * A[5,6] + s * A[2,6]
  294. //
  295. // T
  296. // This is what BG does:
  297. //
  298. // col 2 = c col 2 + s col 5
  299. //
  300. // B[1,2] = c * A[1,2] + s * A[1,5]
  301. // B[2,2] = c * A[2,2] + s * A[2,5]
  302. // B[3,2] = c * A[3,2] + s * A[3,5]
  303. // B[4,2] = c * A[4,2] + s * A[4,5]
  304. // B[5,2] = c * A[5,2] + s * A[5,5]
  305. // B[6,2] = c * A[6,2] + s * A[6,5]
  306. //
  307. // col 5 = c col 5 - s col 2
  308. //
  309. // B[1,5] = c * A[1,5] - s * A[1,2]
  310. // B[2,5] = c * A[2,5] - s * A[2,2]
  311. // B[3,5] = c * A[3,5] - s * A[3,2]
  312. // B[4,5] = c * A[4,5] - s * A[4,2]
  313. // B[5,5] = c * A[5,5] - s * A[5,2]
  314. // B[6,5] = c * A[6,5] - s * A[6,2]
  315. //
  316. //-----------------------------------------------------------------------------
  317. //
  318. // Step 1: Just do upper triangle (i < j), B[2,5] = 0
  319. //
  320. // B[1,2] = c * A[1,2] + s * A[1,5]
  321. //
  322. // B[2,3] = c * A[2,3] + s * A[5,3]
  323. // B[2,4] = c * A[2,4] + s * A[5,4]
  324. // B[2,6] = c * A[2,6] + s * A[5,6]
  325. //
  326. // B[1,5] = c * A[1,5] - s * A[1,2]
  327. // B[3,5] = c * A[3,5] - s * A[3,2]
  328. // B[4,5] = c * A[4,5] - s * A[4,2]
  329. //
  330. // B[5,6] = c * A[5,6] + s * A[2,6]
  331. //
  332. //-----------------------------------------------------------------------------
  333. //
  334. // Step 2: Transpose where i > j since A[i,j] == A[j,i]
  335. //
  336. // B[1,2] = c * A[1,2] + s * A[1,5]
  337. //
  338. // B[2,3] = c * A[2,3] + s * A[3,5]
  339. // B[2,4] = c * A[2,4] + s * A[4,5]
  340. // B[2,6] = c * A[2,6] + s * A[5,6]
  341. //
  342. // B[1,5] = c * A[1,5] - s * A[1,2]
  343. // B[3,5] = c * A[3,5] - s * A[2,3]
  344. // B[4,5] = c * A[4,5] - s * A[2,4]
  345. //
  346. // B[5,6] = c * A[5,6] + s * A[2,6]
  347. //
  348. //-----------------------------------------------------------------------------
  349. //
  350. // Step 3: Same as above except reorder
  351. //
  352. // k < p (k = 1)
  353. //
  354. // A[1,2] = c * A[1,2] + s * A[1,5]
  355. // A[1,5] = c * A[1,5] - s * A[1,2]
  356. //
  357. // p < k < q (k = 3..4)
  358. //
  359. // A[2,3] = c * A[2,3] + s * A[3,5]
  360. // A[3,5] = c * A[3,5] - s * A[2,3]
  361. //
  362. // A[2,4] = c * A[2,4] + s * A[4,5]
  363. // A[4,5] = c * A[4,5] - s * A[2,4]
  364. //
  365. // q < k (k = 6)
  366. //
  367. // A[2,6] = c * A[2,6] + s * A[5,6]
  368. // A[5,6] = c * A[5,6] - s * A[2,6]
  369. //
  370. //-----------------------------------------------------------------------------
  371. static int
  372. step(void)
  373. {
  374. int count, i, j;
  375. count = 0;
  376. // for each upper triangle "off-diagonal" component do step2
  377. for (i = 0; i < n - 1; i++) {
  378. for (j = i + 1; j < n; j++) {
  379. if (D(i, j) != 0.0) {
  380. step2(i, j);
  381. count++;
  382. }
  383. }
  384. }
  385. return count;
  386. }
  387. static void
  388. step2(int p, int q)
  389. {
  390. int k;
  391. double t, theta;
  392. double c, cc, s, ss;
  393. // compute c and s
  394. // from Numerical Recipes (except they have a_qq - a_pp)
  395. theta = 0.5 * (D(p, p) - D(q, q)) / D(p, q);
  396. t = 1.0 / (fabs(theta) + sqrt(theta * theta + 1.0));
  397. if (theta < 0.0)
  398. t = -t;
  399. c = 1.0 / sqrt(t * t + 1.0);
  400. s = t * c;
  401. // D = GD
  402. // which means "add rows"
  403. for (k = 0; k < n; k++) {
  404. cc = D(p, k);
  405. ss = D(q, k);
  406. D(p, k) = c * cc + s * ss;
  407. D(q, k) = c * ss - s * cc;
  408. }
  409. // D = D transpose(G)
  410. // which means "add columns"
  411. for (k = 0; k < n; k++) {
  412. cc = D(k, p);
  413. ss = D(k, q);
  414. D(k, p) = c * cc + s * ss;
  415. D(k, q) = c * ss - s * cc;
  416. }
  417. // Q = GQ
  418. // which means "add rows"
  419. for (k = 0; k < n; k++) {
  420. cc = Q(p, k);
  421. ss = Q(q, k);
  422. Q(p, k) = c * cc + s * ss;
  423. Q(q, k) = c * ss - s * cc;
  424. }
  425. D(p, q) = 0.0;
  426. D(q, p) = 0.0;
  427. }