/*
 * PowerMethod.java
 *
 * Created on October 28, 2005, 10:02 AM
 */

package DDMT.Nodes;
import java.util.Vector;
import java.util.Random;
import java.io.*;
import Jama.*;
/**
 *
 * @author  kanishk1
 */

public class PowerMethod 
{
    double[][] Matrix;
    double EigVal ;
    double[] EigVec;
    int d ;
    
    public PowerMethod(double[][] A, int dimension, double precision) 
    {
        this.d = dimension;
        Matrix = new double[this.d][this.d];
        EigVec = new double[this.d];
        
        //copy the values of A to Matrix
        for (int i=0;i<this.d;i++)
        {
            for (int j=0;j<this.d;j++)
                this.Matrix[i][j] = A[i][j];
        }
        
        double[] GuessVect = new double[this.d];
        Random r = new Random();
        //initial guess
        for (int i=0;i<this.d;i++)
        {
            double t = r.nextDouble();
            GuessVect[i] = t;
        }
        int iter = 0;
        
        double stopNorm = 1.0;
        
        while(stopNorm>precision)
        {
            this.EigVec = this.Multiply(this.Matrix,GuessVect);
            stopNorm = Math.abs(this.Norm(GuessVect)-this.EigVal);
            this.EigVal = this.Norm(GuessVect);
            for (int i=0;i<GuessVect.length;i++)
                GuessVect[i] = this.EigVec[i]/this.EigVal;
        }
        
        for (int i=0;i<GuessVect.length;i++)
                this.EigVec[i] = GuessVect[i]/this.EigVal;
            
//        System.out.println("Tick       : "+Tick+"\n");
//        System.out.println("EigenValue : "+this.EigVal);
//        System.out.println("EigenVect  : \n"+this.MakeString(this.EigVec));
        
        this.AppendFile("c:\\RefEig.txt",this.MakeString(this.EigVec));
        this.AppendFile("c:\\RefEig.txt",this.EigVal+"\n\n");
    }
    
    public PowerMethod(double[][] A, int dimension, double precision,int Tick) 
    {
        this.d = dimension;
        Matrix = new double[this.d][this.d];
        EigVec = new double[this.d];
        
        //copy the values of A to Matrix
        for (int i=0;i<this.d;i++)
        {
            for (int j=0;j<this.d;j++)
                this.Matrix[i][j] = A[i][j];
        }
        
        double[] GuessVect = new double[this.d];
        Random r = new Random();
        //initial guess
        for (int i=0;i<this.d;i++)
        {
            double t = r.nextDouble();
            GuessVect[i] = t;
        }
        int iter = 0;
        
        double stopNorm = 1.0;
        
        while(stopNorm>precision)
        {
            this.EigVec = this.Multiply(this.Matrix,GuessVect);
            stopNorm = Math.abs(this.Norm(GuessVect)-this.EigVal);
            this.EigVal = this.Norm(GuessVect);
            for (int i=0;i<GuessVect.length;i++)
                GuessVect[i] = this.EigVec[i]/this.EigVal;
        }
        
        for (int i=0;i<GuessVect.length;i++)
                this.EigVec[i] = GuessVect[i]/this.EigVal;
            
//        System.out.println("Tick       : "+Tick+"\n");
//        System.out.println("EigenValue : "+this.EigVal);
//        System.out.println("EigenVect  : \n"+this.MakeString(this.EigVec));
    }
    
    public double[] Multiply(double[][] a, double[] b)
    {
        //for generating EigVect
        double[] R = new double[this.d];
        
        for (int i=0;i<this.d;i++)
            for (int j=0;j<this.d;j++)
                R[i] += a[i][j]*b[j];
        
        return R;
    }
    
    public double Norm(double[] p)
    {
        double temp = 0.0;
        for (int i=0;i<p.length;i++)
            temp += p[i]*p[i];
        return Math.sqrt(temp);
    }
    
    public static void AppendFile(String filename,String fileData) 
    {
        try 
        {
            BufferedWriter out = new BufferedWriter(new FileWriter(filename,true));
            out.write(fileData);
            out.close();
        }
        catch (IOException e) 
        {
            System.out.println("Writing exception");
        }
    }
    
    public static void WriteFile(String filename,String fileData) 
    {
        try 
        {
            BufferedWriter out = new BufferedWriter(new FileWriter(filename));
            out.write(fileData);
            out.close();
        }
        catch (IOException e) 
        {
            System.out.println("Writing exception");
        }
    }
       
    public  String MakeString(double[] Pts)
    {
        String Data = "";
        for (int j=0;j<Pts.length;j++)
            Data = Data.concat(Double.toString(Pts[j])+"\n");
        return Data;
    }
    
    public double[] retEigVec()
    {
        return this.EigVec;
    }
    
    public double retEigVal()
    {
        return this.EigVal;
    }
    
    public static double[][] MatrixMultiply(double[][] a, double[][] b, int m, int n,int p)
    {
        double[][] result = new double[m][p];
        for (int i=0;i<m;i++)
            for (int j=0;j<p;j++)
                for (int k=0;k<n;k++)
                    result[i][j] += a[i][k]*b[k][j];
        return result;
    }
    
