/*
 * $Id$
 */

package edu.jas.arith;


import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;


/**
 * BigOctonion tests with JUnit.
 * @author Heinz Kredel
 */

public class BigOctonionTest extends TestCase {


    /**
     * main.
     */
    public static void main(String[] args) {
        junit.textui.TestRunner.run(suite());
    }


    /**
     * Constructs a <CODE>BigOctonionTest</CODE> object.
     * @param name String.
     */
    public BigOctonionTest(String name) {
        super(name);
    }


    /**
     * @return suite.
     */
    public static Test suite() {
        TestSuite suite = new TestSuite(BigOctonionTest.class);
        return suite;
    }


    BigOctonion a, b, c, d, e;


    BigOctonion fac;


    BigQuaternionRing cfac;


    @Override
    protected void setUp() {
        a = b = c = d = e = null;
        cfac = new BigQuaternionRing();
        fac = new BigOctonion(cfac);
    }


    @Override
    protected void tearDown() {
        a = b = c = d = e = null;
        fac = null;
    }


    /**
     * Test static initialization and constants.
     */
    public void testConstants() {
        a = fac.getZERO();
        b = fac.getONE();
        c = b.subtract(b);

        assertEquals("1-1 = 0", c, a);
        assertTrue("1-1 = 0", c.isZERO());
        assertTrue("1 = 1", b.isONE());

        a = fac.getZERO();
        b = fac.getONE();
        c = b.subtract(b);
        assertEquals("1-1 = 0", c, a);
    }


    /**
     * Test bitLength.
     */
    public void testBitLength() {
        a = fac.getZERO();
        b = fac.getONE();
        c = b.random(10);
        //System.out.println("c = " + c); //.toScript());
        //System.out.println("len(c) = " + c.bitLength());

        assertEquals("len(0) = 24", 24, a.bitLength());
        assertEquals("len(1) = 25", 25, b.bitLength());
        assertEquals("len(-1) = 25", 25, b.negate().bitLength());
        assertTrue("len(random) >= 24", 24 <= c.bitLength());

        d = fac.I;
        assertEquals("len(i) = 25", 25, d.bitLength());
        assertEquals("len(-i) = 25", 25, d.negate().bitLength());
    }


    /**
     * Test constructor and toString.
     */
    public void testConstructor() {
        a = new BigOctonion(cfac, "6/8");
        b = new BigOctonion(cfac, "3/4");
        assertEquals("6/8 = 3/4", a, b);

        a = new BigOctonion(cfac, "3/4 i 4/5 j 1/5 k 2/5");
        b = new BigOctonion(cfac, "-3/4 i -4/5 j -1/5 k -2/5");
        assertEquals("3/4 + i 4/5 + j 1/5 + k 2/5", a, b.negate());

        String s = "6/1111111111111111111111111111111111111111111";
        a = new BigOctonion(cfac, s);
        String t = a.toString();
        assertEquals("stringConstr = toString", s, t);

        String sr = "3/4 i 4/5 j 1/5 k 2/5";
        String si = "-3/4 i -4/5 j -1/5 k -2/5";
        s = sr + " o " + si;
        a = new BigOctonion(cfac, s);
        BigQuaternion qr = new BigQuaternion(cfac, sr);
        BigQuaternion qi = new BigQuaternion(cfac, si);
        b = new BigOctonion(qr, qi);
        assertEquals("s = " + s, a, b);

        a = new BigOctonion(cfac, 1);
        b = new BigOctonion(cfac, -1);
        c = b.sum(a);
        assertTrue("1 = 1", a.isONE());
        assertEquals("1+(-1) = 0", c, fac.getZERO());
    }


    /**
     * Test random rationals.
     */
    public void testRandom() {
        a = fac.random(10);

        b = new BigOctonion(a.getR(), a.getI());
        c = b.subtract(a);
        assertEquals("a-b = 0", fac.getZERO(), c);

        d = new BigOctonion(b.getR(), b.getI());
        assertEquals("sign(a-a) = 0", 0, b.compareTo(d));
    }


    /**
     * Test addition.
     */
    public void testAddition() {
        a = fac.random(10);
        b = a.sum(a);
        c = b.subtract(a);

        assertEquals("a+a-a = a", c, a);
        assertEquals("a+a-a = a", 0, c.compareTo(a));

        d = a.sum(fac.getZERO());
        assertEquals("a+0 = a", d, a);
        d = a.subtract(fac.getZERO());
        assertEquals("a-0 = a", d, a);
        d = a.subtract(a);
        assertEquals("a-a = 0", d, fac.getZERO());
    }


    /**
     * Test multiplication.
     */
    public void testMultiplication() {
        a = fac.random(10);
        //System.out.println("a = " + a);

        b = a.multiply(a);
        c = b.divide(a);
        assertEquals("a*a/a = a", c, a);
        assertEquals("a*a/a = a", 0, c.compareTo(a));

        d = a.multiply(fac.getONE());
        assertEquals("a*1 = a", d, a);
        d = a.divide(fac.getONE());
        assertEquals("a/1 = a", d, a);

        a = fac.random(30);
        b = a.inverse();
        c = a.multiply(b);
        assertTrue("a*1/a = 1", c.isONE());

        b = a.abs();
        c = b.inverse();
        d = b.multiply(c);
        assertTrue("abs(a)*1/abs(a) = 1", d.isONE());

        a = fac.random(30);
        b = a.norm(); //abs();
        //c = b.multiply(b);
        d = a.multiply(a.conjugate());
        assertEquals("norm(a) == a a^", b, d);

        c = a.abs();
        d = c.multiply(c);
        //assertEquals("norm() == abs()*abs(): ", b, d);
        BigRational dd = d.or.re.subtract(b.or.re).abs().divide(d.or.re.abs().sum(b.or.re.abs()));
        //System.out.println("dd = " + dd + ", d = " + d + ", b = " + b);
        BigRational eps = new BigRational(1,10).power(BigDecimal.DEFAULT_PRECISION-1);
        assertTrue("abs()*abs() == norm(): " + dd, dd.compareTo(eps) <= 0);

        b = fac.random(10);
        c = a.inverse();
        d = c.multiply(b);
        e = a.multiply(d);
        assertEquals("a*(1/a)*b = b", b, e);

        d = b.multiply(c);
        e = d.multiply(a);
        assertEquals("b*(1/a)*a = b", b, e);

        c = a.rightDivide(b);
        d = c.multiply(b);
        assertEquals("a*(1/b)*b = a", a, d);

        c = a.leftDivide(b);
        d = b.multiply(c);
        assertEquals("b*(1/b)*a = a", a, d);
    }


    /**
     * Test multiplication axioms.
     */
    public void testMultiplicationAxioms() {
        a = fac.random(20);
        b = fac.random(20);

        c = a.multiply(b);
        d = b.multiply(a);
        assertTrue("a*b != b*a", !c.equals(d));

        c = fac.random(20);

        d = a.multiply(b.multiply(c));
        e = a.multiply(b).multiply(c);
        assertTrue("a(bc) != (ab)c", !e.equals(d));
    }


    /**
     * Test distributive law.
     */
    public void testDistributive() {
        a = fac.random(20);
        b = fac.random(20);
        c = fac.random(20);

        d = a.multiply(b.sum(c));
        e = a.multiply(b).sum(a.multiply(c));

        assertEquals("a(b+c) = ab+ac", d, e);
    }

}
