import VisualNumerics.math.*;

/**
 *  Class for calculation of numerical equality
 *  with the help of Qaternions, for example,
 *
 *  ( 1^2 + 2^2 + 3^2 + 4^2 ) ( 2^2 + 3^2 + 4^2 + 5^2 ) =  -36^2 + 6^2 + 12^2 + 12^2
 *
 */
public class Quaternion {

    public static int[] qInt =  {1, 2, 3, 4};
    public static int[] pInt =  {2, 3, 4, 5};
    
    public static double[] qres = new double[4];


    public static void main (String[] args) {

        double[] q = new double[4];
        double[] p = new double[4];

        q[0] = qInt[0];
        q[1] = qInt[1];
        q[2] = qInt[2];
        q[3] = qInt[3];

        p[0] = pInt[0];
        p[1] = pInt[1];
        p[2] = pInt[2];
        p[3] = pInt[3];

        qres = mulQ(q, p);

        int[] qresInt = new int[4];
        qresInt[0] = (int)qres[0];
        qresInt[1] = (int)qres[1];
        qresInt[2] = (int)qres[2];
        qresInt[3] = (int)qres[3];

        System.out.println( "( " + qInt[0] + "^2 + " + qInt[1] + "^2 + " + qInt[2] + "^2 + " + qInt[3] + "^2 ) " +
                            "( " + pInt[0] + "^2 + " + pInt[1] + "^2 + " + pInt[2] + "^2 + " + pInt[3] + "^2 ) = " +
                           " " + qresInt[0] + "^2 + " + qresInt[1] + "^2 + " + qresInt[2] + "^2 + " + qresInt[3] + "^2" );
    }

   

    public static double[] addQ(double[]a, double[]b) {

        double[]c = new double[4];
        Complex[][]q1 = new Complex[2][2];
        Complex[][]q2 = new Complex[2][2];
        Complex[][]qres = new Complex[2][2];

        Complex z11 = new Complex(a[0], a[3]);
        Complex z12 = new Complex(a[1], a[2]);
        Complex z21 = new Complex(b[0], b[3]);
        Complex z22 = new Complex(b[1], b[2]);

        q1[0][0] = Complex.conjugate(z11);
        q1[0][1] = Complex.conjugate(Complex.negate(z12));
        q1[1][0] = z12;
        q1[1][1] = z11;

        q2[0][0] = Complex.conjugate(z21);
        q2[0][1] = Complex.conjugate(Complex.negate(z22));
        q2[1][0] = z22;
        q2[1][1] = z21;

        qres = ComplexMatrix.add(q1, q2);

        c[0] = qres[1][1].re;
        c[1] = qres[1][0].re;
        c[2] = qres[1][0].im;
        c[3] = qres[1][1].im;

        return c;
    }


    public static double[] subQ(double[]a, double[]b) {

        double[]c = new double[4];
        Complex[][]q1 = new Complex[2][2];
        Complex[][]q2 = new Complex[2][2];
        Complex[][]qres = new Complex[2][2];

        Complex z11 = new Complex(a[0], a[3]);
        Complex z12 = new Complex(a[1], a[2]);
        Complex z21 = new Complex(b[0], b[3]);
        Complex z22 = new Complex(b[1], b[2]);

        q1[0][0] = Complex.conjugate(z11);
        q1[0][1] = Complex.conjugate(Complex.negate(z12));
        q1[1][0] = z12;
        q1[1][1] = z11;

        q2[0][0] = Complex.conjugate(z21);
        q2[0][1] = Complex.conjugate(Complex.negate(z22));
        q2[1][0] = z22;
        q2[1][1] = z21;

        qres = ComplexMatrix.subtract(q1, q2);

        c[0] = qres[1][1].re;
        c[1] = qres[1][0].re;
        c[2] = qres[1][0].im;
        c[3] = qres[1][1].im;

        return c;
    }


    public static double[] mulQ(double[]a, double[]b) {

        double[]c = new double[4];
        Complex[][]q1 = new Complex[2][2];
        Complex[][]q2 = new Complex[2][2];
        Complex[][]qres = new Complex[2][2];

        Complex z11 = new Complex(a[0], a[3]);
        Complex z12 = new Complex(a[1], a[2]);
        Complex z21 = new Complex(b[0], b[3]);
        Complex z22 = new Complex(b[1], b[2]);

        q1[0][0] = Complex.conjugate(z11);
        q1[0][1] = Complex.conjugate(Complex.negate(z12));
        q1[1][0] = z12;
        q1[1][1] = z11;

        q2[0][0] = Complex.conjugate(z21);
        q2[0][1] = Complex.conjugate(Complex.negate(z22));
        q2[1][0] = z22;
        q2[1][1] = z21;

        qres = ComplexMatrix.multiply(q1, q2);

        c[0] = qres[1][1].re;
        c[1] = qres[1][0].re;
        c[2] = qres[1][0].im;
        c[3] = qres[1][1].im;

        return c;
    }
    
}