
// Make newform 578.4.b.f in Magma, downloaded from the LMFDB on 11 April 2026.
// To make the character of type GrpDrchElt, type "MakeCharacter_578_b();"
// To make the character of type GrpDrchElt with Codomain the HeckeField, type "MakeCharacter_578_b_Hecke();"
// To make the coeffs of the qexp of the newform in the Hecke field type "qexpCoeffs();"
// To make the newform (type ModFrm), type "MakeNewformModFrm_578_4_b_f();".
// This may take a long time!  To see verbose output, uncomment the SetVerbose lines below.
// The precision argument determines an initial guess on how many Fourier coefficients to use.
// This guess is increased enough to uniquely determine the newform.
// To make the Hecke irreducible modular symbols subspace (type ModSym)
// containing the newform, type "MakeNewformModSym_578_4_b_f();".
// This may take a long time!  To see verbose output, uncomment the SetVerbose line below.
// The default sign is -1.  You can change this with the optional parameter "sign".
function ConvertToHeckeField(input: pass_field := false, Kf := [])
    if not pass_field then
        poly := [9, 0, 7, 0, 1];
        Kf := NumberField(Polynomial([elt : elt in poly]));
        AssignNames(~Kf, ["nu"]);
    end if;
    Rf_num := [[1, 0, 0, 0], [0, 1, 0, 0], [0, 4, 0, 1], [4, 0, 1, 0]];
    Rf_basisdens := [1, 1, 3, 1];
    Rf_basisnums := ChangeUniverse([[z : z in elt] : elt in Rf_num], Kf);
    Rfbasis := [Rf_basisnums[i]/Rf_basisdens[i] : i in [1..Degree(Kf)]];
    inp_vec := Vector(Rfbasis)*ChangeRing(Transpose(Matrix([[elt : elt in row] : row in input])),Kf);
    return Eltseq(inp_vec);
end function;


// To make the character of type GrpDrchElt, type "MakeCharacter_578_b();"
function MakeCharacter_578_b()
    N := 578;
    order := 2;
    char_gens := [3];
    v := [1];
    // chi(gens[i]) = zeta^v[i]
    assert UnitGenerators(DirichletGroup(N)) eq char_gens;
    F := CyclotomicField(order);
    chi := DirichletCharacterFromValuesOnUnitGenerators(DirichletGroup(N,F),[F|F.1^e:e in v]);
    return MinimalBaseRingCharacter(chi);
end function;

// To make the character of type GrpDrchElt with Codomain the HeckeField, type "MakeCharacter_578_b_Hecke();"
function MakeCharacter_578_b_Hecke( : Kf := false)
    N := 578;
    order := 2;
    char_gens := [3];
    char_values := [[-1, 0, 0, 0]];
    assert UnitGenerators(DirichletGroup(N)) eq char_gens;
    values := ConvertToHeckeField(char_values : pass_field := ISA(Type(Kf), Fld), Kf := Kf); // the value of chi on the gens as elements in the Hecke field
    F := Universe(values);// the Hecke field
    chi := DirichletCharacterFromValuesOnUnitGenerators(DirichletGroup(N,F),values);
    return chi;
end function;


