default(parisize,"12M"); \\ 10M overflows on 64 bit

qamt(a,b) =
{
  my(m_i,m_j,m_k);
  m_i = [0,a,0,0;
         1,0,0,0;
         0,0,0,a;
         0,0,1,0];
  m_j = [0, 0,b, 0;
         0, 0,0,-b;
         1, 0,0, 0;
         0,-1,0, 0];
  m_k = [0, 0,0,-a*b;
         0, 0,b,   0;
         0,-a,0,   0;
         1, 0,0,   0];
  [matid(4), m_i, m_j, m_k]
};

\\Tests related to hasse invariants in algebras

do(name, test) = {
 setrand(1);
 print(name,": ", iferr(test(), E, E));
}
gusuite(name, tests) = print("Suite: ", name); tests();

searchin(hf,pr,h) =
{
  for(i=1,#hf[1],
    if(hf[1][i]==pr, return(hf[2][i]==h)));
  return(h==0);
}

samehasse(hf1,hi1,hf2,hi2) =
{
  if (hi1 != hi2, return(0));
  for (i=1, #hf1[1],
    if (!searchin(hf2,hf1[1][i],hf1[2][i]), return(0)));
  for (i=1,#hf2[1],
    if (!searchin(hf1,hf2[1][i],hf2[2][i]), return(0)));
  return(1);
}

