package org.nd4j.linalg.eigen;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.nd4j.linalg.BaseNd4jTest;
import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.linalg.factory.Nd4j;
import org.nd4j.linalg.factory.Nd4jBackend;
import org.nd4j.linalg.eigen.Eigen;
import org.nd4j.linalg.eigen.Covariance;
import org.nd4j.linalg.inverse.InvertMatrix;
import org.nd4j.linalg.util.ArrayUtil;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

/**
 * Created by rcorbish
 */
@RunWith(Parameterized.class)
public class TestEigen extends BaseNd4jTest {

    public TestEigen(Nd4jBackend backend) {
        super(backend);
    }

    // test of functions added by Luke Czapla
    // Compares solution of A x = L x  to solution to A x = L B x when it is simple

    @Test
    public void testCovarianceSyev() {
	INDArray m = Nd4j.randn(10000, 6);
        m.getColumn(0).muli(4.84);
        m.getColumn(1).muli(4.84);
        m.getColumn(2).muli(4.01);
        m.getColumn(1).addi(m.getColumn(2).div(2.0));
        m.getColumn(2).addi(34.286);
        m.getColumn(3).muli(1.0/7.07);
        m.getColumn(4).muli(1.0/7.07);
        m.getColumn(5).muli(1.0/7.07);
        m.getColumn(4).subi(m.getColumn(5).div(2.0));
        m.getColumn(5).addi(3.4);
        INDArray[] result = Covariance.principalComponents(Covariance.covarianceMatrix(m));
	assert result[0].columns() == 6 && result[0].rows() == 6 && result[1].columns() == 6;

    }

    @Test
    public void test2Syev() {
    	double[][] matrix = new double[][] {{0.0427, -0.04, 0, 0, 0, 0}, {-0.04, 0.0427, 0, 0, 0, 0}, {0, 0.00, 0.0597, 0, 0, 0}, {0, 0, 0, 50, 0, 0}, {0, 0, 0, 0, 50, 0}, {0, 0, 0, 0, 0, 50}};
	INDArray m = Nd4j.create(ArrayUtil.flattenDoubleArray(matrix), new int[] {6,6});
	INDArray res = Eigen.symmetricGeneralizedEigenvalues(m, true);
	
	INDArray n = Nd4j.create(ArrayUtil.flattenDoubleArray(matrix), new int[] {6,6});
	INDArray res2 = Eigen.symmetricGeneralizedEigenvalues(n, Nd4j.eye(6).mul(2.0), true);

	for (int i = 0; i < 6; i++) {
		assertEquals(res.getDouble(i), 2*res2.getDouble(i), 0.000001);
	}
	
    }

    @Test
    public void testSyev() {
	    INDArray A = Nd4j.create( new float[][] { 
	    	 { 1.96f,  -6.49f,  -0.47f,  -7.20f,  -0.65f },
		 { -6.49f,  3.80f,  -6.39f,  1.50f,  -6.34f },
		 { -0.47f, -6.39f,  4.17f,  -1.51f,  2.67f },
		 { -7.20f,  1.50f, -1.51f,  5.70f,  1.80f },
		 { -0.65f, -6.34f,  2.67f,  1.80f, -7.10f }
	    } ) ;

	    INDArray B = A.dup() ;
	    INDArray e = Eigen.symmetricGeneralizedEigenvalues(A) ;
	    
	    for( int i=0 ; i<A.rows() ; i++ ) { 
		    INDArray LHS = B.mmul( A.slice(i,1) ) ;
		    INDArray RHS = A.slice(i,1).mul( e.getFloat(i) ) ;
		    
		    for( int j=0 ; j<LHS.length() ; j++ ) {
		    	assertEquals( LHS.getFloat(j), RHS.getFloat(j), 0.001f ) ;
		    }
	    }    
	}


    @Override
    public char ordering() {
        return 'f';
    }
}

@@ -324,49 +324,8 @@
 en;%0A
-import org.nd4j.linalg.eigen.Covariance;%0A
 impo
@@ -810,682 +810,8 @@
 ple%0A
-%0A    @Test%0A    public void testCovarianceSyev() %7B%0A%09INDArray m = Nd4j.randn(10000, 6);%0A        m.getColumn(0).muli(4.84);%0A        m.getColumn(1).muli(4.84);%0A        m.getColumn(2).muli(4.01);%0A        m.getColumn(1).addi(m.getColumn(2).div(2.0));%0A        m.getColumn(2).addi(34.286);%0A        m.getColumn(3).muli(1.0/7.07);%0A        m.getColumn(4).muli(1.0/7.07);%0A        m.getColumn(5).muli(1.0/7.07);%0A        m.getColumn(4).subi(m.getColumn(5).div(2.0));%0A        m.getColumn(5).addi(3.4);%0A        INDArray%5B%5D result = Covariance.principalComponents(Covariance.covarianceMatrix(m));%0A%09assert result%5B0%5D.columns() == 6 && result%5B0%5D.rows() == 6 && result%5B1%5D.columns() == 6;%0A%0A    %7D%0A%0A
     

revert TestEigen