function ExtendMultiplicatively(weight, aps, character)
    prec := NextPrime(NthPrime(#aps)) - 1; // we will able to figure out a_0 ... a_prec
    primes := PrimesUpTo(prec);
    prime_powers := primes;
    assert #primes eq #aps;
    log_prec := Floor(Log(prec)/Log(2)); // prec < 2^(log_prec+1)
    F := Universe(aps);
    FXY<X, Y> := PolynomialRing(F, 2);
    // 1/(1 - a_p T + p^(weight - 1) * char(p) T^2) = 1 + a_p T + a_{p^2} T^2 + ...
    R<T> := PowerSeriesRing(FXY : Precision := log_prec + 1);
    recursion := Coefficients(1/(1 - X*T + Y*T^2));
    coeffs := [F!0: i in [1..prec]];
    coeffs[1] := 1; //a_1
    for i := 1 to #primes do
        p := primes[i];
        coeffs[p] := aps[i];
        b := p^(weight - 1) * F!character(p);
        r := 2;
        p_power := p * p;
        //deals with powers of p
        while p_power le prec do
            Append(~prime_powers, p_power);
            coeffs[p_power] := Evaluate(recursion[r + 1], [aps[i], b]);
            p_power *:= p;
            r +:= 1;
        end while;    
    end for;
    Sort(~prime_powers);
    for pp in prime_powers do
        for k := 1 to Floor(prec/pp) do
            if GCD(k, pp) eq 1 then
                coeffs[pp*k] := coeffs[pp]*coeffs[k];
            end if;
        end for;
    end for;
    return coeffs;
end function;


function qexpCoeffs()
    // To make the coeffs of the qexp of the newform in the Hecke field type "qexpCoeffs();"
    weight := 4;
    raw_aps := [[2, 0, 0, 0], [0, -3, 2, 0], [0, -1, -1, 0], [0, 13, -3, 0], [0, 14, -7, 0], [35, 0, 0, -25], [0, 0, 0, 0], [43, 0, 0, 13], [0, 3, 57, 0], [0, 145, 118, 0], [0, 36, -11, 0], [0, -14, -226, 0], [0, -56, 154, 0], [-161, 0, 0, -28], [195, 0, 0, -6], [495, 0, 0, -57], [222, 0, 0, 276], [0, -54, -121, 0], [-220, 0, 0, 418], [0, -96, -714, 0], [0, 166, 725, 0], [0, -448, -386, 0], [351, 0, 0, -709], [-690, 0, 0, 108], [0, 199, 1415, 0], [951, 0, 0, -214], [-178, 0, 0, -508], [0, -14, 697, 0], [0, 384, -1351, 0], [0, -229, -769, 0], [-863, 0, 0, 68], [0, 306, 630, 0], [-516, 0, 0, 22], [0, 933, 763, 0], [750, 0, 0, 206], [-545, 0, 0, -574], [512, 0, 0, -1285], [0, -364, -1193, 0], [0, 29, -1054, 0], [0, -894, -327, 0], [-3006, 0, 0, 915], [0, 312, 671, 0], [-387, 0, 0, -1333], [0, 1780, 1245, 0], [0, -1723, 1013, 0], [0, 620, -1527, 0], [0, -3, -2149, 0], [334, 0, 0, -2177], [0, 364, 3067, 0], [-440, 0, 0, -1856], [0, -2678, -1340, 0], [1971, 0, 0, 1398], [0, -2103, 2503, 0], [117, 0, 0, -1415], [1530, 0, 0, -1913], [201, 0, 0, 899], [0, -2547, -4248, 0], [-4714, 0, 0, -169], [0, -1936, -1764, 0], [-1218, 0, 0, 1353], [0, -1280, -84, 0], [-1164, 0, 0, -314], [-4558, 0, 0, 2629], [0, 1209, -744, 0], [0, -1390, -6002, 0], [0, -1866, 4725, 0], [-8300, 0, 0, 1399], [0, 1351, 1172, 0], [0, -89, 6406, 0], [853, 0, 0, 4434], [3699, 0, 0, 1272], [-2940, 0, 0, -1869], [0, 4426, 642, 0], [4091, 0, 0, 2320], [0, -4368, -1811, 0], [-7167, 0, 0, -2003], [-2193, 0, 0, 4808], [0, -2506, -9185, 0], [0, 5461, 6787, 0], [-11593, 0, 0, 738], [0, -698, -6713, 0], [8870, 0, 0, -925], [0, 1543, -10421, 0], [-2996, 0, 0, -896], [0, 1534, 13292, 0], [4017, 0, 0, -3676], [0, -2965, 10430, 0], [3142, 0, 0, -4079], [-4194, 0, 0, 7368], [-7702, 0, 0, 3666], [15132, 0, 0, -717], [0, -9114, -7635, 0], [0, -1845, -15334, 0], [7368, 0, 0, -4659], [0, -1849, -17423, 0], [0, -6654, -7449, 0], [12081, 0, 0, 3102], [0, 1088, 14312, 0], [-1123, 0, 0, 1434], [0, -6771, 1768, 0], [0, 5600, 9771, 0], [-3000, 0, 0, 3404], [13296, 0, 0, -7146], [19005, 0, 0, -3042], [0, -3775, 12196, 0], [-2995, 0, 0, 8946], [-16305, 0, 0, -1855], [-2871, 0, 0, 9044], [3711, 0, 0, 8758], [0, 7711, -1722, 0], [0, 50, -3021, 0], [1388, 0, 0, -1134], [0, -5256, 3849, 0], [0, -46, 14173, 0], [-14573, 0, 0, 5867], [0, 11185, 3082, 0], [0, -3882, 13570, 0], [1209, 0, 0, 986], [0, -3042, -5871, 0], [-21087, 0, 0, 9432], [-1148, 0, 0, -4411], [0, 4020, 11684, 0], [0, -11371, -1354, 0], [0, -1153, 3956, 0], [0, -5880, -14596, 0], [8673, 0, 0, -3944], [0, -13907, -16978, 0], [0, -13096, 6377, 0], [-1894, 0, 0, -16000], [-25361, 0, 0, 7705], [-20807, 0, 0, -1118], [0, 6088, -3407, 0], [0, 1542, 14647, 0], [-3029, 0, 0, 7944], [-3471, 0, 0, 2196], [-16213, 0, 0, -1085], [-6789, 0, 0, 1804], [0, -4322, -24112, 0], [16491, 0, 0, -14324], [0, 6506, -1660, 0], [0, -7310, -11134, 0], [0, -230, -10373, 0], [0, -3504, -33535, 0], [0, -5660, -33071, 0], [-10366, 0, 0, 8862], [0, 11826, -12300, 0], [0, -308, 31703, 0], [0, -18570, -1389, 0], [6136, 0, 0, -10090], [21150, 0, 0, -11813], [0, -10873, 17179, 0], [0, -17897, -22646, 0], [-13207, 0, 0, -11387], [0, 18957, 11151, 0], [0, -2203, -14426, 0], [0, -13921, -11293, 0], [-2083, 0, 0, -7607], [0, -17479, -3628, 0], [-2528, 0, 0, -15021], [0, -1141, 39041, 0], [0, -14726, 18343, 0], [43368, 0, 0, -9615], [9190, 0, 0, -14183], [40686, 0, 0, -1625], [-8853, 0, 0, 16711], [0, 20808, 30546, 0], [0, -10419, 32032, 0], [0, 3341, -4016, 0]];
    aps := ConvertToHeckeField(raw_aps);
    chi := MakeCharacter_578_b_Hecke( : Kf := Universe(aps));
    return ExtendMultiplicatively(weight, aps, chi);
end function;


// To make the newform (type ModFrm), type "MakeNewformModFrm_578_4_b_f();".
// This may take a long time!  To see verbose output, uncomment the SetVerbose lines below.
// The precision argument determines an initial guess on how many Fourier coefficients to use.
// This guess is increased enough to uniquely determine the newform.
function MakeNewformModFrm_578_4_b_f(:prec:=4)
    chi := MakeCharacter_578_b();
    f_vec := qexpCoeffs();
    Kf := Universe(f_vec);
    // SetVerbose("ModularForms", true);
    // SetVerbose("ModularSymbols", true);
    S := CuspidalSubspace(ModularForms(chi, 4));
    S := BaseChange(S, Kf);
    maxprec := NextPrime(997) - 1;
    while true do
        trunc_vec := Vector(Kf, [0] cat [f_vec[i]: i in [1..prec]]);
        B := Basis(S, prec + 1);
        S_basismat := Matrix([AbsEltseq(g): g in B]);
        if Rank(S_basismat) eq Min(NumberOfRows(S_basismat), NumberOfColumns(S_basismat)) then
            S_basismat := ChangeRing(S_basismat,Kf);
            f_lincom := Solution(S_basismat,trunc_vec);
            f := &+[f_lincom[i]*Basis(S)[i] : i in [1..#Basis(S)]];
            return f;
        end if;
        error if prec eq maxprec, "Unable to distinguish newform within newspace";
        prec := Min(Ceiling(1.25 * prec), maxprec);
    end while;
end function;


// To make the Hecke irreducible modular symbols subspace (type ModSym)
// containing the newform, type "MakeNewformModSym_578_4_b_f();".
// This may take a long time!  To see verbose output, uncomment the SetVerbose line below.
// The default sign is -1.  You can change this with the optional parameter "sign".
function MakeNewformModSym_578_4_b_f( : sign := -1)
    R<x> := PolynomialRing(Rationals());
    chi := MakeCharacter_578_b();
    // SetVerbose("ModularSymbols", true);
    Snew := NewSubspace(CuspidalSubspace(ModularSymbols(chi,4,sign)));
    Vf := Kernel([<3,R![289, 0, 83, 0, 1]>,<5,R![9, 0, 7, 0, 1]>],Snew);
    return Vf;
end function;