/* * JacobiTransformation.java * * Copyright (c) 2002-2015 Alexei Drummond, Andrew Rambaut and Marc Suchard * * This file is part of BEAST. * See the NOTICE file distributed with this work for additional * information regarding copyright ownership and licensing. * * BEAST is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * BEAST is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with BEAST; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301 USA */ package dr.math.matrixAlgebra; import dr.math.iterations.IterativeProcess; /** * JacobiTransformation * * @author Didier H. Besset */ public class JacobiTransformation extends IterativeProcess { double[][] rows; double[][] transform; int p,q; //Indices of the largest off-diagonal element /** * Create a new instance for a given symmetric matrix. * @param m DhbMatrixAlgebra.SymmetricMatrix */ public JacobiTransformation (SymmetricMatrix m) { int n = m.rows(); rows = new double[n][n]; for ( int i = 0; i < n; i++) { for ( int j = 0; j < n; j++) rows[i][j] = m.components[i][j]; } } /** * @return double[] */ public double[] eigenvalues ( ) { int n = rows.length; double[] eigenvalues = new double[n]; for ( int i = 0; i < n; i++ ) eigenvalues[i] = rows[i][i]; return eigenvalues; } /** * @return DhbMatrixAlgebra.SymmetricMatrix */ public Vector[] eigenvectors ( ) { int n = rows.length; Vector[] eigenvectors = new Vector[n]; double[] temp = new double[n]; for ( int i = 0; i < n; i++ ) { for ( int j = 0; j < n; j++) temp[j] = transform[j][i]; eigenvectors[i] = new Vector( temp); } return eigenvectors; } public double evaluateIteration() { double offDiagonal = largestOffDiagonal(); transform(); return offDiagonal; } /** * @param m int */ private void exchange ( int m) { int m1 = m + 1; double temp = rows[m][m]; rows[m][m] = rows[m1][m1]; rows[m1][m1] = temp; int n = rows.length; for ( int i = 0; i < n; i++ ) { temp = transform[i][m]; transform[i][m] = transform[i][m1]; transform[i][m1] = temp; } } public void finalizeIterations ( ) { int n = rows.length; int bound = n - 1; int i, m; while ( bound >= 0 ) { m = -1; for ( i = 0; i < bound; i++ ) { if ( Math.abs( rows[i][i]) < Math.abs( rows[i+1][i+1]) ) { exchange( i); m = i; } } bound = m; } return; } public void initializeIterations() { transform = SymmetricMatrix.identityMatrix( rows.length).components; } /** * @return double absolute value of the largest off diagonal element */ private double largestOffDiagonal( ) { double value = 0; double r; int n = rows.length; for (int i = 0; i < n; i++) { for ( int j = 0; j < i; j++) { r = Math.abs( rows[i][j]); if ( r > value ) { value = r; p = i; q = j; } } } return value; } /** * Returns a string representation of the system. * @return java.lang.String */ public String toString() { StringBuffer sb = new StringBuffer(); char[] separator = { '[', ' '}; int n = rows.length; for ( int i = 0; i < n; i++) { separator[0] = '{'; for ( int j = 0; j <= i; j++) { sb.append( separator); sb.append( rows[i][j]); separator[0] = ' '; } sb.append('}'); sb.append('\n'); } return sb.toString(); } /** * @return DhbMatrixAlgebra.SymmetricMatrix */ private void transform ( ) { double apq = rows[p][q]; if ( apq == 0 ) return; double app = rows[p][p]; double aqq = rows[q][q]; double arp = ( aqq - app) * 0.5 / apq; double t = arp > 0 ? 1 / ( Math.sqrt( arp * arp + 1) + arp) : 1 / ( arp - Math.sqrt( arp * arp + 1)); double c = 1 / Math.sqrt( t * t + 1); double s = t * c; double tau = s / ( 1 + c); rows[p][p] = app - t * apq; rows[q][q] = aqq + t * apq; rows[p][q] = 0; rows[q][p] = 0; int n = rows.length; for ( int i = 0; i < n; i++ ) { if ( i != p && i != q ) { rows[p][i] = rows[i][p] - s *( rows[i][q] + tau * rows[i][p]); rows[q][i] = rows[i][q] + s *( rows[i][p] - tau * rows[i][q]); rows[i][p] = rows[p][i]; rows[i][q] = rows[q][i]; } arp = transform[i][p]; aqq = transform[i][q]; transform[i][p] = arp - s * ( aqq + tau * arp); transform[i][q] = aqq + s * ( arp - tau * aqq); } } }