default(nbthreads,1);
default(parisize,"32M"); \\ overflows 30M

/*
test(n)=
{
  p = x^n-x-1; c = p;
  for (i=1,n-3, c = polcompositum(p, c); c = c[#c]);
  c;
}
nfsubfields(test(5));
*/

/* From Hulpke and Klueners's papers */
{v=[
x^6 + 108,
x^8 - 12*x^6 + 23*x^4 - 12*x^2 + 1,
x^8 - 10*x^4 + 1,
x^8 + 4*x^6 + 10*x^4 + 12*x^2 + 7,
x^9 - 18*x^8 + 117*x^7 - 348*x^6 + 396*x^5 + 288*x^4 + 3012*x^3 + 576*x^2 + 576*x - 512,
x^10 + 38*x^9 - 99*x^8 + 1334*x^7 - 4272*x^6 + 9244*x^5 - 8297*x^4 + 1222*x^3 + 1023*x^2 - 74*x + 1,
x^10 - 20*x^9 + 80*x^8 + 200*x^7 - 3770*x^6 + 872*x^5 + 29080*x^4 + 36280*x^3 - 456615*x^2 + 541260*x - 517448,
x^10 - 10*x^8 + 20*x^7 + 235*x^6 + 606*x^5 + 800*x^4 + 600*x^3 + 270*x^2 + 70*x + 16,
x^12 + 6*x^9 + 4*x^8 + 8*x^6 - 4*x^5 - 12*x^4 + 8*x^3 - 8*x + 8,
x^12 + 9*x^11 + 3*x^10 - 73*x^9 - 177*x^8 - 267*x^7 - 315*x^6 - 267*x^5 - 177*x^4 - 73*x^3 + 3*x^2 + 9*x + 1,
x^12 - 34734*x^11 + 401000259*x^10 - 1456627492885*x^9 - 2537142937228035*x^8 + 187620727556 79375516*x^7 - 812368636358864062944*x^6 - 70132863629758257512231931*x^5 + 25834472514 893102332821062085*x^4 + 76623280610352450247247939584745*x^3 - 45080885015422662132 515763499758450*x^2 - 2070499552240812214288316981071818900*x - 5505057590977785454 85364826246753544,
x^15 + 20*x^12 + 125*x^11 + 503*x^10 + 1650*x^9 + 3430*x^8 + 4690*x^7 + 4335*x^6 + 2904*x^5 + 1400*x^4 + 485*x^3 + 100*x^2 + 15*x + 1,
x^32-2,
x^27 - 120*x^25 - 63*x^24 + 5673*x^23 + 5181*x^22 - 138003*x^21 - 167184*x^20 + 1865730*x^19 + 2668613*x^18 - 14070078*x^17 - 21889917*x^16 + 57688596*x^15 + 89482089*x^14 - 132575217*x^13 - 190829625*x^12 + 164200812*x^11 + 215956974*x^10 - 86796519*x^9 - 129504396*x^8 + 1575183*x^7 + 32931993*x^6 + 9928740*x^5 + 49968*x^4 - 372144*x^3 - 50736*x^2 - 1344*x + 64,
x^12 - 3*x^10 + 8*x^8 - 14*x^6 + 21*x^4 - 23*x^2 + 26,
x^24 +8*x^23 -32*x^22 -298*x^21+624*x^20+4592*x^19-8845*x^18-31488*x^17+76813*x^16+ 65924*x^15 - 265616*x^14 + 48348*x^13 + 385639*x^12 - 394984*x^11 - 20946*x^10 + 369102*x^9 - 362877*x^8+183396*x^7+434501*x^6-194418*x^5+450637*x^4+125800*x^3-16401*x^2-45880*x+ 115151
/*
x^60 + 36*x^59 + 579*x^58 + 5379*x^57 + 30720*x^56 + 100695*x^55 + 98167*x^54 - 611235*x^53 - 2499942*x^52 - 1083381*x^51 + 15524106*x^50 + 36302361*x^49 - 22772747*x^48 - 205016994*x^47 - 194408478*x^46 + 417482280*x^45 + 954044226*x^44 + 281620485*x^43 - 366211766*x^42 - 1033459767*x^41 - 8746987110*x^40 - 15534020046*x^39 + 23906439759*x^38 + 104232578583*x^37 + 31342660390*x^36 - 364771340802*x^35 - 547716092637*x^34 + 583582152900*x^33 + 2306558029146*x^32 + 998482693677*x^31 - 3932078004617*x^30 - 5195646620046*x^29 + 2421428069304*x^28 + 10559164336236*x^27 + 3475972372302*x^26 - 22874708335419*x^25 - 33428241525914*x^24 + 21431451023271*x^23 + 90595197659892*x^22 + 50882107959528*x^21 - 67090205528313*x^20 - 117796269461541*x^19 - 74369954660792*x^18 + 25377774560496*x^17 + 126851217660123*x^16 + 104232393296166*x^15 - 29072256729168*x^14 - 83163550972215*x^13 - 24296640395870*x^12 + 14633584964262*x^11 + 8865283658688*x^10 + 5364852154893*x^9 - 1565702171883*x^8 - 7601782249737*x^7 - 2106132289551*x^6 + 3369356619543*x^5 +3717661159674*x^4 +1754791133184*x^3 +573470363592*x^2 +74954438640*x + 3285118944
*/
,x^12-4*x^11-14*x^10+44*x^9+226*x^8+380*x^7-542*x^6-2620*x^5+4249*x^4-6312*x^3+13056*x^2-67392*x+97344 /* #1758 */
];}

