# This routine uses subspace iteration to compute the first
# few eigenvalues and vectors for a real, symmetric, generalized
# eigenvalue problem A*V=B*V*w.

# Input:	`A'	A real, symmetric, non-singular matrix.
#		`B'	A real, symmetric, non-singular matrix.
#		`V'	A set of starting vectors.  The number
#			of columns specifies the number of modes.
#		`eps'	The convergence tolerance.
#		`n'	The number of accurate modes desired.

ssi = function( A; B; V; eps; n ) {

    if ( A.symmetry != "symmetric" | B.symmetry != "symmetric" ) {
        message( "run time error: Matrices must be symmetric for subspace iteration." )
	exception();
    }

    if ( A.type != "integer" & A.type != "real" |
	 B.type != "integer" & B.type != "real" |
	 V.type != "integer" & V.type != "real" ) {
	message( "run time error: Wrong input type for subspace iteration." );
	exception();
    }

    if ( eps == NULL ) { eps = 1.0E-6; }

    if ( n == NULL ) {
        if ( V.nc > 16 ) {
            n = V.nc - 8;
        else
            n = integer( (V.nc+1) / 2 );
        }
    else
        if ( n <= 0 | n > V.nc ) {
            message( "run time error: Illegal value for fifth argument." );
            exception();
        }
    }

    local ( lambda; tmp; Afac; Vb; e; d; i; r );
    lambda = diag( transform(A;V) ) / diag( transform(B;V) );

    n = 1:n;
    Afac = chol( A );
    while ( 1 ) {
        Vb = solve( Afac; B*V );
        e = eig( transform(A;Vb); transform(B;Vb) );
        d = e.values;
        tmp = abs( lambda - d );
        for ( i in n ) { tmp[i] = tmp[i] / d[i]; }
        r = tmp[ imax( tmp[n] ) ];
        lambda = e.values;
        V = Vb*e.vectors;
        if ( r < eps ) { break; }
    }

    return { values=e.values; vectors=V };

};


syntax highlighted by Code2HTML, v. 0.9.1