\ eigen33.4th \ \ Eigenvalues and eigenvectors for a 3x3 matrix. \ \ Requires: \ \ ans-words.4th \ struct-200x.4th \ fsl/fsl-util.4th \ fsl/dynmem.4th \ fsl/extras/vector.4th \ fsl/complex.4th \ fsl/cubic.4th \ fsl/lufact.4th \ fsl/backsub.4th \ \ Revisions: \ 2012-04-07 km Use KM/DNW's modules framework. BASE @ DECIMAL Begin-Module \ Some helper words \ Round fp value to u significant digits variable power : power-of-ten ( f -- n | return power of ten factor which scales f such that 0<|f'|<10) 0 power ! FDUP F0= IF FDROP 0 EXIT THEN FABS FDUP 1e F< IF BEGIN 10e F* -1 power +! FDUP 1e F>= UNTIL ELSE FDUP 10e F>= IF BEGIN 10e F/ 1 power +! FDUP 10e F< UNTIL THEN THEN FDROP power @ ; : significant-digits ( f u -- f' | round to u significant decimal digits ) >R FDUP power-of-ten R> 1- ABS 1 MAX SWAP - DUP >R s>f 10e FSWAP F** F* FROUND R> NEGATE s>f 10e FSWAP F** F* ; Public: : cpoly33 ( 'A -- a b c | compute coefficients of the characteristic polynomial for 3x3 matrix) >R R@ 0 0 }} F@ R@ 1 1 }} F@ R@ 2 2 }} F@ F+ F+ FNEGATE \ a R@ 0 0 }} F@ R@ 1 1 }} F@ F* R@ 1 1 }} F@ R@ 2 2 }} F@ F* F+ R@ 0 0 }} F@ R@ 2 2 }} F@ F* F+ R@ 1 2 }} F@ R@ 2 1 }} F@ F* F- R@ 0 1 }} F@ R@ 1 0 }} F@ F* F- R@ 0 2 }} F@ R@ 2 0 }} F@ F* F- \ b R@ 0 0 }} F@ R@ 1 2 }} F@ F* R@ 2 1 }} F@ F* R@ 0 1 }} F@ R@ 1 0 }} F@ F* R@ 2 2 }} F@ F* F+ R@ 0 2 }} F@ R@ 1 1 }} F@ F* R@ 2 0 }} F@ F* F+ R@ 0 0 }} F@ R@ 1 1 }} F@ F* R@ 2 2 }} F@ F* F- R@ 0 1 }} F@ R@ 1 2 }} F@ F* R@ 2 0 }} F@ F* F- R@ 0 2 }} F@ R@ 1 0 }} F@ F* R@ 2 1 }} F@ F* F- \ c R> DROP ; 3 FLOAT array lambda{ : lambda33 ( 'A -- flag | compute eigenvalues of 3x3 real matrix; lambdas in z1,z2,z3) >R R@ cpoly33 cubic-roots R> drop \ store real parts of eigenvalues in the array lambda{ z1 z@ FDROP lambda{ 0 } F! z2 z@ FDROP lambda{ 1 } F! z3 z@ FDROP lambda{ 2 } F! ; Private: 3 3 FLOAT matrix A'{{ LUMATRIX lu3 3 FLOAT array b{ 3 FLOAT array y{ 3 FLOAT array w{ 3 FLOAT array z{ 3 FLOAT array zold{ Public: \ The normalized eigenvectors 3 3 FLOAT MATRIX e{{ FVARIABLE tol 1e-4 tol F! \ tolerance for eigenvector components : ?converged ( -- flag | check for convergence of iterated eigenvector solution z{ ) 3 0 DO zold{ i } F@ FABS z{ i } F@ FABS FOVER F- FABS FSWAP FDUP F0> IF F/ tol F@ F< ELSE FDROP FDROP TRUE THEN LOOP AND AND ; VARIABLE icount 100 CONSTANT MAX_ITER : eig33 ( 'A -- | compute eigenvalues and eigenvectors of 3x3 matrix ) dup lambda33 IF \ all 3 eigenvalues are real lu3 3 lu-malloc 3 0 DO DUP A'{{ 3 3 }}fcopy lambda{ i } F@ 4 significant-digits \ round lambda to 4 significant digits 3 0 DO A'{{ i i }} F@ FOVER F- A'{{ i i }} F! LOOP FDROP \ Check for zero diagonal elements on A'{{ -- if so, replace with small finite value 3 0 DO A'{{ i i }} F@ FABS tol F@ F< IF tol F@ A'{{ i i }} F! THEN LOOP A'{{ lu3 lufact lu3 b{ backsub-init drop \ Begin iterative solution of eigenvector 1e 1e 1e 3 y{ }fput 0e 0e 0e 3 z{ }fput 0 icount ! BEGIN z{ zold{ 3 }fcopy y{ b{ 3 }fcopy 3 solve-Ux=y b{ w{ 3 }fcopy \ Uw = y; solve for w w{ z{ 3 }fcopy 3 z{ vnorm z{ b{ 3 }fcopy 3 solve-Ly=b b{ y{ 3 }fcopy \ Ly = z; solve for y 1 icount +! icount @ MAX_ITER >= ABORT" *** CONVERGENCE FAILED *** " ?converged UNTIL \ CR 3 z{ }fprint 3 0 DO z{ I } F@ e{{ I J }} F! LOOP LOOP DROP lu3 lu-free ELSE DROP TRUE ABORT" Complex eigenvalues! We can't deal with them yet." THEN ; End-Module BASE ! \ Test case TEST-CODE? [IF] [undefined] T{ [IF] include ttester.4th [THEN] DECIMAL 1e-14 rel-near F! 1e-14 abs-near F! set-near 3 3 FLOAT matrix A{{ 2e 1e 0e 1e 3e 1e 0e 1e 4e 3 3 A{{ }}fput \ CR .( The test matrix is: ) CR \ 3 3 A{{ }}fprint TESTING lambda33 A{{ lambda33 drop t{ z1 z@ fdrop -> 1.26794919243112e r}t t{ z2 z@ fdrop -> 4.73205080756888e r}t t{ z3 z@ fdrop -> 3e r}t 1e-4 rel-near F! 1e-4 abs-near F! \ CR CR .( The corresponding eigenvectors are: ) CR TESTING eig33 A{{ eig33 \ First eigenvector t{ e{{ 0 0 }} F@ -> -0.788675134594813e r}t t{ e{{ 1 0 }} F@ -> 0.577350269189626e r}t t{ e{{ 2 0 }} F@ -> -0.211324865405187e r}t \ Second eigenvector t{ e{{ 0 1 }} F@ -> 0.211324865405187e r}t t{ e{{ 1 1 }} F@ -> 0.577350269189626e r}t t{ e{{ 2 1 }} F@ -> 0.788675134594813e r}t \ Third eigenvector t{ e{{ 0 2 }} F@ -> -0.577350269189625e r}t t{ e{{ 1 2 }} F@ -> -0.577350269189626e r}t t{ e{{ 2 2 }} F@ -> 0.577350269189626e r}t [THEN]