Skip to content

Commit

Permalink
Merge pull request #464 from abhijit-mudigonda/cubic-tests
Browse files Browse the repository at this point in the history
basis tests for HMFs over cubic fields
  • Loading branch information
abhijit-mudigonda authored Jul 29, 2024
2 parents 71e6fd1 + 017644f commit a4ef060
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 35 deletions.
58 changes: 23 additions & 35 deletions ModFrmHilD/Restriction.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
intrinsic RestrictionToDiagonal(f::ModFrmHilDElt,M::ModFrmHilDGRng,bb::RngQuadIdl) -> ModFrmElt
intrinsic RestrictionToDiagonal(f::ModFrmHilDElt,M::ModFrmHilDGRng,bb::RngOrdIdl) -> ModFrmElt
{Given an HMF f of parallel weight k, returns the classical modular curve of weight nk and level obtained from restricting
the component bb of the HMF to the diagonal.}
require #SequenceToSet(Weight(f)) eq 1: "Only defined for parallel weight.";
Expand Down Expand Up @@ -36,41 +36,29 @@ intrinsic RestrictionToDiagonal(f::ModFrmHilDElt,M::ModFrmHilDGRng,bb::RngQuadId
return modForms!(denom*(restriction +O(q^(prec))));
end intrinsic;

/*
// Totally Positive Elements in an Ideal
From a basis {a,b} for the ideal bb where
Tr(a) = n and Tr(b) = 0.
Elements in ideal will look like xa + yb where x,y in ZZ
and have embedding xa_1 + yb_1 and xa_2 + yb_2.
All totally positive elements of given trace t will satisfy
1) t = Tr(xa+yb) <=> t = xn
2) xa+yb totally positive <=> y > -x*a_1/b_1 and y > -x*a_2/b_2
Eq 1) determines the value for x,
and Eq 2) allows us to loop over values of y
*/
intrinsic PositiveElementsOfTrace(aa::RngOrdFracIdl, t::RngIntElt) -> SeqEnum[RngOrdFracIdl]
{Given aa a fractional ideal and t a nonnegative integer,
returns the totally positive elements of aa with trace t.}
{
Given aa a fractional ideal and t a nonnegative integer,
returns the totally positive elements of aa with trace t.
}
basis := TraceBasis(aa);
places := InfinitePlaces(NumberField(Parent(basis[1])));
smallestTrace := Integers()!Trace(basis[1]);
T := [];
if t mod smallestTrace eq 0 then
x := t div smallestTrace;
a_1 := Evaluate(basis[1],places[1]);
a_2 := Evaluate(basis[1],places[2]);
b_1 := Evaluate(basis[2],places[1]);
b_2 := Evaluate(basis[2],places[2]);
assert b_1 lt 0 and b_2 gt 0; // if this assumption changes, the inequalities get swapped
// at place 2, x*a2 + y*b2 >= 0 => y >= -x*a2/b2
lower_bnd := Ceiling(-x*a_2/b_2);
// at place 1, x*a1 + y*b1 >= 0 => y <= -x*a1/b1
upper_bnd := Floor(-x*a_1/b_1);
for y in [lower_bnd .. upper_bnd] do
Append(~T, x*basis[1]+y*basis[2]);
end for;
end if;
return T;
end intrinsic;
smallest_trace := Integers()!Trace(basis[1]);
if (t mod smallest_trace) eq 0 then
F := NumberField(Parent(basis[1]));
n := Degree(F);

B := Matrix([[Evaluate(b, v) : v in InfinitePlaces(F)] : b in basis]);
B := t * B^-1;

// drop the first coordinate, it'll always be t / smallest_trace
vertices := [Rationalize(Vector([v[i] : i in [2 .. n]])) : v in Rows(B)];
assert #vertices[1] eq n-1 and #vertices eq n;
P := Polytope(vertices);
pts := InteriorPoints(P);
// put t / smallest_trace back in each vector
x := t div smallest_trace;
return [x * basis[1] + &+[Eltseq(pt)[i] * basis[i+1] : i in [1 .. n-1]] : pt in pts];
else
return [];
end if;
end intrinsic;
26 changes: 26 additions & 0 deletions Tests/cubic_cuspforms.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Checks that the restrictions of parallel weight cusp forms over
// cubic fields are classical cusp forms.
//
// TODO abhijitm - this test will be made more robust shortly, once we can compute
// parallel weight k forms for k > 2.

R<x> := PolynomialRing(Rationals());
F := NumberField(x^3-x^2-2*x+1);
ZF := Integers(F);

M := GradedRingOfHMFs(F, 150);
N := 3*ZF;
M222 := HMFSpace(M, N, [2,2,2]);
S222 := CuspFormBasis(M222);
assert #S222 eq 1;
f := S222[1];

// The restriction of a parallel weight 2 form f to the diagonal g(z) := f(z,z,z)
// should be a weight 6 classical modular form of level 3:
g := RestrictionToDiagonal(f, M, 1*ZF);

// the space of level 3 weight 6 forms has dimension 1
// https://www.lmfdb.org/ModularForm/GL2/Q/holomorphic/3/6/a/a/
h := Basis(CuspForms(Gamma0(3), 6))[1];

assert Degree(F) * h eq g;
23 changes: 23 additions & 0 deletions Tests/cubic_mult.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// tests multiplication for HMFs over cubic fields
//
// checks that the square of an Eisenstein series of parallel weight 1
// lies in the computed space of [2,2,2] forms.
//
// TODO abhijitm - this test will be made more robust once we can compute
// cusp spaces for weights beyond parallel weight 2.

R<x> := PolynomialRing(Rationals());
F := NumberField(x^3-x^2-2*x+1);
ZF := Integers(F);

M := GradedRingOfHMFs(F, 150);
N := 3*ZF;
M222 := HMFSpace(M, N, [2,2,2]);
B222 := Basis(M222);
H := HeckeCharacterGroup(N, [1,2,3]);
chi := H.1;
assert Order(chi) eq 2;
M111 := HMFSpace(M, N, [1,1,1], chi);
E111 := EisensteinBasis(M111);
E111_squared := [f^2 : f in E111];
assert #Intersection(E111_squared, B222) eq #E111_squared;
59 changes: 59 additions & 0 deletions Tests/pos_elts_of_trace.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// we use the old PositiveElementsOfTrace function to test
// the new one

/*
Totally Positive Elements in an Ideal
From a basis {a,b} for the ideal bb where
Tr(a) = n and Tr(b) = 0.
Elements in ideal will look like xa + yb where x,y in ZZ
and have embedding xa_1 + yb_1 and xa_2 + yb_2.
All totally positive elements of given trace t will satisfy
1) t = Tr(xa+yb) <=> t = xn
2) xa+yb totally positive <=> y > -x*a_1/b_1 and y > -x*a_2/b_2
Eq 1) determines the value for x,
and Eq 2) allows us to loop over values of y
*/

function pos_elts_of_trace_quadratic(aa, t)
// aa - RngOrdFracIdl
// t - RngIntElt
// returns - SeqEnum[RngOrdFracIdl]
basis := TraceBasis(aa);
F := NumberField(Parent(basis[1]));
assert Degree(F) eq 2; // only works for quadratic fields
places := InfinitePlaces(F);
smallestTrace := Integers()!Trace(basis[1]);
T := [];
if t mod smallestTrace eq 0 then
x := t div smallestTrace;
a_1 := Evaluate(basis[1],places[1]);
a_2 := Evaluate(basis[1],places[2]);
b_1 := Evaluate(basis[2],places[1]);
b_2 := Evaluate(basis[2],places[2]);
assert b_1 lt 0 and b_2 gt 0; // if this assumption changes, the inequalities get swapped
// at place 2, x*a2 + y*b2 >= 0 => y >= -x*a2/b2
lower_bnd := Ceiling(-x*a_2/b_2);
// at place 1, x*a1 + y*b1 >= 0 => y <= -x*a1/b1
upper_bnd := Floor(-x*a_1/b_1);
for y in [lower_bnd .. upper_bnd] do
Append(~T, x*basis[1]+y*basis[2]);
end for;
end if;
return T;
end function;

max_N_norm := 20;
max_x := 5;
F := QuadraticField(5);
for N in [I : I in IdealsUpTo(max_N_norm, F) | not IsZero(I)] do
basis := TraceBasis(N);
smallest_trace := Integers()!Trace(basis[1]);
for x in [1 .. max_x] do
assert SequenceToSet(PositiveElementsOfTrace(N, x * smallest_trace)) \
eq SequenceToSet(pos_elts_of_trace_quadratic(N, x * smallest_trace));
if smallest_trace ne 1 then
assert #PositiveElementsOfTrace(N, x * smallest_trace - 1) eq 0;
end if;
end for;
end for;

0 comments on commit a4ef060

Please sign in to comment.