/**********************************************************
 * 
 * This is a test file for local_square_classes.m
 * 
 * It performs a cross-check of LocalGroupOfSquaresClasses 
 * against the built-in method LocalMultiplicativeGroupModSquares
 * for each combination of the inertia degree and ramification
 * index.
 * 
 *********************************************************/

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

// how many fields to test for each pair (e,f)
// (provided that enough fields exist)
NUM_OF_FIELDS := 20;

// import the list of dyadic fields from https://www.lmfdb.org/
import "lmfdb_lf_dyadic_fields.m" : data;

R<x> := PolynomialRing(Rationals());

procedure run_tests( K )
    printf ".";
    p :=  PrimeFactorization(K, 2)[1][1];

    // compute the local square-class groups in three ways
    G, mG := LocalMultiplicativeGroupModSquares(p);
    H, mH := LocalGroupOfSquaresClasses(p);

    // construct the change-of-basis matrices
    M := Matrix([ h @ mH @@ mG : h in Basis(H) ]);
    N := Matrix([ g @ mG @@ mH : g in Basis(G) ]);

    // the matrices must be mutually inverse
    assert IsOne(M*N);
end procedure;

// extract all ramification indices and inertia degrees
I := {@ <d[4],d[5]> : d in data @};

// run the tests for all e's and f's
for ef in I do
    printf "e = %o, f = %o:\t", ef[1], ef[2];
    // find all fields with a given ramification index
    // and inertia degree
    fields := [d : d in data | <d[4],d[5]> eq ef];
    // select NUM_OF_FIELDS random elements
    // (or take all if there are not enough)
    if #fields gt NUM_OF_FIELDS then
        inx := { Integers() | };
        while #inx lt NUM_OF_FIELDS do
            Include(~inx, Random([1..#fields]));
        end while;
        fields := fields[ Setseq(inx) ];
    end if;
    // run the tests on the picked fields
    for rec in fields do
        K<t> := NumberField( R!rec[3] );
        run_tests(K);
    end for;
    printf "\n";
end for;

// a few more hand-picked fields with degree > 30
// (hence, no pre-compution used)

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

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

// 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);
printf "\ne = 2, f = 17:\t";
run_tests(K);

print "\nAll test passed!";
quit;