{
for (i=1,#v, P = v[i]; S = nfsubfields(P); print(i,":", apply(x->poldegree(x[1]),S));
  for(j=1,#S,s=S[j];if(subst(s[1],x,Mod(s[2],P)),error([P,s]))))
}

{
  for (i=1,#v, P = v[i];
    S1 = nfsubfields(P,,1);
    S2 = nfsubfields(P,2,1);
    foreach(S1,s,if(type(s)!="t_POL",error([P,s])));
    foreach(S2,s,if(type(s)!="t_POL",error([P,s]))));
}

nfsubfields(x^7-x-1,1)
nfsubfields(x^7-x-1,7)
nfsubfields(x^7-x-1,5)
nfsubfields(x^6-3*x^5+5*x^4-5*x^3+5*x^2-3*x+1,1)
nfsubfields(x^6-3*x^5+5*x^4-5*x^3+5*x^2-3*x+1,6)
nfsubfields(x^6-3*x^5+5*x^4-5*x^3+5*x^2-3*x+1,3)

nfsubfields(x^7-x-1,1,1)
nfsubfields(x^7-x-1,7,1)
nfsubfields(x^7-x-1,5,1)
nfsubfields(x^6-3*x^5+5*x^4-5*x^3+5*x^2-3*x+1,1,1)
nfsubfields(x^6-3*x^5+5*x^4-5*x^3+5*x^2-3*x+1,6,1)
nfsubfields(x^6-3*x^5+5*x^4-5*x^3+5*x^2-3*x+1,3,1)

/* maximal CM subfield */
dec(pol) =
{
  my(vp);
  vp = [15889, 11927, 10499, 18367, 10159, 11657, 13159, 14983, 12541, 17789];
  print(vector(#vp,i,factormod(pol,vp[i],1)[,1]~)); setrand(1);
};
testcm(a,P) =
{
  my(pol,v);
  if(!a,return(a));
  pol=a[1];
  v=variable(pol);
  if(pol!=subst(pol,v,-v), return(-1));
  if(polsturm(pol), return(-2));
  if(polsturm(substpol(pol,v^2,v))!=poldegree(pol)/2, return(-3));
  if(subst(pol,v,Mod(a[2],P))!=0, return(-4));
  dec(pol); \\to quickly check if different output defines the same field
  a
};
testmaxcm(P,fl=0) =
{
  my(a);
  print("P=", P, " fl=",fl);
  if(fl,
    a = nfsubfieldscm(nfinit(P)),
  \\else
    a = nfsubfieldscm(P)
  );
  b = nfsubfieldscm(P,1);
  if(b && type(b)!="t_POL",error(P));
  testcm(a,P)
};

setrand(1);
x = 'x;
y = varhigher("y");
testmaxcm(x^2+2*x+7) \\d=2
testmaxcm(x^2+x+7) \\d=2
testmaxcm(x) \\d=0
testmaxcm(x^2-2) \\d=0
testmaxcm(x^3-x-1) \\d=0
testmaxcm(x^2+3,1) \\d=2
testmaxcm(x^4+3) \\d=2
testmaxcm(x^6+3,1) \\d=2 Galois
testmaxcm(y^6-2*y^3+7*y^2+28*y+29) \\d=2
testmaxcm(x^6+2*x^4+x^2+3) \\d=2
testmaxcm(x^4-x+1,1) \\d=0
testmaxcm(x^3-x+1) \\d=0
testmaxcm(x^4-x^3+2*x-1) \\d=0
testmaxcm(x^4+10*x^2+81,1) \\d=4 Galois
testmaxcm(y^4-y^3+3*y^2-2*y+4) \\d=4
testmaxcm(x^4+4*x^2+2,1) \\d=4 Galois
testmaxcm(y^4-2*y^3+5*y^2-4*y+2,1)\\d=4
testmaxcm(x^8-4*x^7+6*x^6-4*x^5+11*x^4-20*x^3+10*x^2+81,1) \\d=4
pol = x^12-4*x^10+6*x^8+6*x^6-19*x^4+10*x^2+81;
fa = nffactor(pol,subst(pol,x,y));
print("with factorisation given, P=",pol);
testcm(nfsubfieldscm([pol,fa]),pol) \\d=4
testmaxcm(x^8+8*x^6-16*x^5+32*x^4-48*x^3+88*x^2-80*x+49,1) \\d=4
testmaxcm(x^12+4*x^9+4*x^8+6*x^6+8*x^5+2*x^4+4*x^3+4*x^2+1,1) \\d=4
testmaxcm(x^16-8*x^14+1108*x^12+3704*x^10+31142*x^8+104712*x^6+151252*x^4+101000*x^2+25921,1) \\d=4
testmaxcm(x^32+64*x^30+6784*x^28+313984*x^26+7747040*x^24+108163584*x^22+981706752*x^20+10666873856*x^18+162128298368*x^16+1744771198976*x^14+10419948331008*x^12+43184187432960*x^10+220661237381120*x^8+598077891510272*x^6+1432066821718016*x^4+4527791925035008*x^2+5903913504477184) \\d=4
pol=x^12+16*x^10-2*x^9-23*x^8-354*x^7+78*x^6-12*x^5+1468*x^4+1120*x^3+1808*x^2+768*x+576; \\d=2
nf = nfinit(pol);
fa = nffactor(nf,subst(pol,x,y));
print("with factorisation given, P=",pol);
testcm(nfsubfieldscm([nf,fa]),pol)
testmaxcm(x^4 + 12*x^3 + 256*x^2 + 3336*x + 12604,1) \\d=4 Galois
testmaxcm(y^2+y+1,1) \\d=2
testmaxcm(x^6-3*x^5+10*x^4-15*x^3+19*x^2-12*x+3,1) \\d=6
testmaxcm(x^6-2*x^5+5*x^4-7*x^3+10*x^2-8*x+8) \\d=6
testmaxcm(x^6-3*x^5+9*x^4-13*x^3+14*x^2-8*x+2) \\d=6
testmaxcm(x^6-x^5+3*x^4+5*x^2-2*x+1) \\d=6 Galois

\\bug #2279
{testmaxcm( a^32 - 325413*a^30 + 65270233310*a^28 + 1500863526264933*a^26 +
21376978048106811144*a^24 + 5551736480851565829015*a^22 +
133169745322757800314805500*a^20 + 63038687459374293832889074215*a^18 +
257768884325926210746438801850200*a^16 +
106388222008795550711265556291586085*a^14 +
77117030842561455372903634633528375614*a^12 +
89909431142768246830844916641035661283*a^10 +
433487290591291262458414346008665504185*a^8 -
43302983359912417821332209228814088*a^6 + 3368895127412412772163639959696*a^4 +
2707609737271108248140094720*a^2 + 255851012946831041433600)};

\\bug (Pascal)
testmaxcm(x^6-3*x^5+4*x^4-3*x^3+4*x^2-3*x+1);

/*
pol=x^64+96*x^62+3664*x^60+138336*x^58+48820072*x^56+3774511776*x^54+70408452368*x^52-3415715897312*x^50-181460174504612*x^48-1463269424430880*x^46+112876320630546640*x^44+3886553626590075360*x^42+32310544425610576856*x^40-817216419624670193120*x^38-18911989493213299044592*x^36+75574827575221188959392*x^34+6783110257645673896066374*x^32+67427794556366653417262880*x^30-409224232405699240608837520*x^28-10185024231373897791953995488*x^26+33608627271402636315786176216*x^24+2140786977982277330764698677728*x^22+21348037724434578430036558445488*x^20+100303837892445470036900049409120*x^18+582288171538387674384751933046364*x^16+7711202633675979091131330471311264*x^14+69710093402021717453738274884587632*x^12+386871329165182266612613221832239264*x^10+1514959930843170006056476784315321960*x^8+3874327706504734663911058389446508896*x^6+7048076339097734475940309155972500528*x^4+6410435303585417655341147657197094624*x^2+3772954882839399478106092174375436161;
nf = nfinit([pol,10^6]); \\40s
nfcertify(nf)==[]
fa = nffactor(nf,subst(pol,x,y)); \\2min
testcm(nfsubfieldscm([nf,fa]),pol) \\10s
\\nfsubfields 2h
\\d=4
*/


y = 'y;
\\from doc
nf = nfinit(x^8 + 20*x^6 + 10*x^4 - 4*x^2 + 9);
nfsubfieldscm(nf)
testcm(nfsubfieldscm(nf),nf.pol)
pol = y^16 - 8*y^14 + 29*y^12 - 60*y^10 + 74*y^8 - 48*y^6 + 8*y^4 + 4*y^2 + 1;
fa = nffactor(pol, subst(pol,y,x));
nfsubfieldscm([pol,fa])
setrand(1); \\ necessary for 32/64-bit compatibility
testcm(nfsubfieldscm([pol,fa]),pol)

/* maximal subfields */
nfsubfieldsmax(x+1)
nfsubfieldsmax(x^2+1)
nfsubfieldsmax(polcyclo(5))
nfsubfieldsmax(polcyclo(7))
nfsubfieldsmax(x^6+x^4+2*x^2+1)
nfsubfieldsmax(x^12+x^10-x^9+x^8+3*x^7+2*x^6+2*x^5-x^4+x^2+x+1)
nfsubfieldsmax(x^18+x^16-x^15+x^14-2*x^13+2*x^12+4*x^11+4*x^10+2*x^9-2*x^7-2*x^6-2*x^5-x^4+x^2+x+1)
nfsubfieldsmax(x^7-x-1)
nfsubfieldsmax(x^7-x^6-12*x^5+7*x^4+28*x^3-14*x^2-9*x-1)
nfsubfieldsmax(x^8-3*x^7+6*x^6-9*x^5+9*x^4-7*x^3+4*x^2-x+1)
nfsubfieldsmax(x^12-5*x^11+13*x^10-25*x^9+39*x^8-50*x^7+53*x^6-48*x^5+37*x^4-23*x^3+12*x^2-4*x+1)

nfsubfieldsmax(x+1,1)
nfsubfieldsmax(x^2+1,1)
nfsubfieldsmax(polcyclo(5),1)
nfsubfieldsmax(polcyclo(7),1)
nfsubfieldsmax(x^6+x^4+2*x^2+1,1)
nfsubfieldsmax(x^12+x^10-x^9+x^8+3*x^7+2*x^6+2*x^5-x^4+x^2+x+1,1)
nfsubfieldsmax(x^18+x^16-x^15+x^14-2*x^13+2*x^12+4*x^11+4*x^10+2*x^9-2*x^7-2*x^6-2*x^5-x^4+x^2+x+1,1)
nfsubfieldsmax(x^7-x-1,1)
nfsubfieldsmax(x^7-x^6-12*x^5+7*x^4+28*x^3-14*x^2-9*x-1,1)
nfsubfieldsmax(x^8-3*x^7+6*x^6-9*x^5+9*x^4-7*x^3+4*x^2-x+1,1)
nfsubfieldsmax(x^12-5*x^11+13*x^10-25*x^9+39*x^8-50*x^7+53*x^6-48*x^5+37*x^4-23*x^3+12*x^2-4*x+1,1)

/* nfsubfields using factorisation */
y = varhigher("y");
nfsubfields_fa(pol,d=0) = nfsubfields([pol,nffactor(pol,subst(pol,x,y))],d);
nfsubfields_fa(x^2+1)
nfsubfields_fa(polcyclo(5))
nfsubfields_fa(polcyclo(7))
{for(i=1,#v,
  L = nfsubfields_fa(v[i]);
  print(apply(a->poldegree(a[1]),L))
)};
nfsubfields_fa(x^7-x-1,1)
nfsubfields_fa(x^7-x-1,7)
nfsubfields_fa(x^7-x-1,5)
nfsubfields_fa(x^7-x-1)
nfsubfields_fa(x^6-3*x^5+5*x^4-5*x^3+5*x^2-3*x+1,1)
nfsubfields_fa(x^6-3*x^5+5*x^4-5*x^3+5*x^2-3*x+1,6)
nfsubfields_fa(x^6-3*x^5+5*x^4-5*x^3+5*x^2-3*x+1,3)
nfsubfields_fa(x^8-3*x^7+6*x^6-9*x^5+9*x^4-7*x^3+4*x^2-x+1)
nfsubfields_fa(x^12-5*x^11+13*x^10-25*x^9+39*x^8-50*x^7+53*x^6-48*x^5+37*x^4-23*x^3+12*x^2-4*x+1)
{#nfsubfields_fa(x^32-152*x^30+9592*x^28-329344*x^26+6791636*x^24-87823728*x^22
  +723817584*x^20-3802250784*x^18+12604302140*x^16-26054878368*x^14
  +33346127520*x^12-26066364480*x^10+12062323568*x^8-3111766784*x^6
  +403544704*x^4-21688960*x^2+364816,16)} /* 1525 */

\\ slow with bad prime choice
#nfsubfields(x^48-16*x^47+60*x^46+376*x^45-3456*x^44+3040*x^43+53876*x^42-174976*x^41-272765*x^40+2261976*x^39-1548616*x^38-13833480*x^37+29163082*x^36+34773712*x^35-174606468*x^34+60009120*x^33+527504938*x^32-686236912*x^31-709808060*x^30+2088782160*x^29-316365156*x^28-3142585264*x^27+2700543492*x^26+1831044936*x^25-4013808579*x^24+1417663200*x^23+1532709728*x^22-1935905360*x^21+1440999246*x^20-1499656216*x^19+1178342448*x^18+374800016*x^17-2223766223*x^16+2988494200*x^15-2313016936*x^14+860459880*x^13+422835584*x^12-1235711560*x^11+1535454560*x^10-1283650224*x^9+771182694*x^8-207859016*x^7-63471948*x^6+107318416*x^5-56103454*x^4+684280*x^3+4810240*x^2-298000*x-10775,12)

#nfsubfields(x^34+63*x^33+3*x^32+98*x^31+24*x^30+81*x^29+82*x^28+85*x^27+79*x^26+60*x^25+82*x^24+15*x^23+76*x^22+39*x^21+39*x^20+16*x^19+66*x^18+66*x^17+81*x^16+35*x^15+66*x^14+87*x^13+90*x^12+71*x^11+64*x^10+24*x^9+58*x^8+16*x^7+79*x^6+85*x^5+51*x^4+41*x^3+63*x^2+97*x+63)

#nfsubfields(x^24+79*x^23+93*x^22+18*x^21+37*x^20+22*x^19+30*x^18+43*x^17+56*x^16+77*x^15+19*x^14+93*x^13+91*x^12+87*x^11+23*x^10+46*x^9+54*x^8+18*x^7+56*x^6+61*x^5+47*x^2+17*x+47)

nfsubfields(y^4-2,2,1)
nfsubfields(y^4-2,,1)
nfsubfields(y^4-2,3,1)

\\Bill's variable priority bug
P=x^6+108;
t = varhigher("t");  F = nffactor(P,subst(P,x,t)); nfsubfields([P,F])
F = nffactor(subst(P,x,a),P); nfsubfields([subst(P,x,a),F])
F=nffactor(subst(P,x,a),P);  nfsubfields([P,F])

\\bad inputs
nfsubfieldscm(1)
nfsubfieldscm(x^2+1/2)
nfsubfieldscm([1,matrix(0,2)])
nfsubfieldscm([[],matrix(0,2)])
nfsubfieldscm([]);
nfsubfieldscm([x^2+1,1])
nfsubfieldscm([nfinit(x^2+1),1])
nfsubfieldscm(4*x^2+1);
nfsubfieldscm(x^0);
nfsubfields([x^2-5,[z,1;z,1]]);
nfsubfields([x^2-5,[z-x,1;z+x,1]]);

