// ***************************************************************
// ***** This is the file lifting_lowgonal_3.m accompanying ******
// *** LIFTING LOW-GONAL CURVES FOR USE IN TUITMAN'S ALGORITHM ***
// *********** by Wouter Castryck and Floris Vermeulen ***********
// ***************************************************************

// PARAMETERS

F<a> := FiniteField(5,9);
R<x> := PolynomialRing(F);
g := 9;
e := [3,4]; // MARONI INVS, SUM SHOULD BE g - 2;

print "----";
print "Testing our lifting procedure for a generic trigonal curve of genus", g;
print "over GF(", Characteristic(F),",", Degree(F), "), with Maroni invariants", e[1], e[2];
print "These should sum up to g - 2, which is", &+e eq g-2;
print "----";

if Degree(F) eq 1 then
    K := Rationals();
else
    K<a> := ext<Rationals() | PolynomialRing(Integers()) ! MinimalPolynomial(a)>;
end if;

// AUXILIARY FUNCTIONS FOR LIFTING

NaiveLiftEltModp := function(alpha)
  p := #Parent(alpha);
  lift := Integers() ! alpha;
  if lift gt p/2 then return lift - p; else return lift; end if;
end function;

NaiveLiftCoeff := function(alpha, K)
  n := Degree(K);
  if n eq 1 then
    return K ! NaiveLiftEltModp(alpha);
  else
    elt := Eltseq(alpha);
    return &+[NaiveLiftEltModp(elt[i])*K.1^(i-1) : i in [1..n]];
  end if;
end function;

NaiveLiftPol := function(pol, K);
  d := Degree(pol);
  return PolynomialRing(K) ! [NaiveLiftCoeff(alpha, K) : alpha in Eltseq(pol)]; 
end function;

// GENERATE RANDOM DEGREE 3 COVER WITH ABOVE PARAMETERS 
// AND SCRAMBLE OUTPUT SOMEWHAT

S<y> := PolynomialRing(R);

f0 := &+[Random(F)*x^i : i in [0..2*e[2]-e[1]+2]];
f1 := &+[Random(F)*x^i : i in [0..e[2]+2]];
f2 := &+[Random(F)*x^i : i in [0..e[1]+2]];
f3 := &+[Random(F)*x^i : i in [0..2*e[1]-e[2]+2]];

f := f0 + f1*y + f2*y^2 + f3*y^3;
f := Evaluate(f, y + x^10 + x); // SOME RANDOM SCRAMBLING

print f;

// CHECK IF RANDOM CURVE HAS THE CORRECT GENUS

FFf := FunctionField(f); gf := Genus(FFf);
print "Genus of input curve is", gf,"which equals prescribed genus g:", g eq gf;
print "----";

// COMPUTE AND LIFT THE DELONE-FADDEEV MODEL

DeloneFaddeevModel := function(f)
  kx := BaseRing(Parent(f));
  FF := FunctionField(f);

  // COMPUTE REDUCED BASIS AND MAKE IT NORMAL
  red_bas := ShortBasis(DivisorGroup(FF) ! 0);
  M, h := Module(red_bas, kx :  IsBasis := true);
  prod := Inverse(h)(red_bas[2]*red_bas[3]);
  n_bas := [red_bas[1], red_bas[2] - prod[3], red_bas[3] - prod[2]];

  // APPLY DELONE-FADDEEV CORRESPONDENCE
  nM, nh := Module(n_bas, kx :  IsBasis := true);
  sq2 := Inverse(nh)(n_bas[2]^2); sq3 := Inverse(nh)(n_bas[3]^2);
  return Parent(f) !  [sq3[2], -sq3[3], sq2[2], -sq2[3]];
end function;

print "Computing its Delone-Faddeev model...";
//tim := Cputime();
f := DeloneFaddeevModel(f);
//print "Took time", Cputime(tim);

Rlift<x> := PolynomialRing(K);
Slift<y> := PolynomialRing(Rlift);
flift := NaiveLiftPol(Coefficient(f,3), K)*y^3 +
         NaiveLiftPol(Coefficient(f,2), K)*y^2 +
         NaiveLiftPol(Coefficient(f,1), K)*y +
         NaiveLiftPol(Coefficient(f,0), K);

flift := y^3 + Coefficient(flift,2)*y^2
     + Coefficient(flift,1)*Coefficient(flift,3)*y
     + Coefficient(flift,0)*Coefficient(flift,3)^2; // MAKE MONIC

// PRINT TO FILE "inputcurve_4.m", CAN BE FED TO TUITMAN'S ALGORITHM
// (IF F IS A PRIME FIELD, FEED TO pcc_p.m, ELSE FEED TO pcc_q.m)

print "----";

if Degree(F) eq 1 then
  Write("inputcurve_3.m", "p := "*IntegerToString(#F)*"; \n" : Overwrite := true);
  print "Writing output to inputcurve_3.m, can be fed as input to pcc_p";
else
  Write("inputcurve_3.m", "q := "*IntegerToString(#F)*"; \n" : Overwrite := true);
  print "Writing output to inputcurve_3.m, can be fed as input to pcc_q";
end if;

Write("inputcurve_3.m", "Q := \n");
Write("inputcurve_3.m", flift);
Write("inputcurve_3.m", ";");
