jacobi.sa


Generated by gen_html_sa_files from ICSI. Contact gomes@icsi.berkeley.edu for details
 
---------------------------> Sather 1.1 source file <--------------------------
-- jacobi.sa: jacobi method from NR
-- Author: Alex Cozzi <cozzi@neurop2.ruhr-uni-bochum.de>
 
-- COPYRIGHT NOTICE: This code is provided WITHOUT ANY WARRANTY
-- and is subject to the terms of the SATHER LIBRARY GENERAL PUBLIC
-- LICENSE contained in the file: Sather/Doc/License of the
-- Sather distribution. The license is also available from ICSI,
-- 1947 Center St., Suite 600, Berkeley CA 94704, USA.


class JACOBI

class JACOBI is jacobi(aa :MAT, out d :VEC, out v:MAT) :INT -- Compute all eigenvalues and eigenvectors of a real symmetric matrix -- a[N][N]. On output elements of a above the disgonal are destroyed. -- d[N] returns the eigenvalues of a. v[N][N] is a matrix whose columns -- contain, on output, the normalized eigenvectors of a. nrot returns -- the number of Jacobi rotations that were required. pre aa.size1 = aa.size2 -- and aa.is_simmetrical is thresh, theta, tau, t, sm, s, h, g, c :FLT; n ::= aa.size1; a ::= aa.copy; d := #(n); v := #(n, n); loop v.set!(0.0); end; loop ip ::= v.ind1!; v[ip, ip] := 1.0; end; --Initialize b and d to the diagonals of a b ::= #VEC(n); z ::= #VEC(n); loop ip ::= v.ind1!; b[ip] := a[ip, ip]; d[ip] := a[ip, ip]; z[ip] := 0.0; end; nrot ::= 0; loop i ::= 0.upto!(99); sm := 0.0; loop ip ::= 0.upto!(n-2); loop iq ::= (ip+1).upto!(n-1); sm := sm + a[ip, iq].abs; end; end; -- Normal return, which relies on quadratic convergence to -- machine underflow if sm = 0.0 then return nrot; end; if i<3 then thresh := 0.2 * sm/(n*n).flt; -- on the first three sweeps else thresh := 0.0; -- the rest of the sweeps end; loop ip ::= 0.upto!(n-2); loop iq ::= (ip+1).upto!(n-1); g := 100.0 * a[ip, iq].abs; -- After 4 sweeps skip the rotation if the -- off diagonal element is small if i>3 and d[ip].abs+g = d[ip].abs and d[iq].abs+g = d[iq].abs then a[ip, iq] := 0.0; elsif a[ip, iq].abs > thresh then h := d[iq]-d[ip]; if h.abs+g = h.abs then t := a[ip, iq]/h; else theta := 0.5*h/a[ip, iq]; t := 1.0/(theta.abs + (1.0 + theta.square).sqrt); if theta < 0.0 then t := -t; end; end; c := 1.0/(1.0+t*t).sqrt; s := t*c; tau := s/(1.0+c); h := t*a[ip, iq]; z[ip] := z[ip] - h; z[iq] := z[iq] + h; d[ip] := d[ip] - h; d[iq] := d[iq] + h; a[ip, iq] := 0.0; loop j::= 0.upto!(ip-2); rotate(a, j, ip, j, iq, inout h, inout g, s, tau); end; loop j::= (ip+1).upto!(iq-2); rotate(a, ip, j, j, iq, inout h, inout g, s, tau); end; loop j::= (iq+1).upto!(n-1); rotate(a, ip, j, iq, j, inout h, inout g, s, tau); end; loop j::= 0.upto!(n-1); rotate(v, j, ip, j, iq, inout h, inout g, s, tau); end; nrot := nrot + 1; end; end; end; loop ip::=0.upto!(n-1); b[ip] := b[ip] + z[ip]; d[ip] := b[ip]; z[ip] := 0.0; end; end; raise "\nFatal error: too many iterations in jacobi\n"; end; private rotate(a :MAT, i, j, k, l :INT, inout h, inout g, s, tau :FLT) -- Do rotations required by Jacobi Transformation is g := a[i, j]; h := a[k, l]; a[i, j] := g - s*(h+g*tau); a[k, l] := h + s*(g-h*tau); end; end;

class TEST_JACOBI

class TEST_JACOBI is include TEST; main is class_name("JACOBI"); m ::= #MAT(||1.0, 0.0| , |0.0, 1.0||); v :VEC; o :MAT; n ::= JACOBI::jacobi(m, out v, out o); test ("eigenvalues 1", v.str, "|1,1|"); test ("eigenvectors 1", o.str, "||1,0|,|0,1||"); m2::= #MAT(| |1.0, 2.0, 0.0|, |2.0, 1.0, 0.0|, |0.0, 0.0, -1.0| |); n := JACOBI::jacobi(m2, out v, out o); test ("eigenvalues 2", v.str, "|-1,3,-1|"); test ("eigenvectors 2", o.str, "||0.707107,0.707107,0|,|-0.707107,0.707107,0|,|0,0,1||"); m3 ::= #MAT(|| 4.0, -1.0, -1.0, -1.0 |,| -1.0, 4.0, -1.0, -1.0 |, | -1.0, -1.0, 4.0, -1.0 |,| -1.0, -1.0, -1.0, 4.0 ||); n := JACOBI::jacobi(m3, out v, out o); test ("eigenvalues 3", v.str, "|5,1,5,5|"); finish; end; end;