/**
 * This class exponentiates i times a real symmetric matrix.
 * 
 */
public class ExpiRealSym {
	private int	 _dim;
	private Complex[][]	_mat;
/**
 * 
 */
    public ExpiRealSym(
    	double[][] realSymMat){
    	Throw.If(realSymMat.length != realSymMat[0].length, 
    			"The matrix to be exponentiated is not square");
    	_dim = realSymMat.length;
    	_mat = new Complex[_dim][_dim];
    	//at this point, all _mat[row][col] are null
    	for(int row=0; row<_dim; row++){
    		for(int col=0; col<_dim; col++){
    			_mat[row][col] = new Complex(0.0);
    		}
    	}
    	int dimSq = _dim*_dim;
    	int row, col, index;
    	
    	char jobz_j = 'V';
    	char uplo_j = 'U';
    	int n_j = _dim;
     	double[] a_j = new double[dimSq];
     	for(index=0; index < dimSq; index++){
    		a_j[index] = realSymMat[index%_dim][index/_dim];  			
    	}
    	int	 lda_j = n_j;
     	double[] w_j = new double[n_j];
   	
    	int			lwork_j = 4*n_j;
    	double[]	work_j = new double[lwork_j];
    	int[]		info_j = {0};
    	
    	NativeLinAlg.dsyev(	jobz_j,
    			uplo_j, 
    			n_j,
    			a_j,
    			lda_j,
    			w_j,	
    			work_j,
    			lwork_j,
    			info_j);
    	Throw.If(info_j[0] != 0, "clapack error");

    	double[][] omega = new double[n_j][n_j];
    	for(index=0; index < dimSq; index++){
    		omega[index%_dim][index/_dim] = a_j[index]; 			
    	}

     	for(row=0; row < n_j; row++){
    		for(col=0; col < n_j; col++){
    			_mat[row][col].re = 0;
    			_mat[row][col].im = 0;
	    		for(int k=0; k < n_j; k++){
	    			_mat[row][col].re += 
	    				omega[row][k]*Math.cos(w_j[k])*omega[col][k];
	    			_mat[row][col].im += 
	    				omega[row][k]*Math.sin(w_j[k])*omega[col][k];
	    		}
    		}
    	}
	
    }
/**
 * 
 */
    public int getDimension() {
        	return _dim;
    }
    
/**
 * 
 */
    public Complex getEntry(int row, int col) {
    	return _mat[row][col];
    }

/**
*
*/    
    public String toString(){
    	String output = "";
    	output += "dimension= "+ _dim + '\n';
	   
    	output += "Real part:" + '\n';
    	int row, col;
    	for(row=0; row<_dim; row++){
    		for(col=0; col<_dim; col++){
	           output += getEntry(row, col).re + " ";
    		}
    		output += '\n';
    	}
	
    	output += "Imag part:" + '\n';
    	for(row=0; row<_dim; row++){
    		for(col=0; col<_dim; col++){
    			output += getEntry(row, col).im + " ";            
    		}
    		output += '\n';
    	}
	       
    	return output;
    }
/**
*
*/    
	public static void main(String[] args){
		//int numBits = 3;
		int dim = 8;
		double strength = 1/Math.sqrt(2);
		
		int[][] 	incMat = { 
		{0,0,0,0,0,0,0,0},
		{0,0,1,1,0,0,0,0},
		{0,1,0,0,1,1,0,0},
		{0,1,0,0,0,0,1,1},
		{0,0,1,0,0,0,0,0},
		{0,0,1,0,0,0,0,0},
		{0,0,0,1,0,0,0,0},
		{0,0,0,1,0,0,0,0}
		};
		System.out.println(incMat.toString());

		double[][] realSymMat = new double[dim][dim];    	
		int row, col;
		for(row=0; row<dim; row++){
			for(col=0; col<dim; col++){
				realSymMat[row][col] = strength*incMat[row][col];
			}
		}
		ExpiRealSym  expiMat = new ExpiRealSym(realSymMat);
		System.out.print(expiMat.toString());
	}

}