hassetriv(hf,hi) = samehasse(hf,hi,[[],Vecsmall([])],Vecsmall(vector(#hi,i,0)));
altriv(al) = hassetriv(alghassef(al),alghassei(al));
alsame(al,hf,hi) = samehasse(alghassef(al),alghassei(al),hf,hi);

alcheckhasse(al) =
{
  my(n,h);
  n = algdegree(al);
  h = Mod(0,n);
  for(i=1, #alghassef(al)[1],
      h += alghassef(al)[2][i]);
  for(i=1, #alghassei(al),
      h += (n/2)*alghassei(al)[i]);
  return(h == Mod(0,n));
}

al_cyclotomic(p,b,fl=3) =
{
  my(Q,F,pc,r);
  Q = nfinit(y);
  pc = polcyclo(p,x);
  F = rnfinit(Q,pc);
  r = lift(znprimroot(p));
  return(alginit(F, [Mod(Mod(1,y)*x^r,pc), b], 'x, fl));
}

hasse0() = gusuite("hasse sum to 0", ()->{
  do("cyclo construction", ()->al_cyclotomic(3,-175624635));
  do("cyclo ramified at infinity", ()->alcheckhasse(al_cyclotomic(3,-175624635)));
  do("cyclo unramified at infinity", ()->alcheckhasse(al_cyclotomic(3,2763764)));
  do("cyclo 5", ()->alcheckhasse(al_cyclotomic(5,7861623)));
  do("cyclo 5 bis", ()->alcheckhasse(al_cyclotomic(5,6569846846546548798*25)));
  do("cyclo 7 bis no mo", ()->alcheckhasse(al_cyclotomic(7,168656465154165487*7^3,2)));
  do("cyclo 11 no mo", ()->alcheckhasse(al_cyclotomic(11,87165765,2)));
  do("quat -1,-1 over Q", ()->alcheckhasse(alginit(nfinit(y),[-1,-1])));
  do("quat -1,-1 over Q(sqrt(2))", ()->alcheckhasse(alginit(nfinit(y^2-2),[-1,-1],x)));
  do("quat -1,-1 over Q(sqrt(60))", ()->alcheckhasse(alginit(nfinit(y^2-60),[-1,-1],x)));
});

alfromhasse() = gusuite("algebra from Hasse invariants", ()->{
  my(nf, pr7, pr13, finvm, finv, finv1, finv2, iinvm, iinv, iinv1, iinv2, d1,\
    d2, d, dm, mai, al);
  nf = nfinit(y^3+y^2-2*y-1);
  pr7 = idealprimedec(nf,7);
  pr13 = idealprimedec(nf,13);
  J = varhigher("J");

  al = alginit(nf,3,J);
  do("matrix algebra invariants", ()->altriv(al));

  d1 = 3;
  finv1 = [pr13,Vecsmall([1,1,1])];
  iinv1 = Vecsmall([0,0,0]);
  al = alginit(nf,[d1,finv1,iinv1],J);
  do("algebra 1 invariants", ()->alsame(al,finv1,iinv1));

  d2 = 2;
  finv2 = [pr7,Vecsmall([1])];
  iinv2 = Vecsmall([1,0,0]);
  al = alginit(nf,[d2,finv2,iinv2],J);
  do("algebra 2 invariants", ()->alsame(al,finv2,iinv2));

  nf = nfinit(y);
  p13 = idealprimedec(nf,13)[1];
  finv1 = [[p13],[Mod(1,2)]];
  iinv1 = Vecsmall([1]);
  do("test", ()->alginit(nf,[2,finv1,iinv1],J));

  d = 6;
  p3 = idealprimedec(nf,3)[1];
  p5 = idealprimedec(nf,5)[1];
  p7 = idealprimedec(nf,7)[1];
  p11 = idealprimedec(nf,11)[1];
  finv = [[p3,p5,p7,p11], Vecsmall([3,2,2,2])];
  iinv = Vecsmall([3]);
  al = alginit(nf,[d,finv,iinv],J,0);
  do("degree 6 algebra over Q", ()->alsame(al,finv,iinv));

  nf = nfinit(y^2-5);
  finv1 = [[],[]];
  iinv1 = Vecsmall([1,1]);
  do("trivial finite conditions", ()->my(al=alginit(nf,[2,finv1,iinv1]));
    [alghassei(al),alghassef(al)]);

});

all() = gusuite("all", ()->{
  hasse0();
  alfromhasse();
});

all();

\\better accessors for hasse invariants
print("better accessors");
setrand(1);
x='x;
nf = nfinit(y^3-y+1);
rnf = rnfinit(nf, polcyclo(5,x));
al = alginit(rnf, [x^2,-2],, 0);
alghasse(al,1)
alghasse(al,2)
alghasse(al,idealprimedec(nf,2)[1])
alghasse(al,idealprimedec(nf,3)[1])
alghasse(al,idealprimedec(nf,5)[1])
alghasse(al,idealprimedec(nf,5)[2])
algindex(al,1)
algindex(al,2)
algindex(al,idealprimedec(nf,2)[1])
algindex(al,idealprimedec(nf,3)[1])
algindex(al,idealprimedec(nf,5)[1])
algindex(al,idealprimedec(nf,5)[2])
algindex(al)
algisdivision(al,1)
algisdivision(al,2)
algisdivision(al,idealprimedec(nf,2)[1])
algisdivision(al,idealprimedec(nf,3)[1])
algisdivision(al,idealprimedec(nf,5)[1])
algisdivision(al,idealprimedec(nf,5)[2])
algisdivision(al)
algissplit(al,1)
algissplit(al,2)
algissplit(al,idealprimedec(nf,2)[1])
algissplit(al,idealprimedec(nf,3)[1])
algissplit(al,idealprimedec(nf,5)[1])
algissplit(al,idealprimedec(nf,5)[2])
algissplit(al)
algisramified(al,1)
algisramified(al,2)
algisramified(al,idealprimedec(nf,2)[1])
algisramified(al,idealprimedec(nf,3)[1])
algisramified(al,idealprimedec(nf,5)[1])
algisramified(al,idealprimedec(nf,5)[2])
algisramified(al)
algramifiedplaces(al)

print(" ");
al = 0;
al = alginit(rnf, [x^2,-1],, 0);
alghasse(al,1)
alghasse(al,2)
alghasse(al,idealprimedec(nf,2)[1])
alghasse(al,idealprimedec(nf,5)[1])
alghasse(al,idealprimedec(nf,5)[2])
algindex(al,1)
algindex(al,2)
algindex(al,idealprimedec(nf,2)[1])
algindex(al,idealprimedec(nf,5)[1])
algindex(al,idealprimedec(nf,5)[2])
algindex(al)
algisdivision(al,1)
algisdivision(al,2)
algisdivision(al,idealprimedec(nf,2)[1])
algisdivision(al,idealprimedec(nf,5)[1])
algisdivision(al,idealprimedec(nf,5)[2])
algisdivision(al)
algissplit(al,1)
algissplit(al,2)
algissplit(al,idealprimedec(nf,2)[1])
algissplit(al,idealprimedec(nf,5)[1])
algissplit(al,idealprimedec(nf,5)[2])
algissplit(al)
algisramified(al,1)
algisramified(al,2)
algisramified(al,idealprimedec(nf,2)[1])
algisramified(al,idealprimedec(nf,5)[1])
algisramified(al,idealprimedec(nf,5)[2])
algisramified(al)
algramifiedplaces(al)

print(" ");
al = 0;
al = alginit(rnf, [x^2, 1],, 0);
alghasse(al,1)
alghasse(al,2)
alghasse(al,idealprimedec(nf,2)[1])
alghasse(al,idealprimedec(nf,5)[2])
algindex(al,1)
algindex(al,2)
algindex(al,idealprimedec(nf,2)[1])
algindex(al,idealprimedec(nf,5)[2])
algindex(al)
algisdivision(al,1)
algisdivision(al,2)
algisdivision(al,idealprimedec(nf,2)[1])
algisdivision(al,idealprimedec(nf,5)[2])
algisdivision(al)
algissplit(al,1)
algissplit(al,2)
algissplit(al,idealprimedec(nf,2)[1])
algissplit(al,idealprimedec(nf,5)[2])
algissplit(al)
algisramified(al,1)
algisramified(al,2)
algisramified(al,idealprimedec(nf,2)[1])
algisramified(al,idealprimedec(nf,5)[2])
algisramified(al)
algramifiedplaces(al)

print("Hasse inv 0 bug");
setrand(1); a='a;
K=nfinit(a);PR=idealprimedec(K,2);A=alginit(K,[3,[PR,[0]],[0]],,0);
algdegree(A)
algdim(A)
algindex(A)
algisdivision(A)
algadd(A,[1,0,0,0,0,0,0,0,0]~,[1,2,3]~)
algsub(A,[1,0,0,0,0,0,0,0,0]~,[1,2,3]~)
algmul(A,[0,0,0,0,0,0,0,0,0]~,[1,2,3]~)

print("\ntests with splitting field that does not descend");
setrand(1);
nf = nfinit(y^2-5);
al = alginit(nf,[y,-1]);
algramifiedplaces(al)
al = alginit(nf,[-3+y,-1]);
algramifiedplaces(al)
al = alginit(nf,[-3+y,y]);
algramifiedplaces(al)
nf = nfinit(y^4 - 10*y^2 + 1);
p3 = idealprimedec(nf,3)[1];
p5 = idealprimedec(nf,5)[1];
al = alginit(nf, [2, [[p3,p5],[1/2,1/2]], [1/2,0,0,1/2]]);
algramifiedplaces(al)
al = alginit(nf, [2, [[p3],[1/2]], [0,1/2,0,0]]);
algramifiedplaces(al)
nf = nfinit(y^8 - 40*y^6 + 352*y^4 - 960*y^2 + 576);
p3 = idealprimedec(nf,3)[1];
al = alginit(nf, [2,[[p3],[1/2]], [1/2,0,0,1/2,1/2,0,0,0]]);
algramifiedplaces(al)

print("quaternion from ramification shortcut");
setrand(1);
nf = nfinit(y^2-2);
P1 = idealprimedec(nf,17)[1];
P2 = idealprimedec(nf,2)[1];
alg = alginit(nf,[[P1,P2],[0,0]]);
a = poldisc(algsplittingfield(alg).pol);
b = algb(alg);
alg = alginit(nf,[a,b]);
alghasse(alg,P1) == 1/2
alghasse(alg,P2) == 1/2
alghasse(alg,1) == 0
alghasse(alg,2) == 0
algdisc(alg) == nf.disc^4 * (2*17)^2 * 2^8
alg = alginit(nf,[[],[1,1]]);
a = poldisc(algsplittingfield(alg).pol);
b = algb(alg);
alg = alginit(nf,[a,b]);
alghasse(alg,1) == 1/2
alghasse(alg,2) == 1/2
algdisc(alg) == nf.disc^4 * 2^8


print("degree bug");
nf = nfinit(y); p2 = idealprimedec(nf,2)[1]; p3 = idealprimedec(nf,3)[1];
al = alginit(nf, [4,[[p2,p3],[1/2,1/2]],[0]]); algdegree(al)
{for(i=1,10,
  al = alginit(nf, [2,[[p2,p3],[0,0]],[0]]);
  print1(algdegree(al)," ");
)};
al = alginit(nf, [4,[[p2,p3],[0,0]],[0]]); algdegree(al)
nf = nfinit(z^2+1);
p31 = idealprimedec(nf,31)[1];
p2 = idealprimedec(nf,2)[1];
{for(i=1,10,
   al = alginit(nf, [2, [[p31,p2], [0, 0]], []]); print1(algdegree(al)," ");
)};

print("infinite loop in GW"); \\Bug #2343
F=nfinit(y^4 - y^3 - 3*y^2 + y + 1);
P=nfgrunwaldwang(F, [], Vecsmall([]), Vecsmall([-1, 0, -1, 0]));
P=nfgrunwaldwang(F, [], Vecsmall([]), Vecsmall([0, 0, -1, 0]));

print("inefficiency in backtrackfacto");
F=nfinit(y^5-y^4-3*y^2+1);
setrand(5)
alginit(F, [2, [[], []], [1,1,0]],,0);

print("bug: alg_complete at ramified primes");
\\James Rickards's example
setrand(1);
F=nfinit(y^3 - y^2 - 10*y + 8);
setrand(1);
pr1 = idealprimedec(F, 2)[1];
pr2 = idealprimedec(F, 13)[1];
A=alginit(F, [2, [[pr1, pr2], [1, 1]], [0, 1, 1]]);
\\more examples
nf = nfinit(y^2-17);
[pr1,pr2] = idealprimedec(nf,2);
al = alginit(nf,[2,[[pr1],[1/2]],[0,1]],,0);
nf = nfinit(y^4 + 7*y^2 + 49);
pr1 = idealprimedec(nf,3)[1];
pr2 = idealprimedec(nf,5)[1];
al = alginit(nf,[3,[[pr1,pr2],[1/3,2/3]],[]],,0);

print("bug alghasse"); \\hasse invariants not sorted
nf = nfinit(y^2-2);
pr = idealprimedec(nf,17)[1];
al = alginit(nf, [[pr],[1,0]]);
alghasse(al,pr) == 1/2
Lpr = alghassef(al)[1];
Lpr == idealfactor(nf,idealfactorback(nf,Lpr))[,1]~

print("doc alginit: quatalg from ramification");
nf = nfinit(y^2-2);
PR = idealprimedec(nf,2); \\ramified at the prime above 2
hi = [1,0]; \\ramified at one place at infinity
A = alginit(nf, [PR,hi]);
#algramifiedplaces(A)

print("algisisom");
print("degree 1");
nf = nfinit(y^2-3);
pr = idealprimedec(nf,3)[1];
al = alginit(rnfinit(nf,x),[x,1]);
al2 = alginit(rnfinit(nf,x-1),[x,2]);
algisisom(al,al2)
algisisom(al,al2,pr)
algisisom(al,al2,1)
al3 = alginit(nf,[matid(1)]);
al4 = alginit(nf,[matid(1)]);
algisisom(al3,al4)
algisisom(al,al3)
print("degree 2");
nf = nfinit(y^2-2);
pr = idealprimedec(nf,17)[1];
al = alginit(nf, [1+y, 7*y]);
{al2 = alginit(nf, [[pr | pr <- algramifiedplaces(al), type(pr)!="t_INT"],
  alghassei(al)]);}
algisisom(al, al2)
{al3 = alginit(nf, [[pr | pr <- algramifiedplaces(al), type(pr)!="t_INT"],
  [0,1]]);}
pr2 = algramifiedplaces(al)[2];
!algisisom(al, al3) \\not isom at infinite places
!algisisom(al,al3,1)
algisisom(al,al3,pr)
algisisom(al,al3,pr2)
al4 = alginit(nf, [[pr],alghassei(al)]);
!algisisom(al, al4) \\not isom at finite places
algisisom(al, al4, 1)
algisisom(al, al4, 2)
!algisisom(al, al4, pr)
nf = nfinit(y^4 + 2003*y^2 + 2119936);
rnf = rnfinit(nf, x^2 + (-1/8736*y^3 - 547/8736*y - 11/2));
al = alginit(rnf, [-x,1/4368*y^3 + 547/4368*y + 10]);
al2 = alginit(nf,2);
algisisom(al,al2)
print("degree 3");
Q = nfinit(y);
al = alginit(rnfinit(Q,x^3 - x^2 - 86*x - 48), [1/6*x^2 - 5/6*x - 9, 2*11]);
pr = algramifiedplaces(al)[1];
al2 = alginit(Q, [3, [algramifiedplaces(al),[1/3,-1/3]], [0]]);
algisisom(al,al2)
algisisom(al,al2,pr)
al3 = alginit(Q, [3, [algramifiedplaces(al),[-1/3,1/3]], [0]]);
!algisisom(al,al3,pr)
!algisisom(al,al3)
print("degree 4");
nf = nfinit(y^2-7);
b = Mod(1+3*y, nf.pol);
al = alginit(rnfinit(nf,polcyclo(5)), [x^2, b^2]);
al2 = alginit(nf, [algramifiedplaces(al), [0,0]]);
!algisisom(al,al2) \\similar but not isomorphic
print("doc algisisom");
nf = nfinit(y^2-2);
al = alginit(nf, [1+y, -7]);
al2 = alginit(nf, [-1, 2*y-1]);
al3 = alginit(nf, [1-y, -7]);
algisisom(al,al2)
!algisisom(al,al3) \\isomorphic over Q but not as F-algebras
pr = idealprimedec(nf,2)[1];
algisisom(al,al3,pr)
!algisisom(al,al3,1)

print("bad inputs algisisom");
al = alginit(nfinit(y),[-1,-1]);
algisisom([],al);
algisisom(al,[]);
almt = algtableinit([matid(1)]);
algisisom(almt,al);
algisisom(al,almt);
H = alginit(1.,1/2);
algisisom(H,al);
algisisom(al,H);
al2 = alginit(nfinit(y-1),[-1,-1]);
algisisom(al,al2);
p = nextprime(10^60);
q = nextprime(10^61);
al = alginit(nfinit(y^2-2), [-1,-p*q],,0);
al2 = alginit(nfinit(y^2-2), [-2,-p*q],,0);
algisisom(al,al2);
algisisom(al,al2,[]);
nf = nfinit(y^2-5);
al = alginit(nf, qamt(y+7,y-2));
al2 = alginit(nf, qamt(y-6,y+4));
algisisom(al,al2);
al3 = alginit(nf, [y+3,y-5]);
algisisom(al,al3);
algisisom(al,al3,192);

