eigen.scm 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. #| -*-Scheme-*-
  2. Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
  3. 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
  4. 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Massachusetts
  5. Institute of Technology
  6. This file is part of MIT/GNU Scheme.
  7. MIT/GNU Scheme is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or (at
  10. your option) any later version.
  11. MIT/GNU Scheme is distributed in the hope that it will be useful, but
  12. WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with MIT/GNU Scheme; if not, write to the Free Software
  17. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,
  18. USA.
  19. |#
  20. ;;;; Simple code to find eigenvalues and eigenvectors of small systems.
  21. (define* (matrix->eigenvalues matrix #:optional expand-multiplicities?)
  22. (if (default-object? expand-multiplicities?)
  23. (set! expand-multiplicities? #t))
  24. (let ((x (generate-uninterned-symbol 'x)))
  25. (let ((poly
  26. (m:determinant
  27. (g:- matrix (g:* x (m:make-identity (m:dimension matrix)))))))
  28. (pcf:expression-> (expression poly)
  29. (lambda (pcf syms)
  30. (poly->roots pcf expand-multiplicities?))))))
  31. (define* (real-matrix->eigenvalues-eigenvectors matrix #:optional cutoff)
  32. (if (default-object? cutoff)
  33. (set! cutoff (* 1000 *machine-epsilon*)))
  34. (let ((eigenvalues (matrix->eigenvalues matrix #f)))
  35. (map (lambda (root)
  36. (let ((m (car root)) ; multiplicity
  37. (x (cdr root)))
  38. (svd (g:- matrix (g:* x (m:make-identity (m:dimension matrix))))
  39. (lambda (U SIGMA V W)
  40. (let ((n (vector-length W))
  41. (minw
  42. (* cutoff (apply max (map abs (vector->list W))))))
  43. (cons x
  44. (let lp ((i 0))
  45. (cond ((fix:= i n) '())
  46. ((< (abs (vector-ref W i)) cutoff)
  47. (cons (m:nth-col V i)
  48. (lp (fix:+ i 1))))
  49. (else
  50. (lp (fix:+ i 1)))))))))))
  51. eigenvalues)))
  52. (define (matrix->eigenvalues-eigenvectors matrix)
  53. (let ((eigenvalues (matrix->eigenvalues matrix #f)))
  54. (map (lambda (root)
  55. (let ((m (car root)) ; multiplicity
  56. (x (cdr root)))
  57. (cons x
  58. (lu-null-space
  59. (g:- matrix
  60. (g:* x (m:make-identity (m:dimension matrix))))))))
  61. eigenvalues)))
  62. #|
  63. ;;; For example, this system has 3 distinct eigenvalues and
  64. ;;; corresponding eigenvectors:
  65. (pp (matrix->eigenvalues-eigenvectors
  66. (matrix-by-rows '(2 -1 0)
  67. '(-1 2 -1)
  68. '(0 -1 2))))
  69. ((.585786437626913 #(.5000000000000014 .7071067811865455 .5000000000000014))
  70. (2. #(-.7071067811865475 0. .7071067811865475))
  71. (3.414213562373087 #(.5000000000000014 -.7071067811865455 .5000000000000014)))
  72. ;;; For systems with multiplicity the multiple eigenvectors appear
  73. ;;; with the multiple root:
  74. (pp (matrix->eigenvalues-eigenvectors
  75. (matrix-by-rows '(0 0 0)
  76. '(0 1 0)
  77. '(0 0 1))))
  78. ((0. #(1 0 0)) (1. #(0 0 1) #(0 1 0)))
  79. ;;; A real example: the standard map at a hyperbolic point.
  80. (pp (matrix->eigenvalues-eigenvectors
  81. (a^m_n->mmn
  82. (let ((K 1))
  83. ((D (lambda (v)
  84. (let ((x (ref v 0))
  85. (y (ref v 1)))
  86. (let ((yp (+ y (* K (sin x)))))
  87. (up (+ x yp) yp)))))
  88. (up 0 0))))))
  89. ((.38196601125010315 #(-.525731112119133 .8506508083520402))
  90. (2.6180339887498967 #(.8506508083520401 .5257311121191331)))
  91. ;;; Pavel's test
  92. (pp (matrix->eigenvalues-eigenvectors
  93. (matrix-by-rows '(1 1)
  94. '(0 1))))
  95. ((1. #(1 0)))
  96. (pp (matrix->eigenvalues-eigenvectors
  97. (matrix-by-rows '(13 -4 2)
  98. '(-4 13 -2)
  99. '(2 -2 10))))
  100. ((9. #(-.4472135954999579 0. .8944271909999159)
  101. #(.7071067811865475 .7071067811865475 0.))
  102. (17.999999999999954
  103. #(.6666666666666701 -.6666666666666624 .33333333333333504)))
  104. (pp (matrix->eigenvalues-eigenvectors
  105. (matrix-by-rows '(1 2 3)
  106. '(4 5 6)
  107. '(7 8 9))))
  108. ((0.
  109. #(.4082482904638631 -.8164965809277261 .4082482904638631))
  110. (-1.1168439698070243
  111. #(-.7858302387420639 -.08675133925663416 .6123275602288135))
  112. (16.116843969807025
  113. #(.2319706872462861 .5253220933012344 .8186734993561811)))
  114. (pp (matrix->eigenvalues-eigenvectors
  115. (matrix-by-rows '(2 0 0 0)
  116. '(1 2 0 0)
  117. '(0 0 2 0)
  118. '(0 0 0 2))))
  119. ((2. #(0. 0. 0. 1.) #(0. 0. 1. 0.) #(0. 1. 0. 0.)))
  120. (pp (matrix->eigenvalues-eigenvectors
  121. (matrix-by-rows '(2 0 0 0)
  122. '(1 2 0 0)
  123. '(0 0 2 0)
  124. '(0 0 1 2))))
  125. ((2. #(0. 0. 0. 1.) #(0. 1. 0. 0.)))
  126. |#
  127. #|
  128. ;;; Bug!
  129. (define A
  130. (matrix-by-rows (list 8 0 3/16)
  131. (list 0 8 3/16)
  132. (list 3/16 3/16 8)))
  133. (pp (matrix->eigenvalues-eigenvectors A))
  134. ((7.7348349570559485) (7.9999999999982006) (8.265165042945835))
  135. #|
  136. ;; Eigenvects missing -- answer should have been (matlab sez)
  137. ((7.7348349570559485 #(1 0 1))
  138. (7.9999999999982006 #(.7071 1 -.7071))
  139. (8.265165042945835 #(.7071 -1 -.7071)))
  140. |#
  141. (lu-null-space
  142. (g:- A
  143. (g:* 8 (m:make-identity (m:dimension A)))))
  144. ;Value: (#(-.7071067811865475 .7071067811865475 0.))
  145. (lu-null-space
  146. (g:- A
  147. (g:* 7.9999999999982006 (m:make-identity (m:dimension A)))))
  148. ;Value: ()
  149. (real-matrix->eigenvalues-eigenvectors A)
  150. ;Value: ((7.7348349570559485) (7.9999999999982006) (8.265165042945835))
  151. (pp (real-matrix->eigenvalues-eigenvectors A (* *machine-epsilon* 1e4)))
  152. ((7.7348349570559485 #(-.5 -.49999999999999994 .7071067811865475))
  153. (7.9999999999982006 #(.7071067811865475 -.7071067811865475 -3.465221769689776e-27))
  154. (8.265165042945835 #(.49999999999999994 .49999999999999967 .7071067811865474)))
  155. ;;; Indeed
  156. (/ (* A #(-1/2 -1/2 (/ (sqrt 2) 2))) 7.7348349570559485)
  157. ;Value: #(-.49999999999994155 -.49999999999994155 .707106781186465)
  158. ;;; And, indeed:
  159. (set! heuristic-zero-test-bugger-factor 1e-11)
  160. (pp (matrix->eigenvalues-eigenvectors A))
  161. ((7.7348349570559485
  162. #(-.5000000000008521 -.5000000000008521 .7071067811853424))
  163. (7.9999999999982006 #(-.7071067811865475 .7071067811865475 0.))
  164. (8.265165042945835
  165. #(.49999999999917066 .49999999999917066 .7071067811877204)))
  166. ;;; Problem is roots are not good enuf for null-space test
  167. (pe (determinant (- A (* 'lam (m:identity-like A)))))
  168. (+ (* -1 (expt lam 3)) (* 24 (expt lam 2)) (* -24567/128 lam) 8183/16)
  169. ((lambda (lam)
  170. (+ (* -1 (expt lam 3)) (* 24 (expt lam 2)) (* -24567/128 lam) 8183/16))
  171. 8)
  172. ;Value: 0
  173. ((lambda (lam)
  174. (+ (* -1 (expt lam 3)) (* 24 (expt lam 2)) (* -24567/128 lam) 8183/16))
  175. 7.9999999999982006)
  176. ;Value: -1.1368683772161603e-13
  177. ;;; ugh!
  178. ;;; but I can generally not do better:
  179. (zbrent (lambda (lam)
  180. (+ (* -1 (expt lam 3)) (* 24 (expt lam 2)) (* -24567/128 lam) 8183/16))
  181. 7.9999999999982006
  182. 8.0003)
  183. ;Value: (#t 8.000000000001434 3)
  184. (- 8.000000000001434 8)
  185. ;Value: 1.4335199693960021e-12
  186. |#