/**********************************************************
 * 
 * This is a test file for local_square_classes.m
 * 
 * It checks that given an element a, the coordinates of
 * its local square-class are correctly computed.
 * 
 *********************************************************/

// set the path to the package
import "path.m" : PATH_TO_LSC;
Attach(PATH_TO_LSC);

SetDebugOnError(true);

// Magma needs a size for Random intrinsic
SIZE := 4;

procedure run_tests( K : exhaustive := true, ntests := 64 )
// This routine tests the correctness of coordinate
// computation for a given field. 
// If exhaustive is set to true (default) it will
// exhaustively check the whole vector space.
// Otherwise. it does only random tests.
// The number of random tests is controlled by ntests.
    printf "o";

    // get the dyadic ideal
    p :=  PrimeFactorization(K, 2)[1][1];
    // compute the group of local square-classes (in two ways)
    G, mG := LocalGroupOfSquaresClasses(p);
    // extract the bases
    B := [ v @ mG : v in Basis(G) ];

    // check whether G -> K -> G is an identity
    if exhaustive then
        // check the whole vector space
        assert forall{ v : v in G | v eq (v @ mG @@ mG ) };
    else
        // check the basis (to make sure all possible quadratic
        // defects appear) and ntests random elements
        G_ := [ Random(G) : j in [1..ntests] ] cat Basis(G);
        assert forall{ v : v in G_ | v eq (v @ mG @@ mG ) };
    end if;

    // check whether the coordinates of two elements in the same
    // local square-class are equal; this test is always randomized
    // first, check the bases (to make sure all possible quadratic
    // defects appear)
    A := [ Random(K, SIZE) : i in [1..ntests] ];
    A := [ a : a in A | not IsZero(a) ];
    assert forall{ b : b in B | [ b @@ mG : a in A] eq [ (b*a^2) @@ mG : a in A ] };
    // now check ntests random elements
    for j in [1..ntests] do
        repeat a := Random(K, SIZE); until not IsZero(a);
        repeat b := Random(K, SIZE); until not IsZero(b);
        assert (a @@ mG) eq ((a*b^2) @@ mG);
    end for;
    printf "\bx";
end procedure;

R<x> := PolynomialRing(Rationals());
printf "............\b\b\b\b\b\b\b\b\b\b\b\b";

// The following list of fields should exhaust all the
// branches of the code

// LMFDB 2.5.0.1: e = 1, f = 5
K<t> := NumberField( R![1, 0, 1, 0, 0, 1] );
run_tests(K);

// LMRDB 2.5.4.1: e = 5, f = 1
K<t> := NumberField( R![2, 0, 0, 0, 0, 1] );
run_tests(K);

// LMFDB 2.4.6.3: e = 2, f = 2
K<t> := NumberField( R![84, 48, 28, 8, 1] );
run_tests(K);

// LMFDB 2.4.6.7: e = 4, f = 1
K<t> := NumberField( R![2, 0, 2, 2, 1] );
run_tests(K);

// LMFDB 2.4.0.1: e = 1, f = 4
K<t> := NumberField( R![1, 1, 0, 0, 1] );
run_tests(K);

// LMFDB 2.6.4.1: e = 3, f = 2
K<t> := NumberField( R![7, 11, 22, 19, 10, 3, 1] );
run_tests(K);

// LMFDB 2.6.6.2: e = 2, f = 3
K<t> := NumberField( R![72, 8, 44, 24, 14, 6, 1] );
run_tests(K);

// LMFDB 2.9.6.1: e = 3, f = 3
K<t> := NumberField( R![29, -27, 9, -26, 0, 3, 9, 3, 0, 1] );
run_tests(K);

// e = 31, f = 1, degree > 30 (so no precomputation used)
K<t> := NumberField(x^31 + 128);
run_tests(K : exhaustive := false);

// e = 1, f = 31, degree > 30 (so no precomputation used)
K<t> := NumberField(x^31 + x^3 + 1);
run_tests(K : exhaustive := false);

// e = 2, f = 17, degree > 30 (so no precomputation used)
K<t> := NumberField(x^34 + 2*x^20 + 2*x^17 + x^6 + 2*x^3 + 16*x + 1);
run_tests(K : exhaustive := false);

// example from a review
K<t> := NumberField(x^18 + 9*x^17 + 45*x^16 + 156*x^15 + 414*x^14 + 882*x^13 + 1554*x^12 + 2304*x^11 + 2907*x^10 + 3139*x^9 + 2907*x^8 + 2304*x^7 + 1554*x^6 + 882*x^5 + 414*x^4 + 156*x^3 + 45*x^2 + 9*x + 3);
run_tests(K : exhaustive := false);

print "\nAll tests passed.";
quit;