    public static void main(String[] args) 
    {
        int SIZE_OF_DATABASE = 50;
        int dimension = 15;
        double[][] A = new double[dimension][dimension];
        Vector S_it = new Vector();
        
        DataGen dg = new DataGen(2);
        
        for (int i=0;i<SIZE_OF_DATABASE;i++)
        {
            dg.GenPoint(1, 0.1, 1);
            Point p = (Point)dg.GetPoint();
            S_it.add(p);
        }
        
        for (int i=0;i<dimension;i++)
            for (int j=0;j<dimension;j++)
                A[i][j] = 0;
        
        for (int i=0;i<S_it.size();i++)
        {
            Point p = (Point)S_it.elementAt(i);
            int x = (int)p.x[0];
            int y = (int)p.x[1];
            if (dimension/2+x>=0&&x<dimension/2)
                if (dimension/2+y>=0&&y<dimension/2)
                    A[dimension/2+x][dimension/2+y] += 1;
        }
        
        for (int i=0;i<dimension;i++)
            for (int j=0;j<dimension;j++)
                A[i][j] /=SIZE_OF_DATABASE;
        
        PowerMethod pw = new PowerMethod(A,dimension,0.001);
        
        
        /*
        double[] means = new double[numcols];
        int numPCA = 10;
        String FileName = "C:\\DataInitial.txt";
        try
        {
            File file = new File(FileName);
            byte buffer[] = new byte[(int)file.length()];
            BufferedInputStream input = new BufferedInputStream(new FileInputStream(file));
            input.read(buffer,0,buffer.length);
            input.close();					 
            String fileData = new String(buffer);
            String[] result = fileData.split("\n");
            for (int i=0;i<result.length;i++)
            {
                System.out.println(i);
                String[] comp = result[i].split("\t");
                for (int j=0;j<comp.length;j++)
                    A[i][j] = Double.parseDouble(comp[j].trim());
            }
            
            //find the means of the data
            for (int i=0;i<numcols;i++)
                for (int j=0;j<numrows;j++)
                    means[i] += A[j][i];

            for (int i=0;i<means.length;i++)
                means[i] /= numcols;
            
            OwnMatrix mt = new OwnMatrix(A,numrows,numcols);
            OwnMatrix m = mt.getCov();
            String toWrite = "";
//            for (int i=0;i<numcols;i++)
//            {
//                System.out.println(i);
//                for (int j=0;j<numcols;j++)
//                   toWrite = toWrite.concat(m.A[i][j]+"\t");
//                toWrite = toWrite.concat("\n");
//                AppendFile("C:\\Cov.txt",toWrite);
//                toWrite = "";
//            }
            
            Matrix jamaMatrix = new Matrix(m.A);
            EigenvalueDecomposition evd = new EigenvalueDecomposition(jamaMatrix);
            Matrix eigenvect = evd.getV();
            Matrix eigenval = evd.getD();
            int rows = eigenvect.getRowDimension();
            int cols = eigenvect.getColumnDimension();
            double[][] eigenVector = new double[rows][cols];
            eigenVector = eigenvect.getArray();
            double[][] eigenValue = new double[rows][cols];
            eigenValue = eigenval.getArray();
            
            double[][] TopeigenValue = new double[numPCA][cols];
            double[][] TopeigenVector = new double[rows][numPCA];
            
            for (int i=0;i<rows;i++)
            {
                for (int j=0;j<numPCA;j++)
                {
                    TopeigenVector[i][j] = eigenVector[i][cols-j-1];
                }
            }
            
            for (int i=0;i<numPCA;i++)
            {
                for (int j=0;j<cols;j++)
                {
                    TopeigenValue[i][j] = eigenValue[rows-i-1][j];
                }
            }
            
            
            toWrite = "";
            for (int i=0;i<numcols;i++)
            {
                System.out.println(i);
                AppendFile("C:\\Means.txt",means[i]+"\n");
            }
            
            toWrite = "";
            for (int i=0;i<rows;i++)
            {
                System.out.println(i);
                for (int j=0;j<numPCA;j++)
                    toWrite = toWrite.concat(TopeigenVector[i][j]+"\t");
                toWrite = toWrite.concat("\n");
                AppendFile("C:\\EigenVector.txt",toWrite);
                toWrite = "";
            }
//            WriteFile("C:\\EigenVector.txt",toWrite);
            
            toWrite = "";
            for (int i=0;i<numPCA;i++)
            {
                System.out.println(i);
                for (int j=0;j<cols;j++)
                   toWrite = toWrite.concat(TopeigenValue[i][j]+"\t");
               toWrite = toWrite.concat("\n");
            }
            WriteFile("C:\\EigenValue.txt",toWrite);
            
            //project the data on the eigenvectors
            double[][] projectedData = new double[numrows][numPCA];
            projectedData = MatrixMultiply(A,TopeigenVector,numrows,numcols,numPCA);
            
//            toWrite = "";
//            for (int i=0;i<numrows;i++)
//            {
//                System.out.println(i);
//                for (int j=0;j<numPCA;j++)
//                   toWrite = toWrite.concat(projectedData[i][j]+"\t");
//               toWrite = toWrite.concat("\n");
//               AppendFile("C:\\projectedData.txt",toWrite);
//               toWrite = "";
//            }
//            WriteFile("C:\\projectedData.txt",toWrite);
            
            Vector PointList = new Vector();
            for (int i=0;i<numrows;i++)
            {
                double[] temp = new double[numPCA];
                for (int j=0;j<numPCA;j++)
                    temp[j] = projectedData[i][j];
                Point p = new Point(temp,-1);
                PointList.add(p);
            }
            
            Kmeans km = new Kmeans(10,PointList,0.1,1,numPCA);
            
        }   
        catch(IOException e)
        {
            System.out.println(e);
        }
         **/
    }
}
