/*************************************************************************/
/** **/
/** GALOIS CONJUGATES **/
/** **/
/*************************************************************************/
/* $Id: galconj.c,v 1.8 1999/09/23 17:50:56 karim Exp $ */
#include "pari.h"
GEN
galoisconj(GEN nf)
{
GEN x, y, z;
long i, lz, lx, v, av = avma;
nf = checknf(nf);
x = (GEN) nf[1];
v = varn(x);
lx = lgef(x) - 2;
if (v == 0)
nf = gsubst(nf, 0, polx[MAXVARN]);
else
{
x = dummycopy(x);
setvarn(x, 0);
}
z = nfroots(nf, x);
lz = lg(z);
y = cgetg(lz, t_COL);
for (i = 1; i < lz; i++)
{
GEN p1 = lift((GEN) z[i]);
setvarn(p1, v);
y[i] = (long) p1;
}
return gerepileupto(av, y);
}
/* nbmax: maximum number of possible conjugates */
GEN
galoisconj2pol(GEN x, long nbmax, long prec)
{
long av = avma, i, n, v, nbauto;
GEN y, w, polr, p1, p2;
n = lgef(x) - 3;
if (n <= 0)
return cgetg(1, t_VEC);
if (gisirreducible(x) == gzero)
err(redpoler, "galoisconj2pol");
polr = roots(x, prec);
p1 = (GEN) polr[1];
nbauto = 1;
prec = (long) (bit_accuracy(prec) * L2SL10 * 0.75);
w = cgetg(n + 2, t_VEC);
w[1] = un;
for (i = 2; i <= n; i++)
w[i] = lmul(p1, (GEN) w[i - 1]);
v = varn(x);
y = cgetg(nbmax + 1, t_COL);
y[1] = (long) polx[v];
for (i = 2; i <= n && nbauto < nbmax; i++)
{
w[n + 1] = polr[i];
p1 = lindep2(w, prec);
if (signe(p1[n + 1]))
{
setlg(p1, n + 1);
p2 = gdiv(gtopolyrev(p1, v), negi((GEN) p1[n + 1]));
if (gdivise(poleval(x, p2), x))
{
y[++nbauto] = (long) p2;
if (DEBUGLEVEL > 1)
fprintferr("conjugate %ld: %Z\n", i, y[nbauto]);
}
}
}
setlg(y, 1 + nbauto);
return gerepileupto(av, gen_sort(y, 0, cmp_pol));
}
GEN
galoisconj2(GEN nf, long nbmax, long prec)
{
long av = avma, i, j, n, r1, ru, nbauto;
GEN x, y, w, polr, p1, p2;
if (typ(nf) == t_POL)
return galoisconj2pol(nf, nbmax, prec);
nf = checknf(nf);
x = (GEN) nf[1];
n = lgef(x) - 3;
if (n <= 0)
return cgetg(1, t_VEC);
r1 = itos(gmael(nf, 2, 1));
p1 = (GEN) nf[6];
prec = precision((GEN) p1[1]);
/* accuracy in decimal digits */
prec = (long) (bit_accuracy(prec) * L2SL10 * 0.75);
ru = (n + r1) >> 1;
nbauto = 1;
polr = cgetg(n + 1, t_VEC);
for (i = 1; i <= r1; i++)
polr[i] = p1[i];
for (j = i; i <= ru; i++)
{
polr[j++] = p1[i];
polr[j++] = lconj((GEN) p1[i]);
}
p2 = gmael(nf, 5, 1);
w = cgetg(n + 2, t_VEC);
for (i = 1; i <= n; i++)
w[i] = coeff(p2, 1, i);
y = cgetg(nbmax + 1, t_COL);
y[1] = (long) polx[varn(x)];
for (i = 2; i <= n && nbauto < nbmax; i++)
{
w[n + 1] = polr[i];
p1 = lindep2(w, prec);
if (signe(p1[n + 1]))
{
setlg(p1, n + 1);
settyp(p1, t_COL);
p2 = gdiv(gmul((GEN) nf[7], p1), negi((GEN) p1[n + 1]));
if (gdivise(poleval(x, p2), x))
{
y[++nbauto] = (long) p2;
if (DEBUGLEVEL > 1)
fprintferr("conjugate %ld: %Z\n", i, y[nbauto]);
}
}
}
setlg(y, 1 + nbauto);
return gerepileupto(av, gen_sort(y, 0, cmp_pol));
}
/*************************************************************************/
/** **/
/** GALOIS4 **/
/** **/
/** **/
/** **/
/*************************************************************************/
struct galois_lift
{
GEN T;
GEN den;
GEN p;
GEN borne;
GEN L;
long e;
GEN Q;
};
/* Initialise la structure galois_lift */
void
initlift(GEN T, GEN den, GEN p, GEN borne, GEN L, struct galois_lift * gl)
{
ulong ltop, lbot;
gl->T = T;
gl->den = den;
gl->p = p;
gl->borne = borne;
gl->L = L;
ltop = avma;
gl->e = itos(gmax(gdeux, gceil(gdiv(glog(gmul2n(borne, 1), DEFAULTPREC),
glog(p, DEFAULTPREC)))));
lbot = avma;
gl->Q = gpowgs(p, gl->e);
gl->Q = gerepile(ltop, lbot, gl->Q);
}
/*
* T est le polynome \sum t_i*X^i S est un Polmod T Retourne un vecteur Spow
* verifiant la condition: i>=1 et t_i!=0 ==> Spow[i]=S^(i-1)*t_i Essaie
* d'etre efficace sur les polynomes lacunaires
*/
GEN
compoTS(GEN T, GEN S)
{
GEN Spow;
int i;
Spow = cgetg(lgef(T) - 2, t_VEC);
for (i = 3; i < lg(Spow); i++)
Spow[i] = 0;
Spow[1] = un;
Spow[2] = (long) S;
for (i = 2; i < lg(Spow) - 1; i++)
{
if (!gcmp0((GEN) T[i + 3]))
for (;;)
{
int k, l;
for (k = 1; k <= (i >> 1); k++)
if (Spow[k + 1] && Spow[i - k + 1])
break;
if ((k << 1) < i)
{
Spow[i + 1] = lmul((GEN) Spow[k + 1], (GEN) Spow[i - k + 1]);
break;
} else if ((k << 1) == i) /* En esperant que sqr est plus
* rapide... */
{
Spow[i + 1] = lsqr((GEN) Spow[k + 1]);
break;
}
for (k = i - 1; k > 0; k--)
if (Spow[k + 1])
break;
if ((k << 1) < i)
{
Spow[(k << 1) + 1] = lsqr((GEN) Spow[k + 1]);
continue;
}
for (l = i - k; l > 0; l--)
if (Spow[l + 1])
break;
if (Spow[i - l - k + 1])
Spow[i - k + 1] = lmul((GEN) Spow[i - l - k + 1], (GEN) Spow[l + 1]);
else
Spow[l + k + 1] = lmul((GEN) Spow[k + 1], (GEN) Spow[l + 1]);
}
}
for (i = 1; i < lg(Spow); i++)
if (!gcmp0((GEN) T[i + 2]))
Spow[i] = lmul((GEN) Spow[i], (GEN) T[i + 2]);
return Spow;
}
/*
* Calcule T(S) a l'aide du vecteur Spow
*/
static GEN
calcTS(GEN Spow, GEN T, GEN S)
{
GEN res = gzero;
int i;
for (i = 1; i < lg(Spow); i++)
if (!gcmp0((GEN) T[i + 2]))
res = gadd(res, (GEN) Spow[i]);
res = gmul(res, S);
return gadd(res, (GEN) T[2]);
}
/*
* Calcule T'(S) a l'aide du vecteur Spow
*/
static GEN
calcderivTS(GEN Spow, GEN T, GEN mod)
{
GEN res = gzero;
int i;
for (i = 1; i < lg(Spow); i++)
if (!gcmp0((GEN) T[i + 2]))
res = gadd(res, gmul((GEN) Spow[i], stoi(i)));
res = gmul(lift(lift(res)), mod);
return gmodulcp(res, T);
}
/*
* Verifie que S est une solution presque surement et calcule sa permutation
*/
static int
poltopermtest(GEN f, GEN L, GEN pf)
{
ulong ltop;
GEN fx, fp;
int i, j;
fp = cgetg(lg(L), t_VECSMALL);
ltop = avma;
for (i = 1; i < lg(fp); i++)
fp[i] = 1;
for (i = 1; i < lg(L); i++)
{
fx = gsubst(f, varn(f), (GEN) L[i]);
for (j = 1; j < lg(L); j++)
if (fp[j] && gegal(fx, (GEN) L[j]))
{
pf[i] = j;
fp[j] = 0;
break;
}
if (j == lg(L))
return 0;
avma = ltop;
}
return 1;
}
/*
* Soit T un polynome de \ZZ[X] , p un nombre premier , S\in\FF_p[X]/(T) tel
* que T(S)=0 [p,T] Relever S en S_0 tel que T(S_0)=0 [T,p^e]
*/
GEN
automorphismlift(GEN S, struct galois_lift * gl)
{
ulong ltop, lbot;
long x;
GEN q, mod, modold;
GEN W, Tr, Sr, Wr = gzero, Trold, Spow;
int flag, init, ex;
GEN *gptr[2];
if (DEBUGLEVEL >= 1)
timer2();
x = varn(gl->T);
Tr = gmul(gl->T, gmodulcp(gun, gl->p));
W = ginv(gsubst(deriv(Tr, x), x, S));
q = gl->p;
modold = gl->p;
Trold = Tr;
ex = 1;
flag = 1;
init = 0;
gptr[0] = &S;
gptr[1] = &Wr;
while (flag)
{
if (DEBUGLEVEL >= 1)
timer2();
q = gsqr(q);
ex <<= 1;
if (ex >= gl->e)
{
flag = 0;
q = gl->Q;
ex = gl->e;
}
mod = gmodulcp(gun, q);
Tr = gmul(gl->T, mod);
ltop = avma;
Sr = gmodulcp(gmul(lift(lift(S)), mod), Tr);
Spow = compoTS(Tr, Sr);
if (init)
W = gmul(Wr, gsub(gdeux, gmul(Wr, calcderivTS(Spow, Trold, modold))));
else
init = 1;
Wr = gmodulcp(gmul(lift(lift(W)), mod), Tr);
S = gmul(Wr, calcTS(Spow, Tr, Sr));
lbot = avma;
Wr = gcopy(Wr);
S = gsub(Sr, S);
gerepilemanysp(ltop, lbot, gptr, 2);
modold = mod;
Trold = Tr;
}
if (DEBUGLEVEL >= 1)
msgtimer("automorphismlift()");
return S;
}
struct galois_testlift
{
long n;
long f;
long g;
GEN bezoutcoeff;
GEN pauto;
};
/*
* Si polb est un polynomes de Z[X] et pola un facteur modulo p, retourne b*v
* telqu' il existe u et a tel que: a=pola [mod p] a*b=polb [mod p^e]
* b*v+a*u=1 [mod p^e]
*/
GEN
bezout_lift_fact(GEN pola, GEN polb, GEN p, GEN pev, long e)
{
long ev;
GEN ae, be, u, v, ae2, be2, s, t, pe, pe2, z, g;
long ltop = avma, lbot;
if (DEBUGLEVEL >= 1)
timer2();
ae = lift(pola);
be = Fp_poldivres(polb, ae, p, NULL);
g = (GEN) Fp_pol_extgcd(ae, be, p, &u, &v)[2]; /* deg g = 0 */
if (!gcmp1(g))
{
g = mpinvmod(g, p);
u = gmul(u, g);
v = gmul(v, g);
}
for (pe = p, ev = 1; ev < e;)
{
ev <<= 1;
pe2 = (ev >= e) ? pev : sqri(pe);
g = gadd(polb, gneg_i(gmul(ae, be)));
g = Fp_pol_red(g, pe2);
g = gdivexact(g, pe);
z = Fp_pol_red(gmul(v, g), pe);
t = Fp_poldivres(z, ae, pe, &s);
t = gadd(gmul(u, g), gmul(t, be));
t = Fp_pol_red(t, pe);
be2 = gadd(be, gmul(t, pe));
ae2 = gadd(ae, gmul(s, pe));/* already reduced mod pe2 */
g = gadd(gun, gneg_i(gadd(gmul(u, ae2), gmul(v, be2))));
g = Fp_pol_red(g, pe2);
g = gdivexact(g, pe);
z = Fp_pol_red(gmul(v, g), pe);
t = Fp_poldivres(z, ae, pe, &s);
t = gadd(gmul(u, g), gmul(t, be));
t = Fp_pol_red(t, pe);
u = gadd(u, gmul(t, pe));
v = gadd(v, gmul(s, pe));
pe = pe2;
ae = ae2;
be = be2;
}
lbot = avma;
g = gmul(v, be);
g = gerepile(ltop, lbot, g);
if (DEBUGLEVEL >= 1)
msgtimer("bezout_lift_fact()");
return g;
}
static long
inittestlift(GEN Tmod, long elift, struct galois_lift * gl, struct galois_testlift * gt, GEN frob)
{
ulong ltop = avma;
int i, j;
long v;
GEN pe, autpow, plift;
GEN Tmodp, xmodp, modQ, TmodQ, xmodQ;
GEN *gptr[2];
v = varn(gl->T);
gt->n = lg(gl->L) - 1;
gt->g = lg(Tmod) - 1;
gt->f = gt->n / gt->g;
Tmodp = gmul(gl->T, gmodulcp(gun, gl->p));
xmodp = gmodulcp(gmul(polx[v], gmodulcp(gun, gl->p)), Tmodp);
pe = gpowgs(gl->p, elift);
plift = automorphismlift(powgi(xmodp, pe), gl);
if (frob)
{
GEN tlift;
tlift = gdiv(centerlift(gmul((GEN) plift[2], gl->den)), gl->den);
if (poltopermtest(tlift, gl->L, frob))
{
avma = ltop;
return 1;
}
}
modQ = gmodulcp(gun, gl->Q);
TmodQ = gmul(gl->T, modQ);
xmodQ = gmodulcp(gmul(polx[v], modQ), TmodQ);
gt->bezoutcoeff = cgetg(gt->g + 1, t_VEC);
for (i = 1; i <= gt->g; i++)
{
GEN blift;
blift = bezout_lift_fact((GEN) Tmod[i], gl->T, gl->p, gl->Q, gl->e);
gt->bezoutcoeff[i] = (long) gmodulcp(gmul(blift, modQ), TmodQ);
}
gt->pauto = cgetg(gt->f + 1, t_VEC);
gt->pauto[1] = (long) xmodQ;
gt->pauto[2] = (long) plift;
if (gt->f > 2)
{
autpow = cgetg(gt->n, t_VEC);
autpow[1] = (long) plift;
for (i = 2; i < gt->n; i++)
autpow[i] = lmul((GEN) autpow[i - 1], plift);
for (i = 3; i <= gt->f; i++)
{
GEN s, P;
P = ((GEN **) gt->pauto)[i - 1][2];
s = (GEN) P[2];
for (j = 1; j < lgef(P) - 2; j++)
s = gadd(s, gmul((GEN) autpow[j], (GEN) P[j + 2]));
gt->pauto[i] = (long) s;
}
}
gptr[0] = >->bezoutcoeff;
gptr[1] = >->pauto;
gerepilemany(ltop, gptr, 2);
return 0;
}
/*
*
*/
long
frobeniusliftall(GEN sg, GEN * psi, struct galois_lift * gl, struct galois_testlift * gt, GEN frob)
{
ulong ltop = avma, av, ltop2;
long d, N, z, m, c;
int i, j, k;
GEN pf, u, v;
m = gt->g;
c = lg(sg) - 1;
d = m / c;
pf = cgetg(m, t_VECSMALL);
*psi = pf;
ltop2 = avma;
N = itos(gdiv(mpfact(m), gmul(stoi(c), gpowgs(mpfact(d), c))));
avma = ltop2;
v = gmul((GEN) gt->pauto[2], (GEN) gt->bezoutcoeff[m]);
for (i = 1; i < m; i++)
pf[i] = 1 + i / d;
av = avma;
for (i = 0;; i++)
{
u = v;
if (DEBUGLEVEL >= 4)
{
fprintferr("GaloisConj:Testing %Z:%d:%Z:", sg, i, pf);
timer2();
}
for (j = 1; j < m; j++)
u = gadd(u, gmul((GEN) gt->pauto[sg[pf[j]] + 1], (GEN) gt->bezoutcoeff[j]));
u = gdiv(centerlift(gmul((GEN) u[2], gl->den)), gl->den);
if (poltopermtest(u, gl->L, frob))
{
if (DEBUGLEVEL >= 4)
msgtimer("");
avma = ltop2;
return 1;
}
if (DEBUGLEVEL >= 4)
msgtimer("");
avma = av;
if (i == N - 1)
break;
for (j = 2; j < m && pf[j - 1] >= pf[j]; j++);
for (k = 1; k < j - k && pf[k] != pf[j - k]; k++)
{
z = pf[k];
pf[k] = pf[j - k];
pf[j - k] = z;
}
for (k = j - 1; pf[k] >= pf[j]; k--);
z = pf[j];
pf[j] = pf[k];
pf[k] = z;
}
avma = ltop;
*psi = NULL;
return 0;
}
/*
* applique une permutation t a un vecteur s sans duplication
*/
static GEN
applyperm(GEN s, GEN t)
{
GEN u;
int i;
if (lg(s) < lg(t))
err(talker, "First permutation shorter than second in applyperm");
u = cgetg(lg(s), typ(s));
for (i = 1; i < lg(s); i++)
u[i] = s[t[i]];
return u;
}
/*
* alloue une ardoise pour n entiers de longueurs pour les test de
* permutation
*/
GEN
alloue_ardoise(long n, long s)
{
GEN ar;
long i;
ar = cgetg(n + 1, t_VEC);
for (i = 1; i <= n; i++)
ar[i] = lgetg(s, t_INT);
return ar;
}
/*
* structure contenant toutes les données pour le tests des permutations:
*
* ordre :ordre des tests pour verifie_test ordre[lg(ordre)]: numero du test
* principal borne : borne sur les coefficients a trouver ladic: modulo
* l-adique des racines lborne:ladic-borne TM:vecteur des ligne de M
* PV:vecteur des clones des matrices de test (Vmatrix) (ou NULL si non
* calcule) L,M comme d'habitude (voir plus bas)
*/
struct galois_test
{
GEN ordre;
GEN borne, lborne, ladic;
GEN PV, TM;
GEN L, M;
};
/* Calcule la matrice de tests correspondant a la n-ieme ligne de V */
static GEN
Vmatrix(long n, struct galois_test * td)
{
ulong ltop = avma, lbot;
GEN V;
long i;
V = cgetg(lg(td->L), t_VEC);
for (i = 1; i < lg(V); i++)
V[i] = ((GEN **) td->M)[i][n][2];
V = centerlift(gmul(td->L, V));
lbot = avma;
V = gmod(V, td->ladic);
return gerepile(ltop, lbot, V);
}
/*
* Initialise la structure galois_test
*/
static void
inittest(GEN L, GEN M, GEN borne, GEN ladic, struct galois_test * td)
{
ulong ltop;
long i;
int n = lg(L) - 1;
if (DEBUGLEVEL >= 8)
fprintferr("GaloisConj:Entree Init Test\n");
td->ordre = cgetg(n + 1, t_VECSMALL);
for (i = 1; i <= n - 2; i++)
td->ordre[i] = i + 2;
for (; i <= n; i++)
td->ordre[i] = i - n + 2;
td->borne = borne;
td->lborne = gsub(ladic, borne);
td->ladic = ladic;
td->L = L;
td->M = M;
td->PV = cgetg(n + 1, t_VECSMALL); /* peut-etre t_VEC est correct ici */
for (i = 1; i <= n; i++)
td->PV[i] = 0;
ltop = avma;
td->PV[td->ordre[n]] = (long) gclone(Vmatrix(td->ordre[n], td));
avma = ltop;
td->TM = gtrans(M);
settyp(td->TM, t_VEC);
for (i = 1; i < lg(td->TM); i++)
settyp(td->TM[i], t_VEC);
if (DEBUGLEVEL >= 8)
fprintferr("GaloisConj:Sortie Init Test\n");
}
/*
* liberer les clones de la structure galois_test
*
* Reservé a l'accreditation ultra-violet:Liberez les clones! Paranoia(tm)
*/
static void
freetest(struct galois_test * td)
{
int i;
for (i = 1; i < lg(td->PV); i++)
if (td->PV[i])
{
gunclone((GEN) td->PV[i]);
td->PV[i] = 0;
}
}
/*
* Test si le nombre padique P est proche d'un entier inferieur a td->borne
* en valeur absolue.
*/
long
padicisint(GEN P, struct galois_test * td)
{
long r;
ulong ltop = avma;
GEN U;
if (typ(P) != t_INT)
err(typeer, "padicisint");
U = modii(P, td->ladic);
r = gcmp(U, (GEN) td->borne) <= 0 || gcmp(U, (GEN) td->lborne) >= 0;
avma = ltop;
return r;
}
/*
* Verifie si pf est une vrai solution et non pas un "hop"
*/
static long
verifietest(GEN pf, struct galois_test * td)
{
ulong av = avma;
GEN P, V;
int i, j;
int n = lg(td->L) - 1;
if (DEBUGLEVEL >= 8)
fprintferr("GaloisConj:Entree Verifie Test\n");
P = applyperm(td->L, pf);
for (i = 1; i < n; i++)
{
long ord;
GEN PW;
ord = td->ordre[i];
PW = (GEN) td->PV[ord];
if (PW)
{
V = ((GEN **) PW)[1][pf[1]];
for (j = 2; j <= n; j++)
V = gadd(V, ((GEN **) PW)[j][pf[j]]);
} else
V = centerlift(gmul((GEN) td->TM[ord], P));
if (!padicisint(V, td))
break;
}
if (i == n)
{
if (DEBUGLEVEL >= 8)
fprintferr("GaloisConj:Sortie Verifie Test:1\n");
avma = av;
return 1;
}
if (!td->PV[td->ordre[i]])
{
td->PV[td->ordre[i]] = (long) gclone(Vmatrix(td->ordre[i], td));
if (DEBUGLEVEL >= 2)
fprintferr("M");
}
if (DEBUGLEVEL >= 2)
fprintferr("%d.", i);
if (i > 1)
{
long z;
z = td->ordre[i];
for (j = i; j > 1; j--)
td->ordre[j] = td->ordre[j - 1];
td->ordre[1] = z;
if (DEBUGLEVEL >= 6)
fprintferr("%Z", td->ordre);
}
if (DEBUGLEVEL >= 8)
fprintferr("GaloisConj:Sortie Verifie Test:0\n");
avma = av;
return 0;
}
/*
* F est la decomposition en cycle de sigma, B est la decomposition en cycle
* de cl(tau) Teste toutes les permutations pf pouvant correspondre a tau tel
* que : tau*sigma*tau^-1=sigma^s et tau^d=sigma^t ou d est l'ordre de
* cl(tau) --------- x: vecteur des choix y: vecteur des mises a jour G:
* vecteur d'acces a F linéaire
*/
GEN
testpermutation(GEN F, GEN B, long s, long t, long cut, struct galois_test * td)
{
ulong av, avm = avma, av2;
long a, b, c, d, n;
GEN pf, x, ar, y, *G;
int N, cx, p1, p2, p3, p4, p5, p6;
int i, j, hop = 0;
GEN V, W;
if (DEBUGLEVEL >= 1)
timer2();
a = lg(F) - 1;
b = lg(F[1]) - 1;
c = lg(B) - 1;
d = lg(B[1]) - 1;
n = a * b;
s = (b + s) % b;
pf = cgetg(n + 1, t_VECSMALL);
av = avma;
ar = alloue_ardoise(a, 1 + lg(td->ladic));
x = cgetg(a + 1, t_VECSMALL);
y = cgetg(a + 1, t_VECSMALL);
G = (GEN *) cgetg(a + 1, t_VECSMALL); /* Don't worry */
av2 = avma;
W = (GEN) td->PV[td->ordre[n]];
for (cx = 1, i = 1, j = 1; cx <= a; cx++, i++)
{
x[cx] = (i != d) ? 0 : t;
y[cx] = 1;
G[cx] = (GEN) F[((long **) B)[j][i]]; /* Be happy */
if (i == d)
{
i = 0;
j++;
}
} /* Be happy now! */
N = itos(gpowgs(stoi(b), c * (d - 1))) / cut;
avma = av2;
if (DEBUGLEVEL >= 4)
fprintferr("GaloisConj:I will try %d permutations\n", N);
for (cx = 0; cx < N; cx++)
{
if (DEBUGLEVEL >= 2 && cx % 1000 == 999)
fprintferr("%d%% ", (100 * cx) / N);
if (cx)
{
for (i = 1, j = d; i < a;)
{
y[i] = 1;
if ((++(x[i])) != b)
break;
x[i++] = 0;
if (i == j)
{
y[i++] = 1;
j += d;
}
}
y[i + 1] = 1;
}
for (p1 = 1, p5 = d; p1 <= a; p1++, p5++)
if (y[p1])
{
if (p5 == d)
{
p5 = 0;
p4 = 0;
} else
p4 = x[p1 - 1];
if (p5 == d - 1)
p6 = p1 + 1 - d;
else
p6 = p1 + 1;
y[p1] = 0;
V = gzero;
for (p2 = 1 + p4, p3 = 1 + x[p1]; p2 <= b; p2++)
{
V = gadd(V, ((GEN **) W)[G[p6][p3]][G[p1][p2]]);
p3 += s;
if (p3 > b)
p3 -= b;
}
p3 = 1 + x[p1] - s;
if (p3 <= 0)
p3 += b;
for (p2 = p4; p2 >= 1; p2--)
{
V = gadd(V, ((GEN **) W)[G[p6][p3]][G[p1][p2]]);
p3 -= s;
if (p3 <= 0)
p3 += b;
}
gaffect((GEN) V, (GEN) ar[p1]);
}
V = gzero;
for (p1 = 1; p1 <= a; p1++)
V = gadd(V, (GEN) ar[p1]);
if (padicisint(V, td))
{
for (p1 = 1, p5 = d; p1 <= a; p1++, p5++)
{
if (p5 == d)
{
p5 = 0;
p4 = 0;
} else
p4 = x[p1 - 1];
if (p5 == d - 1)
p6 = p1 + 1 - d;
else
p6 = p1 + 1;
for (p2 = 1 + p4, p3 = 1 + x[p1]; p2 <= b; p2++)
{
pf[G[p1][p2]] = G[p6][p3];
p3 += s;
if (p3 > b)
p3 -= b;
}
p3 = 1 + x[p1] - s;
if (p3 <= 0)
p3 += b;
for (p2 = p4; p2 >= 1; p2--)
{
pf[G[p1][p2]] = G[p6][p3];
p3 -= s;
if (p3 <= 0)
p3 += b;
}
}
if (verifietest(pf, td))
{
avma = av;
if (DEBUGLEVEL >= 1)
msgtimer("testpermutation(%d)", cx + 1);
if (DEBUGLEVEL >= 2 && hop)
fprintferr("GaloisConj:%d hop sur %d iterations\n", hop, cx + 1);
return pf;
} else
hop++;
}
avma = av2;
}
avma = avm;
if (DEBUGLEVEL >= 1)
msgtimer("testpermutation(%d)", N);
if (DEBUGLEVEL >= 2 && hop)
fprintferr("GaloisConj:%d hop sur %d iterations\n", hop, N);
return gzero;
}
/*
* Calcule la liste des sous groupes de \ZZ/m\ZZ d'ordre divisant p et
* retourne la liste de leurs elements
*/
GEN
listsousgroupes(long m, long p)
{
ulong ltop = avma, lbot;
GEN zns, lss, res, sg, gen, ord, res1;
int k, card, i, j, l, n, phi, h;
if (m == 2)
{
res = cgetg(2, t_VEC);
sg = cgetg(2, t_VECSMALL);
res[1] = (long) sg;
sg[1] = 1;
return res;
}
zns = znstar(stoi(m));
phi = itos((GEN) zns[1]);
lss = subgrouplist((GEN) zns[2], 0);
gen = cgetg(lg(zns[3]), t_VECSMALL);
ord = cgetg(lg(zns[3]), t_VECSMALL);
res1 = cgetg(lg(lss), t_VECSMALL);
lbot = avma;
for (k = 1, i = lg(lss) - 1; i >= 1; i--)
{
long av;
av = avma;
card = phi / itos(det((GEN) lss[i]));
avma = av;
if (p % card == 0)
{
sg = cgetg(1 + card, t_VECSMALL);
sg[1] = 1;
av = avma;
for (j = 1; j < lg(gen); j++)
{
gen[j] = 1;
for (h = 1; h < lg(lss[i]); h++)
gen[j] = (gen[j] * itos(lift(powgi(((GEN **) zns)[3][h],
((GEN ***) lss)[i][j][h])))) % m;
ord[j] = itos(((GEN **) zns)[2][j]) / itos(((GEN ***) lss)[i][j][j]);
}
avma = av;
for (j = 1, l = 1; j < lg(gen); j++)
{
int c = l * (ord[j] - 1);
for (n = 1; n <= c; n++)/* I like it */
sg[++l] = (sg[n] * gen[j]) % m;
}
res1[k++] = (long) sg;
}
}
res = cgetg(k, t_VEC);
for (i = 1; i < k; i++)
res[i] = res1[i];
return gerepile(ltop, lbot, res);
}
/* retourne la permutation identite */
GEN
permidentity(long l)
{
GEN perm;
int i;
perm = cgetg(l + 1, t_VECSMALL);
for (i = 1; i <= l; i++)
perm[i] = i;
return perm;
}
/* retourne la decomposition en cycle */
GEN
permtocycle(GEN p)
{
long ltop = avma, lbot;
int i, j, k, l, m;
GEN bit, cycle, cy;
cycle = cgetg(lg(p), t_VEC);
bit = cgetg(lg(p), t_VECSMALL);
for (i = 1; i < lg(p); i++)
bit[i] = 0;
for (k = 1, l = 1; k < lg(p);)
{
for (j = 1; bit[j]; j++);
cy = cgetg(lg(p), t_VECSMALL);
m = 1;
do
{
bit[j] = 1;
k++;
cy[m++] = j;
j = p[j];
} while (!bit[j]);
setlg(cy, m);
cycle[l++] = (long) cy;
}
setlg(cycle, l);
lbot = avma;
cycle = gcopy(cycle);
return gerepile(ltop, lbot, cycle);
}
/* Calcule les orbites d'un ensemble de permutations */
GEN
vecpermorbite(GEN v)
{
ulong ltop = avma, lbot;
int i, j, k, l, m, n, o, p, flag;
GEN bit, cycle, cy;
n = lg(v[1]);
cycle = cgetg(n, t_VEC);
bit = cgetg(n, t_VECSMALL);
for (i = 1; i < n; i++)
bit[i] = 0;
for (k = 1, l = 1; k < n;)
{
for (j = 1; bit[j]; j++);
cy = cgetg(n, t_VECSMALL);
m = 1;
cy[m++] = j;
bit[j] = 1;
k++;
do
{
flag = 0;
for (o = 1; o < lg(v); o++)
{
for (p = 1; p < m; p++) /* m varie! */
{
j = ((long **) v)[o][cy[p]];
if (!bit[j])
{
flag = 1;
bit[j] = 1;
k++;
cy[m++] = j;
}
}
}
} while (flag);
setlg(cy, m);
cycle[l++] = (long) cy;
}
setlg(cycle, l);
lbot = avma;
cycle = gcopy(cycle);
return gerepile(ltop, lbot, cycle);
}
/*
* Calcule la permutation associe a un polynome f des racines L
*/
GEN
poltoperm(GEN f, GEN L)
{
ulong ltop, ltop2;
GEN pf, fx, fp;
int i, j;
pf = cgetg(lg(L), t_VECSMALL);
ltop = avma;
fp = cgetg(lg(L), t_VECSMALL);
ltop2 = avma;
for (i = 1; i < lg(fp); i++)
fp[i] = 1;
for (i = 1; i < lg(L); i++)
{
fx = gsubst(f, varn(f), (GEN) L[i]);
for (j = 1; j < lg(L); j++)
if (fp[j] && gegal(fx, (GEN) L[j]))
{
pf[i] = j;
fp[j] = 0;
break;
}
avma = ltop2;
}
avma = ltop;
return pf;
}
/*
* Calcule un polynome R definissant le corps fixe de T pour les orbites O
* tel que R est sans-facteur carre modulo mod et l retourne dans U les
* racines de R
*/
GEN
corpsfixeorbitemod(GEN L, GEN O, long x, GEN mod, GEN l, GEN * U)
{
ulong ltop = avma, lbot, av, av2;
GEN g, p, PL, *gptr[2], gmod, gl, modl;
GEN id;
int i, j, d, dmax;
PL = cgetg(lg(O), t_COL);
modl = gmodulcp(gun, l);
av2 = avma;
dmax = lg(L) + 1;
d = 0;
do
{
avma = av2;
id = stoi(d);
g = polun[x];
for (i = 1; i < lg(O); i++)
{
p = gadd(id, (GEN) L[((GEN *) O)[i][1]]);
for (j = 2; j < lg(O[i]); j++)
p = gmul(p, gadd(id, (GEN) L[((GEN *) O)[i][j]]));
PL[i] = (long) p;
g = gmul(g, gsub(polx[x], p));
}
lbot = avma;
g = centerlift(g);
av = avma;
gmod = gmul(g, mod);
gl = gmul(g, modl);
if (DEBUGLEVEL >= 6)
fprintferr("GaloisConj:corps fixe:%d:%Z\n", d, g);
d = (d > 0 ? -d : 1 - d);
if (d > dmax)
err(talker, "prime too small in corpsfixeorbitemod");
} while (degree(ggcd(deriv(gl, x), gl)) || degree(ggcd(deriv(gmod, x), gmod)));
avma = av;
*U = gcopy(PL);
gptr[0] = &g;
gptr[1] = U;
gerepilemanysp(ltop, lbot, gptr, 2);
return g;
}
/*
* Calcule l'inclusion de R dans T i.e. S telque T|R\compo S
*/
GEN
corpsfixeinclusion(GEN O, GEN PL)
{
GEN S;
int i, j;
S = cgetg((lg(O) - 1) * (lg(O[1]) - 1) + 1, t_COL);
for (i = 1; i < lg(O); i++)
for (j = 1; j < lg(O[i]); j++)
S[((GEN *) O)[i][j]] = lcopy((GEN) PL[i]);
return S;
}
/* Calcule l'inverse de la matrice de van der Monde de T multiplie par den */
GEN
vandermondeinverse(GEN L, GEN T, GEN den)
{
ulong ltop = avma, lbot;
int i, j, n = lg(L);
long x = varn(T);
GEN M, P, Tp;
if (DEBUGLEVEL >= 1)
timer2();
M = cgetg(n, t_MAT);
Tp = deriv(T, x);
for (i = 1; i < n; i++)
{
M[i] = lgetg(n, t_COL);
P = gdiv(gdeuc(T, gsub(polx[x], (GEN) L[i])), gsubst(Tp, x, (GEN) L[i]));
for (j = 1; j < n; j++)
((GEN *) M)[i][j] = P[1 + j];
}
if (DEBUGLEVEL >= 1)
msgtimer("vandermondeinverse");
lbot = avma;
M = gmul(den, M);
return gerepile(ltop, lbot, M);
}
/* Calcule le polynome associe a un vecteur conjugue v */
static GEN
vectopol(GEN v, GEN L, GEN M, GEN den, long x)
{
ulong ltop = avma, lbot;
GEN res;
res = gmul(M, v);
res = gtopolyrev(centerlift(res), x);
lbot = avma;
res = gdiv(res, den);
return gerepile(ltop, lbot, res);
}
/* Calcule le polynome associe a une permuation p */
static GEN
permtopol(GEN p, GEN L, GEN M, GEN den, long x)
{
ulong ltop = avma, lbot;
GEN res;
res = gmul(M, applyperm(L, p));
res = gtopolyrev(centerlift(res), x);
lbot = avma;
res = gdiv(res, den);
return gerepile(ltop, lbot, res);
}
/*
* factorise partiellement n sous la forme n=d*u*f^2 ou d est sans facteur
* carre et u n'est pas un carre parfait et retourne u*f
*/
GEN
mycoredisc(GEN n)
{
ulong av = avma, tetpil, r;
GEN y, p1, p2, ret;
{
long av = avma, tetpil, i;
GEN fa, p1, p2, p3, res = gun, res2 = gun, y;
fa = auxdecomp(n, 0);
p1 = (GEN) fa[1];
p2 = (GEN) fa[2];
for (i = 1; i < lg(p1) - 1; i++)
{
p3 = (GEN) p2[i];
if (mod2(p3))
res = mulii(res, (GEN) p1[i]);
if (!gcmp1(p3))
res2 = mulii(res2, gpui((GEN) p1[i], shifti(p3, -1), 0));
}
p3 = (GEN) p2[i];
if (mod2(p3)) /* impaire: verifions */
{
if (!gcmp1(p3))
res2 = mulii(res2, gpui((GEN) p1[i], shifti(p3, -1), 0));
if (isprime((GEN) p1[i]))
res = mulii(res, (GEN) p1[i]);
else
res2 = mulii(res2, (GEN) p1[i]);
} else /* paire:OK */
res2 = mulii(res2, gpui((GEN) p1[i], shifti(p3, -1), 0));
tetpil = avma;
y = cgetg(3, t_VEC);
y[1] = (long) icopy(res);
y[2] = (long) icopy(res2);
ret = gerepile(av, tetpil, y);
}
p2 = ret;
p1 = (GEN) p2[1];
r = mod4(p1);
if (signe(p1) < 0)
r = 4 - r;
if (r == 1 || r == 4)
return (GEN) p2[2];
tetpil = avma;
y = gmul2n((GEN) p2[2], -1);
return gerepile(av, tetpil, y);
}
/* Calcule la puissance exp d'une permutation decompose en cycle */
GEN
permcyclepow(GEN O, long exp)
{
int j, k, n;
GEN p;
for (n = 0, j = 1; j < lg(O); j++)
n += lg(O[j]) - 1;
p = cgetg(n + 1, t_VECSMALL);
for (j = 1; j < lg(O); j++)
{
n = lg(O[j]) - 1;
for (k = 1; k <= n; k++)
p[((long **) O)[j][k]] = ((long **) O)[j][1 + (k + exp - 1) % n];
}
return p;
}
/*
* Casse l'orbite O en sous-orbite d'ordre premier correspondant a des
* puissance de l'element
*/
GEN
splitorbite(GEN O)
{
ulong ltop = avma, lbot;
int i, n;
GEN F, fc, res;
n = lg(O[1]) - 1;
F = factor(stoi(n));
fc = cgetg(lg(F[1]), t_VECSMALL);
for (i = 1; i < lg(fc); i++)
fc[i] = itos(gpow(((GEN **) F)[1][i], ((GEN **) F)[2][i], DEFAULTPREC));
lbot = avma;
res = cgetg(lg(fc), t_VEC);
for (i = 1; i < lg(fc); i++)
{
GEN v;
v = cgetg(3, t_VEC);
res[i] = (long) v;
v[1] = (long) permcyclepow(O, n / fc[i]);
v[2] = (long) stoi(fc[i]);
}
return gerepile(ltop, lbot, res);
}
/*
* structure qui contient l'analyse du groupe de Galois par etude des degres
* de Frobenius:
*
* p: nombre premier a relever deg: degre du lift à effectuer pgp: plus grand
* diviseur premier du degre de T. exception: 1 si le pgp-Sylow est
* non-cyclique. l: un nombre premier tel que T est totalement decompose
* modulo l ppp: plus petit diviseur premier du degre de T. primepointer:
* permet de calculer les premiers suivant p.
*/
struct galois_analysis
{
long p;
long deg;
long exception;
long ord;
long l;
long ppp;
long p4;
byteptr primepointer;
};
/* peut-etre on peut accelerer(distinct degree factorisation */
void
galoisanalysis(GEN T, struct galois_analysis * ga, long calcul_l)
{
ulong ltop = avma;
long n, p, ex, plift, nbmax, nbtest, exist6 = 0, p4 = 0;
GEN F, fc;
byteptr primepointer, pp = 0;
long pha, ord, deg, ppp, pgp, ordmax = 0, l = 0;
int i;
/* Etude du cardinal: */
/* Calcul de l'ordre garanti d'un sous-groupe cyclique */
/* Tout les groupes d'ordre n sont cyclique ssi gcd(n,phi(n))==1 */
if (DEBUGLEVEL >= 1)
timer2();
n = degree(T);
F = factor(stoi(n));
fc = cgetg(lg(F[1]), t_VECSMALL);
for (i = 1; i < lg(fc); i++)
fc[i] = itos(gpow(((GEN **) F)[1][i], ((GEN **) F)[2][i], DEFAULTPREC));
ppp = itos(((GEN **) F)[1][1]); /* Plus Petit diviseur Premier */
pgp = itos(((GEN **) F)[1][lg(F[1]) - 1]); /* Plus Grand diviseur
* Premier */
pha = 1;
ord = 1;
ex = 0;
for (i = lg(F[1]) - 1; i > 0; i--)
{
p = itos(((GEN **) F)[1][i]);
if (pha % p != 0)
{
ord *= p;
pha *= p - 1;
} else
{
ex = 1;
break;
}
if (!gcmp1(((GEN **) F)[2][i]))
break;
}
plift = 0;
/* Etude des ordres des Frobenius */
nbmax = max(4, n / 2); /* Nombre maxi d'éléments à tester */
nbtest = 0;
deg = 0;
for (p = 0, primepointer = diffptr; plift == 0 || (nbtest < nbmax && ord != n) || (n == 24 && exist6 == 0 && p4 == 0);)
{
long u, s, c;
long isram;
GEN S;
c = *primepointer++;
if (!c)
err(primer1);
p += c;
if (p <= (n << 1))
continue;
S = (GEN) simplefactmod(T, stoi(p));
isram = 0;
for (i = 1; i < lg(S[2]) && !isram; i++)
if (!gcmp1(((GEN **) S)[2][i]))
isram = 1;
if (isram == 0)
{
s = itos(((GEN **) S)[1][1]);
for (i = 2; i < lg(S[1]) && !isram; i++)
if (itos(((GEN **) S)[1][i]) != s)
{
avma = ltop;
if (DEBUGLEVEL >= 2)
fprintferr("GaloisAnalysis:non Galois for p=%d\n", p);
ga->p = p;
ga->deg = 0;
return; /* Not a Galois polynomial */
}
if (l == 0 && s == 1)
l = p;
nbtest++;
if (nbtest > (3 * nbmax) && (n == 60 || n == 75))
break;
if (s % 6 == 0)
exist6 = 1;
if (p4 == 0 && s == 4)
p4 = p;
if (DEBUGLEVEL >= 6)
fprintferr("GaloisAnalysis:Nbtest=%d,plift=%d,p=%d,s=%d,ord=%d\n", nbtest, plift, p, s, ord);
if (s > ordmax)
ordmax = s;
if (s >= ord) /* Calcul de l'exposant distinguant minimal
* garanti */
{
if (s * ppp == n) /* Tout sous groupe d'indice ppp est distingué */
u = s;
else /* Théorème de structure des groupes
* hyper-résoluble */
{
u = 1;
for (i = lg(fc) - 1; i > 0; i--)
{
if (s % fc[i] == 0)
u *= fc[i];
else
break;
}
}
if (u != 1)
{
if (!ex || s > ord || (s == ord && (plift == 0 || u > deg)))
{
deg = u;
ord = s;
plift = p;
pp = primepointer;
ex = 1;
}
} else if (!ex && (plift == 0 || s > ord))
/*
* J'ai besoin de plus de connaissance sur les p-groupes, surtout
* pour p=2;
*/
{
deg = pgp;
ord = s;
plift = p;
pp = primepointer;
ex = 0;
}
}
}
}
if (plift == 0 || ((n == 36 || n == 48) && !exist6) || (n == 56 && ordmax == 7) || (n == 60 && ordmax == 5) || (n == 72 && !exist6) || (n == 80 && ordmax == 5))
{
deg = 0;
err(warner, "Galois group almost certainly not weakly super solvable");
}
avma = ltop;
if (calcul_l)
{
ulong av;
GEN x;
long c;
x = cgetg(3, t_POLMOD);
x[2] = lpolx[varn(T)];
av = avma;
while (l == 0)
{
c = *primepointer++;
if (!c)
err(primer1);
p += c;
x[1] = lmul(T, gmodulss(1, p));
if (gegal(gpuigs(x, p), x))
l = p;
avma = av;
}
avma = ltop;
}
ga->p = plift;
ga->exception = ex;
ga->deg = deg;
ga->ord = ord;
ga->l = l;
ga->primepointer = pp;
ga->ppp = ppp;
ga->p4 = p4;
if (DEBUGLEVEL >= 4)
fprintferr("GaloisAnalysis:p=%d l=%d exc=%d deg=%d ord=%d ppp=%d\n", p, l, ex, deg, ord, ppp);
if (DEBUGLEVEL >= 1)
msgtimer("galoisanalysis()");
}
/* Calcule les bornes sur les coefficients a chercher */
struct galois_borne
{
GEN l;
long valsol;
long valabs;
GEN bornesol;
GEN ladicsol;
GEN ladicabs;
};
/*
* recalcule L avec une precision superieur
*/
GEN
recalculeL(GEN T, GEN Tp, GEN L, struct galois_borne * gb, struct galois_borne * ngb)
{
ulong ltop = avma, lbot = avma;
GEN L2, y, z, lad;
long i, val;
if (DEBUGLEVEL >= 1)
timer2();
L2 = cgetg(lg(L), typ(L));
for (i = 1; i < lg(L); i++)
{
ltop = avma;
val = gb->valabs;
lad = gb->ladicabs;
z = (GEN) L[i];
while (val < ngb->valabs)
{
val <<= 1;
if (val >= ngb->valabs)
{
val = ngb->valabs;
lad = ngb->ladicabs;
} else
lad = gsqr(lad);
y = gmodulcp((GEN) z[2], lad);
z = gdiv(poleval(T, y), poleval(Tp, y));
lbot = avma;
z = gsub(y, z);
}
L2[i] = (long) gerepile(ltop, lbot, z);
}
return L2;
}
void
initborne(GEN T, GEN disc, struct galois_borne * gb, long ppp)
{
ulong ltop = avma, lbot, av2;
GEN borne, borneroots, borneabs;
int i, j;
int n;
GEN L, M, z;
L = roots(T, DEFAULTPREC);
n = lg(L) - 1;
for (i = 1; i <= n; i++)
{
z = (GEN) L[i];
if (signe(z[2]))
break;
L[i] = z[1];
}
M = vandermondeinverse(L, gmul(T, realun(DEFAULTPREC)), disc);
borne = gzero;
for (i = 1; i <= n; i++)
{
z = gzero;
for (j = 1; j <= n; j++)
z = gadd(z, gabs(((GEN **) M)[j][i], DEFAULTPREC));
if (gcmp(z, borne) > 0)
borne = z;
}
borneroots = gzero;
for (i = 1; i <= n; i++)
{
z = gabs((GEN) L[i], DEFAULTPREC);
if (gcmp(z, borneroots) > 0)
borneroots = z;
}
borneabs = addsr(1, gpowgs(addsr(n, borneroots), n / ppp));
lbot = avma;
borneroots = addsr(1, gmul(borne, borneroots));
av2 = avma;
borneabs = gmul2n(gmul(borne, borneabs), 4);
gb->valsol = itos(gceil(gdiv(glog(gmul2n(borneroots, 4 + (n >> 1)), DEFAULTPREC), glog(gb->l, DEFAULTPREC))));
if (DEBUGLEVEL >= 4)
fprintferr("GaloisConj:val1=%d\n", gb->valsol);
gb->valabs = max(gb->valsol, itos(gceil(gdiv(glog(borneabs, DEFAULTPREC), glog(gb->l, DEFAULTPREC)))));
if (DEBUGLEVEL >= 4)
fprintferr("GaloisConj:val2=%d\n", gb->valabs);
avma = av2;
gb->bornesol = gerepile(ltop, lbot, borneroots);
gb->ladicsol = gpowgs(gb->l, gb->valsol);
gb->ladicabs = gpowgs(gb->l, gb->valabs);
}
/* Groupe A4 */
GEN
a4galoisgen(GEN T, struct galois_test * td)
{
int ltop = avma, av, av2;
int i, j, k;
int n;
int N, hop = 0;
GEN *ar, **mt; /* tired of casting */
GEN t, u, O;
GEN res, orb, ry;
GEN pft, pfu, pfv;
n = degree(T);
res = cgetg(4, t_VEC);
ry = cgetg(3, t_VEC);
res[1] = (long) ry;
pft = cgetg(n + 1, t_VECSMALL);
ry[1] = (long) pft;
ry[2] = (long) stoi(2);
ry = cgetg(3, t_VEC);
pfu = cgetg(n + 1, t_VECSMALL);
ry[1] = (long) pfu;
ry[2] = (long) stoi(2);
res[2] = (long) ry;
ry = cgetg(3, t_VEC);
pfv = cgetg(n + 1, t_VECSMALL);
ry[1] = (long) pfv;
ry[2] = (long) stoi(3);
res[3] = (long) ry;
av = avma;
ar = (GEN *) alloue_ardoise(n, 1 + lg(td->ladic));
mt = (GEN **) td->PV[td->ordre[n]];
t = cgetg(n + 1, t_VECSMALL) + 1; /* Sorry for this hack */
u = cgetg(n + 1, t_VECSMALL) + 1; /* too lazy to correct */
av2 = avma;
N = itos(gdiv(mpfact(n), mpfact(n >> 1))) >> (n >> 1);
if (DEBUGLEVEL >= 4)
fprintferr("A4GaloisConj:I will test %d permutations\n", N);
avma = av2;
for (i = 0; i < n; i++)
t[i] = i + 1;
for (i = 0; i < N; i++)
{
GEN g;
int a, x, y;
if (i == 0)
{
gaffect(gzero, ar[(n - 2) >> 1]);
for (k = n - 2; k > 2; k -= 2)
gaddz(ar[k >> 1], gadd(mt[k + 1][k + 2], mt[k + 2][k + 1]), ar[(k >> 1) - 1]);
} else
{
x = i;
y = 1;
do
{
hiremainder = 0;
y += 2;
x = divll(x, y);
a = hiremainder;
}
while (!a);
switch (y)
{
case 3:
x = t[2];
if (a == 1)
{
t[2] = t[1];
t[1] = x;
} else
{
t[2] = t[0];
t[0] = x;
}
break;
case 5:
x = t[0];
t[0] = t[2];
t[2] = t[1];
t[1] = x;
x = t[4];
t[4] = t[4 - a];
t[4 - a] = x;
gaddz(ar[2], gadd(mt[t[4]][t[5]], mt[t[5]][t[4]]), ar[1]);
break;
case 7:
x = t[0];
t[0] = t[4];
t[4] = t[3];
t[3] = t[1];
t[1] = t[2];
t[2] = x;
x = t[6];
t[6] = t[6 - a];
t[6 - a] = x;
gaddz(ar[3], gadd(mt[t[6]][t[7]], mt[t[7]][t[6]]), ar[2]);
gaddz(ar[2], gadd(mt[t[4]][t[5]], mt[t[5]][t[4]]), ar[1]);
break;
case 9:
x = t[0];
t[0] = t[6];
t[6] = t[5];
t[5] = t[3];
t[3] = x;
x = t[4];
t[4] = t[1];
t[1] = x;
x = t[8];
t[8] = t[8 - a];
t[8 - a] = x;
gaddz(ar[4], gadd(mt[t[8]][t[9]], mt[t[9]][t[8]]), ar[3]);
gaddz(ar[3], gadd(mt[t[6]][t[7]], mt[t[7]][t[6]]), ar[2]);
gaddz(ar[2], gadd(mt[t[4]][t[5]], mt[t[5]][t[4]]), ar[1]);
break;
default:
y--;
x = t[0];
t[0] = t[2];
t[2] = t[1];
t[1] = x;
for (k = 4; k < y; k += 2)
{
int j;
x = t[k];
for (j = k; j > 0; j--)
t[j] = t[j - 1];
t[0] = x;
}
x = t[y];
t[y] = t[y - a];
t[y - a] = x;
for (k = y; k > 2; k -= 2)
gaddz(ar[k >> 1], gadd(mt[t[k]][t[k + 1]], mt[t[k + 1]][t[k]]), ar[(k >> 1) - 1]);
}
}
g = gadd(ar[1], gadd(gadd(mt[t[0]][t[1]], mt[t[1]][t[0]]),
gadd(mt[t[2]][t[3]], mt[t[3]][t[2]])));
if (padicisint(g, td))
{
for (k = 0; k < n; k += 2)
{
pft[t[k]] = t[k + 1];
pft[t[k + 1]] = t[k];
}
if (verifietest(pft, td))
break;
else
hop++;
}
avma = av2;
}
if (i == N)
{
avma = ltop;
if (DEBUGLEVEL >= 1 && hop)
fprintferr("A4GaloisConj: %d hop sur %d iterations\n", hop, N);
return gzero;
}
if (DEBUGLEVEL >= 1 && hop)
fprintferr("A4GaloisConj: %d hop sur %d iterations\n", hop, N);
N = itos(gdiv(mpfact(n >> 1), mpfact(n >> 2))) >> 1;
avma = av2;
if (DEBUGLEVEL >= 4)
fprintferr("A4GaloisConj:sigma=%Z \n", pft);
for (i = 0; i < N; i++)
{
GEN g;
int a, x, y;
if (i == 0)
{
for (k = 0; k < n; k += 4)
{
u[k + 3] = t[k + 3];
u[k + 2] = t[k + 1];
u[k + 1] = t[k + 2];
u[k] = t[k];
}
} else
{
x = i;
y = -2;
do
{
hiremainder = 0;
y += 4;
x = divll(x, y);
a = hiremainder;
} while (!a);
x = u[2];
u[2] = u[0];
u[0] = x;
switch (y)
{
case 2:
break;
case 6:
x = u[4];
u[4] = u[6];
u[6] = x;
if (a % 2 == 0)
{
a = 4 - a / 2;
x = u[6];
u[6] = u[a];
u[a] = x;
x = u[4];
u[4] = u[a - 2];
u[a - 2] = x;
}
break;
case 10:
x = u[6];
u[6] = u[3];
u[3] = u[2];
u[2] = u[4];
u[4] = u[1];
u[1] = u[0];
u[0] = x;
if (a >= 3)
a += 2;
a = 8 - a;
x = u[10];
u[10] = u[a];
u[a] = x;
x = u[8];
u[8] = u[a - 2];
u[a - 2] = x;
break;
}
}
g = gzero;
for (k = 0; k < n; k += 2)
g = gadd(g, gadd(mt[u[k]][u[k + 1]], mt[u[k + 1]][u[k]]));
if (padicisint(g, td))
{
for (k = 0; k < n; k += 2)
{
pfu[u[k]] = u[k + 1];
pfu[u[k + 1]] = u[k];
}
if (verifietest(pfu, td))
break;
else
hop++;
}
avma = av2;
}
if (i == N)
{
avma = ltop;
return gzero;
}
if (DEBUGLEVEL >= 1 && hop)
fprintferr("A4GaloisConj: %d hop sur %d iterations\n", hop, N);
if (DEBUGLEVEL >= 4)
fprintferr("A4GaloisConj:tau=%Z \n", u);
avma = av2;
orb = cgetg(3, t_VEC);
orb[1] = (long) pft;
orb[2] = (long) pfu;
if (DEBUGLEVEL >= 4)
fprintferr("A4GaloisConj:orb=%Z \n", orb);
O = vecpermorbite(orb);
if (DEBUGLEVEL >= 4)
fprintferr("A4GaloisConj:O=%Z \n", O);
av2 = avma;
for (j = 0; j < 2; j++)
{
pfv[((long **) O)[1][1]] = ((long **) O)[2][1];
pfv[((long **) O)[1][2]] = ((long **) O)[2][3 + j];
pfv[((long **) O)[1][3]] = ((long **) O)[2][4 - (j << 1)];
pfv[((long **) O)[1][4]] = ((long **) O)[2][2 + j];
for (i = 0; i < 4; i++)
{
long x;
GEN g;
switch (i)
{
case 0:
break;
case 1:
x = ((long **) O)[3][1];
((long **) O)[3][1] = ((long **) O)[3][2];
((long **) O)[3][2] = x;
x = ((long **) O)[3][3];
((long **) O)[3][3] = ((long **) O)[3][4];
((long **) O)[3][4] = x;
break;
case 2:
x = ((long **) O)[3][1];
((long **) O)[3][1] = ((long **) O)[3][4];
((long **) O)[3][4] = x;
x = ((long **) O)[3][2];
((long **) O)[3][2] = ((long **) O)[3][3];
((long **) O)[3][3] = x;
break;
case 3:
x = ((long **) O)[3][1];
((long **) O)[3][1] = ((long **) O)[3][2];
((long **) O)[3][2] = x;
x = ((long **) O)[3][3];
((long **) O)[3][3] = ((long **) O)[3][4];
((long **) O)[3][4] = x;
}
pfv[((long **) O)[2][1]] = ((long **) O)[3][1];
pfv[((long **) O)[2][3 + j]] = ((long **) O)[3][4 - j];
pfv[((long **) O)[2][4 - (j << 1)]] = ((long **) O)[3][2 + (j << 1)];
pfv[((long **) O)[2][2 + j]] = ((long **) O)[3][3 - j];
pfv[((long **) O)[3][1]] = ((long **) O)[1][1];
pfv[((long **) O)[3][4 - j]] = ((long **) O)[1][2];
pfv[((long **) O)[3][2 + (j << 1)]] = ((long **) O)[1][3];
pfv[((long **) O)[3][3 - j]] = ((long **) O)[1][4];
g = gzero;
for (k = 1; k <= n; k++)
g = gadd(g, mt[k][pfv[k]]);
if (padicisint(g, td) && verifietest(pfv, td))
{
avma = av;
if (DEBUGLEVEL >= 1)
fprintferr("A4GaloisConj:%d hop sur %d iterations max\n", hop, 10395 + 68);
return res;
} else
hop++;
avma = av2;
}
}
/* Echec? */
avma = ltop;
return gzero;
}
/* Groupe S4 */
GEN
Fpisom(GEN p, GEN T1, GEN T2)
{
ulong ltop = avma, lbot;
GEN T, res;
long v;
if (T1 == T2)
return gmodulcp(polx[varn(T1)], T1);
v = varn(T2);
setvarn(T2, MAXVARN);
T = (GEN) factmod9(T1, p, T2)[1];
setvarn(T2, v);
lbot = avma;
res = gneg(((GEN **) T)[1][2]);
setvarn(res[1], v);
setvarn(res[2], v);
return gerepile(ltop, lbot, res);
}
GEN
Fpinvisom(GEN S)
{
ulong ltop = avma, lbot;
GEN M, U, V;
int n, i, j;
long x;
x = varn(S[1]);
U = gmodulcp(polun[x], (GEN) S[1]);
n = degree((GEN) S[1]);
M = cgetg(n + 1, t_MAT);
for (i = 1; i <= n; i++)
{
int d;
if (i > 1)
U = gmul(U, S);
M[i] = lgetg(n + 1, t_COL);
d = degree((GEN) U[2]);
for (j = 1; j <= d + 1; j++)
((GEN *) M)[i][j] = ((GEN *) U)[2][1 + j];
for (j = d + 2; j <= n; j++)
((GEN *) M)[i][j] = zero;
}
V = cgetg(n + 1, t_COL);
for (i = 1; i <= n; i++)
V[i] = zero;
V[2] = un;
V = gauss(M, V);
lbot = avma;
V = gtopolyrev(V, x);
return gerepile(ltop, lbot, V);
}
static void
makelift(GEN u, struct galois_lift * gl, GEN liftpow)
{
int i;
liftpow[1] = (long) automorphismlift(u, gl);
for (i = 2; i < lg(liftpow); i++)
liftpow[i] = lmul((GEN) liftpow[i - 1], (GEN) liftpow[1]);
}
static long
s4test(GEN u, GEN liftpow, struct galois_lift * gl, GEN phi)
{
GEN res;
int i;
if (DEBUGLEVEL >= 6)
timer2();
u = (GEN) u[2];
res = (GEN) u[2];
for (i = 1; i < lgef(u) - 2; i++)
res = gadd(res, gmul((GEN) liftpow[i], (GEN) u[i + 2]));
res = gdiv(centerlift(gmul((GEN) res[2], gl->den)), gl->den);
if (DEBUGLEVEL >= 6)
msgtimer("s4test()");
return poltopermtest(res, gl->L, phi);
}
GEN
s4galoisgen(struct galois_lift * gl)
{
struct galois_testlift gt;
ulong ltop = avma, av, ltop2;
GEN Tmod, isom, isominv, misom;
int i, j;
GEN sg;
GEN sigma, tau, phi;
GEN res, ry;
GEN pj;
GEN p;
GEN bezoutcoeff, pauto, liftpow;
long v;
p = gl->p;
v = varn(gl->T);
res = cgetg(5, t_VEC);
ry = cgetg(3, t_VEC);
res[1] = (long) ry;
ry[1] = lgetg(lg(gl->L), t_VECSMALL);
ry[2] = (long) stoi(2);
ry = cgetg(3, t_VEC);
res[2] = (long) ry;
ry[1] = lgetg(lg(gl->L), t_VECSMALL);
ry[2] = (long) stoi(2);
ry = cgetg(3, t_VEC);
res[3] = (long) ry;
ry[1] = lgetg(lg(gl->L), t_VECSMALL);
ry[2] = (long) stoi(3);
ry = cgetg(3, t_VEC);
res[4] = (long) ry;
ry[1] = lgetg(lg(gl->L), t_VECSMALL);
ry[2] = (long) stoi(2);
ltop2 = avma;
sg = cgetg(7, t_VECSMALL);
pj = cgetg(7, t_VECSMALL);
sigma = cgetg(lg(gl->L), t_VECSMALL);
tau = cgetg(lg(gl->L), t_VECSMALL);
phi = cgetg(lg(gl->L), t_VECSMALL);
for (i = 1; i < lg(sg); i++)
sg[i] = i;
Tmod = (GEN) factmod(gl->T, p)[1];
isom = cgetg(lg(Tmod), t_VEC);
isominv = cgetg(lg(Tmod), t_VEC);
misom = cgetg(lg(Tmod), t_MAT);
inittestlift(Tmod, 1, gl, >, NULL);
bezoutcoeff = gt.bezoutcoeff;
pauto = gt.pauto;
for (i = 1; i < lg(pj); i++)
pj[i] = 0;
for (i = 1; i < lg(isom); i++)
{
misom[i] = lgetg(lg(Tmod), t_COL);
isom[i] = (long) Fpisom(p, (GEN) Tmod[1], (GEN) Tmod[i]);
if (DEBUGLEVEL >= 4)
fprintferr("S4GaloisConj:Computing isomorphisms %d:%Z\n", i, (GEN) isom[i]);
isominv[i] = (long) lift(Fpinvisom((GEN) isom[i]));
}
for (i = 1; i < lg(isom); i++)
for (j = 1; j < lg(isom); j++)
((GEN **) misom)[i][j] = gsubst((GEN) isominv[i], v, (GEN) isom[j]);
liftpow = cgetg(24, t_VEC);
av = avma;
for (i = 0; i < 3; i++)
{
ulong av2;
GEN u;
int j1, j2, j3;
ulong avm1, avm2;
GEN u1, u2, u3;
if (i)
{
int x;
x = sg[3];
if (i == 1)
{
sg[3] = sg[2];
sg[2] = x;
} else
{
sg[3] = sg[1];
sg[1] = x;
}
}
u = chinois(((GEN **) misom)[sg[1]][sg[2]],
((GEN **) misom)[sg[2]][sg[1]]);
u = chinois(u, ((GEN **) misom)[sg[3]][sg[4]]);
u = chinois(u, ((GEN **) misom)[sg[4]][sg[3]]);
u = chinois(u, ((GEN **) misom)[sg[5]][sg[6]]);
u = chinois(u, ((GEN **) misom)[sg[6]][sg[5]]);
makelift(u, gl, liftpow);
av2 = avma;
for (j1 = 0; j1 < 4; j1++)
{
u1 = gadd(gmul((GEN) bezoutcoeff[sg[5]], (GEN) pauto[1 + j1]),
gmul((GEN) bezoutcoeff[sg[6]], (GEN) pauto[((-j1) & 3) + 1]));
avm1 = avma;
for (j2 = 0; j2 < 4; j2++)
{
u2 = gadd(u1, gmul((GEN) bezoutcoeff[sg[3]], (GEN) pauto[1 + j2]));
u2 = gadd(u2, gmul((GEN) bezoutcoeff[sg[4]], (GEN) pauto[((-j2) & 3) + 1]));
avm2 = avma;
for (j3 = 0; j3 < 4; j3++)
{
u3 = gadd(u2, gmul((GEN) bezoutcoeff[sg[1]], (GEN) pauto[1 + j3]));
u3 = gadd(u3, gmul((GEN) bezoutcoeff[sg[2]], (GEN) pauto[((-j3) & 3) + 1]));
if (DEBUGLEVEL >= 4)
fprintferr("S4GaloisConj:Testing %d/3:%d/4:%d/4:%d/4:%Z\n", i, j1, j2, j3, sg);
if (s4test(u3, liftpow, gl, sigma))
{
pj[1] = j3;
pj[2] = j2, pj[3] = j1;
goto suites4;
}
avma = avm2;
}
avma = avm1;
}
avma = av2;
}
avma = av;
}
avma = ltop;
return gzero;
suites4:
if (DEBUGLEVEL >= 4)
fprintferr("S4GaloisConj:sigma=%Z\n", sigma);
if (DEBUGLEVEL >= 4)
fprintferr("S4GaloisConj:pj=%Z\n", pj);
avma = av;
for (j = 1; j <= 3; j++)
{
ulong av2;
GEN u;
int w, l;
int z;
z = sg[1];
sg[1] = sg[3];
sg[3] = sg[5];
sg[5] = z;
z = sg[2];
sg[2] = sg[4];
sg[4] = sg[6];
sg[6] = z;
z = pj[1];
pj[1] = pj[2];
pj[2] = pj[3];
pj[3] = z;
for (l = 0; l < 2; l++)
{
u = chinois(((GEN **) misom)[sg[1]][sg[3]],
((GEN **) misom)[sg[3]][sg[1]]);
u = chinois(u, ((GEN **) misom)[sg[2]][sg[4]]);
u = chinois(u, ((GEN **) misom)[sg[4]][sg[2]]);
u = chinois(u, ((GEN **) misom)[sg[5]][sg[6]]);
u = chinois(u, ((GEN **) misom)[sg[6]][sg[5]]);
makelift(u, gl, liftpow);
av2 = avma;
for (w = 0; w < 4; w += 2)
{
GEN uu;
long av3;
pj[6] = (w + pj[3]) & 3;
uu = gadd(gmul((GEN) bezoutcoeff[sg[5]], (GEN) pauto[(pj[6] & 3) + 1]),
gmul((GEN) bezoutcoeff[sg[6]], (GEN) pauto[((-pj[6]) & 3) + 1]));
av3 = avma;
for (i = 0; i < 4; i++)
{
GEN u;
pj[4] = i;
pj[5] = (i + pj[2] - pj[1]) & 3;
if (DEBUGLEVEL >= 4)
fprintferr("S4GaloisConj:Testing %d/3:%d/2:%d/2:%d/4:%Z:%Z\n", j - 1, w >> 1, l, i, sg, pj);
u = gadd(uu, gmul((GEN) pauto[(pj[4] & 3) + 1], (GEN) bezoutcoeff[sg[1]]));
u = gadd(u, gmul((GEN) pauto[((-pj[4]) & 3) + 1], (GEN) bezoutcoeff[sg[3]]));
u = gadd(u, gmul((GEN) pauto[(pj[5] & 3) + 1], (GEN) bezoutcoeff[sg[2]]));
u = gadd(u, gmul((GEN) pauto[((-pj[5]) & 3) + 1], (GEN) bezoutcoeff[sg[4]]));
if (s4test(u, liftpow, gl, tau))
goto suites4_2;
avma = av3;
}
avma = av2;
}
z = sg[4];
sg[4] = sg[3];
sg[3] = z;
pj[2] = (-pj[2]) & 3;
avma = av;
}
}
avma = ltop;
return gzero;
suites4_2:
avma = av;
{
int abc, abcdef;
GEN u;
ulong av2;
abc = (pj[1] + pj[2] + pj[3]) & 3;
abcdef = (((abc + pj[4] + pj[5] - pj[6]) & 3) >> 1);
u = chinois(((GEN **) misom)[sg[1]][sg[4]],
((GEN **) misom)[sg[4]][sg[1]]);
u = chinois(u, ((GEN **) misom)[sg[2]][sg[5]]);
u = chinois(u, ((GEN **) misom)[sg[5]][sg[2]]);
u = chinois(u, ((GEN **) misom)[sg[3]][sg[6]]);
u = chinois(u, ((GEN **) misom)[sg[6]][sg[3]]);
makelift(u, gl, liftpow);
av2 = avma;
for (j = 0; j < 8; j++)
{
int h, g, i;
h = j & 3;
g = abcdef + ((j & 4) >> 1);
i = h + abc - g;
u = gmul((GEN) pauto[(g & 3) + 1], (GEN) bezoutcoeff[sg[1]]);
u = gadd(u, gmul((GEN) pauto[((-g) & 3) + 1], (GEN) bezoutcoeff[sg[4]]));
u = gadd(u, gmul((GEN) pauto[(h & 3) + 1], (GEN) bezoutcoeff[sg[2]]));
u = gadd(u, gmul((GEN) pauto[((-h) & 3) + 1], (GEN) bezoutcoeff[sg[5]]));
u = gadd(u, gmul((GEN) pauto[(i & 3) + 1], (GEN) bezoutcoeff[sg[3]]));
u = gadd(u, gmul((GEN) pauto[((-i) & 3) + 1], (GEN) bezoutcoeff[sg[6]]));
if (DEBUGLEVEL >= 4)
fprintferr("S4GaloisConj:Testing %d/8 %d:%d:%d\n", j, g & 3, h & 3, i & 3);
if (s4test(u, liftpow, gl, phi))
break;
avma = av2;
}
}
if (j == 8)
{
avma = ltop;
return gzero;
}
for (i = 1; i < lg(gl->L); i++)
{
((GEN **) res)[1][1][i] = sigma[tau[i]];
((GEN **) res)[2][1][i] = phi[sigma[tau[phi[i]]]];
((GEN **) res)[3][1][i] = phi[sigma[i]];
((GEN **) res)[4][1][i] = sigma[i];
}
avma = ltop2;
return res;
}
GEN
galoisgen(GEN T, GEN L, GEN M, GEN den, struct galois_borne * gb, const struct galois_analysis * ga)
{
struct galois_analysis Pga;
struct galois_borne Pgb;
struct galois_test td;
struct galois_testlift gt;
struct galois_lift gl;
ulong ltop = avma, lbot;
long n, p, deg, ex;
byteptr primepointer;
long sg, Pm = 0, fp;
long x = varn(T);
int i, j;
GEN Tmod, res, pf = gzero, split, psi, ip, mod, ppsi;
GEN frob;
GEN O;
GEN P, PG, PL, Pden, PM, Pmod, Pp;
GEN *lo; /* tired of casting */
n = degree(T);
if (!ga->deg)
return gzero;
p = ga->p;
ex = ga->exception;
deg = ga->deg;
primepointer = ga->primepointer;
if (DEBUGLEVEL >= 9)
fprintferr("GaloisConj:denominator:%Z\n", den);
if (n == 12 && ga->ord == 3) /* A4 is very probable,so test it first */
{
long av = avma;
if (DEBUGLEVEL >= 4)
fprintferr("GaloisConj:Testing A4 first\n");
inittest(L, M, gb->bornesol, gb->ladicsol, &td);
lbot = avma;
PG = a4galoisgen(T, &td);
freetest(&td);
if (PG != gzero)
{
return gerepile(ltop, lbot, PG);
}
avma = av;
}
if (n == 24 && ga->ord == 3) /* S4 is very probable,so test it first */
{
long av = avma;
if (DEBUGLEVEL >= 4)
fprintferr("GaloisConj:Testing S4 first\n");
lbot = avma;
initlift(T, den, stoi(ga->p4), gb->bornesol, L, &gl);
PG = s4galoisgen(&gl);
if (PG != gzero)
{
return gerepile(ltop, lbot, PG);
}
avma = av;
}
frob = cgetg(lg(L), t_VECSMALL);
for (;;)
{
ulong av = avma;
long isram;
long c;
ip = stoi(p);
Tmod = (GEN) factmod(T, ip);
isram = 0;
for (i = 1; i < lg(Tmod[2]) && !isram; i++)
if (!gcmp1(((GEN **) Tmod)[2][i]))
isram = 1;
if (isram == 0)
{
fp = degree(((GEN **) Tmod)[1][1]);
for (i = 2; i < lg(Tmod[1]); i++)
if (degree(((GEN **) Tmod)[1][i]) != fp)
{
avma = ltop;
return gzero; /* Not Galois polynomial */
}
if (fp % deg == 0)
{
if (DEBUGLEVEL >= 4)
fprintferr("Galoisconj:p=%d deg=%d fp=%d\n", p, deg, fp);
lo = (GEN *) listsousgroupes(deg, n / fp);
initlift(T, den, ip, gb->bornesol, L, &gl);
if (inittestlift((GEN) Tmod[1], fp / deg, &gl, >, frob))
{
int k;
sg = lg(lo) - 1;
psi = cgetg(gt.g + 1, t_VECSMALL);
for (k = 1; k <= gt.g; k++)
psi[k] = 1;
goto suite;
}
if (DEBUGLEVEL >= 4)
fprintferr("Galoisconj:Subgroups list:%Z\n", (GEN) lo);
if (deg == fp && cgcd(deg, n / deg) == 1) /* Pretty sure it's the
* biggest ? */
{
for (sg = 1; sg < lg(lo) - 1; sg++)
if (frobeniusliftall(lo[sg], &psi, &gl, >, frob))
goto suite;
} else
{
for (sg = lg(lo) - 2; sg >= 1; sg--) /* else start with the
* fastest! */
if (frobeniusliftall(lo[sg], &psi, &gl, >, frob))
goto suite;
}
if (ex == 1 && (n == 12 || n % 12 != 0))
{
avma = ltop;
return gzero;
} else
{
ex--;
if (n % 12 == 0)
{
if (n % 36 == 0)
deg = 5 - deg;
else
deg = 2; /* For group like Z/2ZxA4 */
}
if (n % 12 == 0 && ex == -5)
err(warner, "galoisconj _may_ hang up for this polynomial");
}
}
}
c = *primepointer++;
if (!c)
err(primer1);
p += c;
if (DEBUGLEVEL >= 4)
fprintferr("GaloisConj:next p=%d\n", p);
avma = av;
}
suite: /* Djikstra probably hates me. (Linus
* Torvalds linux/kernel/sched.c) */
if (deg == n) /* Cyclique */
{
lbot = avma;
res = cgetg(2, t_VEC);
res[1] = lgetg(3, t_VEC);
((GEN **) res)[1][1] = gcopy(frob);
((GEN **) res)[1][2] = stoi(deg);
return gerepile(ltop, lbot, res);
}
if (DEBUGLEVEL >= 9)
fprintferr("GaloisConj:Frobenius:%Z\n", frob);
O = permtocycle(frob);
if (DEBUGLEVEL >= 9)
fprintferr("GaloisConj:Orbite:%Z\n", O);
{
GEN S, Tp, Fi, Sp;
long gp = n / fp;
ppsi = cgetg(gp + 1, t_VECSMALL);
mod = gmodulcp(gun, ip);
P = corpsfixeorbitemod(L, O, x, mod, gb->l, &PL);
S = corpsfixeinclusion(O, PL);
S = vectopol(S, L, M, den, x);
if (DEBUGLEVEL >= 6)
fprintferr("GaloisConj:Inclusion:%Z\n", S);
Pmod = (GEN) factmod(P, ip)[1];
Tp = gmul(T, mod);
Sp = gmul(S, mod);
Pp = gmul(P, mod);
if (DEBUGLEVEL >= 4)
fprintferr("GaloisConj:psi=%Z\n", psi);
if (DEBUGLEVEL >= 4)
fprintferr("GaloisConj:Pmod=%Z\n", Pmod);
if (DEBUGLEVEL >= 4)
fprintferr("GaloisConj:Tmod=%Z\n", Tmod);
for (i = 1; i <= gp; i++)
{
Fi = ggcd(Tp, gsubst((GEN) Pmod[i], x, Sp));
Fi = gdiv(Fi, (GEN) Fi[lgef(Fi) - 1]);
if (DEBUGLEVEL >= 6)
fprintferr("GaloisConj:Fi=%Z %d", Fi, i);
for (j = 1; j <= gp; j++)
if (gegal(Fi, ((GEN **) Tmod)[1][j]))
break;
if (DEBUGLEVEL >= 6)
fprintferr("-->%d\n", j);
if (j == gp + 1)
{
avma = ltop;
return gzero;
}
if (j == gp)
{
Pm = i;
ppsi[i] = 1;
} else
ppsi[i] = psi[j];
}
if (DEBUGLEVEL >= 4)
fprintferr("GaloisConj:Pm=%d ppsi=%Z\n", Pm, ppsi);
galoisanalysis(P, &Pga, 0);
if (Pga.deg == 0)
{
avma = ltop;
return gzero; /* Avoid computing the discriminant */
}
Pden = gabs(mycoredisc(discsr(P)), DEFAULTPREC);
Pgb.l = gb->l;
initborne(P, Pden, &Pgb, Pga.ppp);
if (Pgb.valabs > gb->valabs)
PL = recalculeL(P, deriv(P, x), PL, gb, &Pgb);
PM = vandermondeinverse(PL, P, Pden);
PG = galoisgen(P, PL, PM, Pden, &Pgb, &Pga);
}
if (DEBUGLEVEL >= 4)
fprintferr("GaloisConj:Retour sur Terre:%Z\n", PG);
if (PG == gzero)
{
avma = ltop;
return gzero;
}
inittest(L, M, gb->bornesol, gb->ladicsol, &td);
split = splitorbite(O);
lbot = avma;
res = cgetg(lg(PG) + lg(split) - 1, t_VEC);
for (i = 1; i < lg(split); i++)
res[i] = lcopy((GEN) split[i]);
for (j = 1; j < lg(PG); j++)
{
ulong lbot = 0, av = avma;
GEN B, tau;
long t, g;
long w, sr, dss;
if (DEBUGLEVEL >= 6)
fprintferr("GaloisConj:G[%d][1]=%Z\n", j, ((GEN **) PG)[j][1]);
B = permtocycle(((GEN **) PG)[j][1]);
if (DEBUGLEVEL >= 6)
fprintferr("GaloisConj:B=%Z\n", B);
tau = gmul(mod, permtopol(((GEN **) PG)[j][1], PL, PM, Pden, x));
tau = gsubst((GEN) Pmod[Pm], x, tau);
tau = ggcd(Pp, tau);
tau = gdiv(tau, (GEN) tau[lgef(tau) - 1]);
if (DEBUGLEVEL >= 6)
fprintferr("GaloisConj:tau=%Z\n", tau);
for (g = 1; g < lg(Pmod); g++)
if (gegal(tau, (GEN) Pmod[g]))
break;
if (g == lg(Pmod))
{
freetest(&td);
avma = ltop;
return gzero;
}
w = ((long **) lo)[sg][ppsi[g]];
dss = deg / cgcd(deg, w - 1);
sr = 1;
for (i = 1; i < lg(B[1]) - 1; i++)
sr = (1 + sr * w) % deg;
sr = cgcd(sr, deg);
if (DEBUGLEVEL >= 6)
fprintferr("GaloisConj:w=%d [%d] sr=%d dss=%d\n", w, deg, sr, dss);
for (t = 0; t < sr; t += dss)
{
lbot = avma;
pf = testpermutation(O, B, w, t, sr, &td);
if (pf != gzero)
break;
}
if (pf == gzero)
{
freetest(&td);
avma = ltop;
return gzero;
} else
{
GEN f;
f = cgetg(3, t_VEC);
f[1] = (long) pf;
f[2] = (long) gcopy(((GEN **) PG)[j][2]);
res[lg(split) + j - 1] = (long) gerepile(av, lbot, f);
}
}
if (DEBUGLEVEL >= 4)
fprintferr("GaloisConj:Fini!\n");
freetest(&td);
return gerepile(ltop, lbot, res);
}
/*
* T: polynome ou nf den optionnel: si présent doit etre un multiple du
* dénominateur commun des solutions Si T est un nf et den n'est pas présent,
* le denominateur de la base d'entiers est pris pour den
*/
GEN
galoisconj4(GEN T, GEN den, long flag)
{
ulong ltop = avma, lbot;
GEN G, L, M, res, aut, L2, M2, grp;
struct galois_analysis ga;
struct galois_borne gb;
int n, i, j, k;
if (typ(T) != t_POL)
{
T = checknf(T);
if (!den)
den = gcoeff((GEN) T[8], degree((GEN) T[1]), degree((GEN) T[1]));
T = (GEN) T[1];
}
n = lgef(T) - 3;
if (n <= 0)
err(constpoler, "galoisconj4");
for (k = 2; k <= n + 2; k++)
if (typ(T[k]) != t_INT)
err(talker, "polynomial not in Z[X] in galoisconj4");
if (!gcmp1((GEN) T[n + 2]))
err(talker, "non-monic polynomial in galoisconj4");
n = degree(T);
if (n == 1) /* Too easy! */
{
res = cgetg(2, t_COL);
res[1] = (long) polx[varn(T)];
return res;
}
galoisanalysis(T, &ga, 1);
if (ga.deg == 0)
{
avma = ltop;
return stoi(ga.p); /* Avoid computing the discriminant */
}
if (!den)
den = absi(mycoredisc(discsr(T)));
else
{
if (typ(den) != t_INT)
err(talker, "Second arg. must be integer in galoisconj4");
den = absi(den);
}
gb.l = stoi(ga.l);
initborne(T, den, &gb, ga.ppp);
if (DEBUGLEVEL >= 1)
timer2();
{
GEN f = rootpadic(T, gb.l, gb.valabs);
GEN _p = gmael(f, 1, 2);
L = gmul(gtrunc(f), gmodulcp(gun, gb.ladicabs));
gunclone(_p);
}
if (DEBUGLEVEL >= 1)
msgtimer("rootpadic()");
M = vandermondeinverse(L, T, den);
G = galoisgen(T, L, M, den, &gb, &ga);
if (DEBUGLEVEL >= 6)
fprintferr("GaloisConj:%Z\n", G);
if (G == gzero)
{
avma = ltop;
return gzero;
}
if (DEBUGLEVEL >= 1)
timer2();
L2 = gmul(L, gmodulcp(gun, gb.ladicsol));
M2 = gmul(M, gmodulcp(gun, gb.ladicsol));
if (flag)
{
lbot = avma;
grp = cgetg(7, t_VEC);
grp[1] = (long) gcopy(T);
grp[2] = (long) stoi(ga.l);
grp[3] = (long) gcopy(L);
grp[4] = (long) gcopy(M);
grp[5] = (long) gcopy(den);
}
res = cgetg(n + 1, t_VEC);
res[1] = (long) permidentity(n);
k = 1;
for (i = 1; i < lg(G); i++)
{
int c = k * (itos(((GEN **) G)[i][2]) - 1);
for (j = 1; j <= c; j++) /* I like it */
res[++k] = (long) applyperm((GEN) res[j], ((GEN **) G)[i][1]);
}
if (flag)
{
grp[6] = (long) res;
return gerepile(ltop, lbot, grp);
}
aut = cgetg(n + 1, t_COL);
for (i = 1; i <= n; i++)
aut[i] = (long) permtopol((GEN) res[i], L2, M2, den, varn(T));
if (DEBUGLEVEL >= 1)
msgtimer("Calcul polynomes");
return gerepileupto(ltop, aut);
}
/* Calcule le nombre d'automorphisme de T avec forte probabilité */
/* pdepart premier nombre premier a tester */
long
numberofconjugates(GEN T, long pdepart)
{
ulong ltop = avma, ltop2;
long n, p, nbmax, nbtest;
long card;
byteptr primepointer;
int i;
GEN L;
n = degree(T);
card = sturm(T);
card = cgcd(card, n - card);
nbmax = n + 1;
nbtest = 0;
L = cgetg(n + 1, t_VECSMALL);
ltop2 = avma;
for (p = 0, primepointer = diffptr; nbtest < nbmax && card > 1;)
{
long s, c;
long isram;
GEN S;
c = *primepointer++;
if (!c)
err(primer1);
p += c;
if (p < pdepart)
continue;
S = (GEN) simplefactmod(T, stoi(p));
isram = 0;
for (i = 1; i < lg(S[2]) && !isram; i++)
if (!gcmp1(((GEN **) S)[2][i]))
isram = 1;
if (isram == 0)
{
for (i = 1; i <= n; i++)
L[i] = 0;
for (i = 1; i < lg(S[1]) && !isram; i++)
L[itos(((GEN **) S)[1][i])]++;
s = L[1];
for (i = 2; i <= n; i++)
s = cgcd(s, L[i] * i);
card = cgcd(s, card);
}
if (DEBUGLEVEL >= 6)
fprintferr("NumberOfConjugates:Nbtest=%d,card=%d,p=%d\n", nbtest, card, p);
nbtest++;
avma = ltop2;
}
if (DEBUGLEVEL >= 2)
fprintferr("NumberOfConjugates:card=%d,p=%d\n", card, p);
avma = ltop;
return card;
}
GEN
galoisconj0(GEN nf, long flag, GEN d, long prec)
{
GEN G, T;
long card;
if (typ(nf) != t_POL)
{
nf = checknf(nf);
T = (GEN) nf[1];
} else
T = nf;
switch (flag)
{
case 0:
G = galoisconj4(nf, d, 0);
if (typ(G) != t_INT) /* Success */
return G;
else
{
card = G == gzero ? degree(T) : numberofconjugates(T, itos(G));
if (card != 1)
{
if (typ(nf) == t_POL)
return galoisconj2pol(nf, card, prec);
else
return galoisconj(nf);
}
}
break; /* Failure */
case 1:
return galoisconj(nf);
case 2:
return galoisconj2(nf, degree(T), prec);
case 4:
G = galoisconj4(nf, d, 0);
if (typ(G) != t_INT)
return G;
break; /* Failure */
default:
err(flagerr, "nfgaloisconj");
}
G = cgetg(2, t_COL);
G[1] = (long) polx[varn(T)];
return G; /* Failure */
}
/******************************************************************************/
/* Galois theory related algorithms */
/******************************************************************************/
GEN
checkgal(GEN gal)
{
if (typ(gal) == t_POL)
err(talker, "please apply galoisinit first");
if (typ(gal) != t_VEC || lg(gal) != 7)
err(talker, "Not a Galois field in a Galois related function");
return gal;
}
GEN
galoisinit(GEN nf, GEN den)
{
GEN G;
G = galoisconj4(nf, den, 1);
if (typ(G) == t_INT)
err(talker, "galoisinit: field not Galois or Galois group not weakly super solvable");
return G;
}
GEN
galoispermtopol(GEN gal, GEN perm)
{
gal = checkgal(gal);
if (typ(perm) != t_VEC)
err(typeer, "galoispermtopol:");
return permtopol(perm, (GEN) gal[3], (GEN) gal[4], (GEN) gal[5], varn((GEN) gal[1]));
}
GEN
galoisfixedfield(GEN gal, GEN perm, GEN p)
{
ulong ltop = avma, lbot;
GEN P, S, PL, O, res, mod;
long x;
x = varn((GEN) gal[1]);
gal = checkgal(gal);
if (typ(perm) != t_VEC)
err(typeer, "galoisfixedfield:");
if (p)
{
if (typ(p) != t_INT)
err(talker, "galoisfixedfield: optionnal argument must be an prime integer");
mod = gmodulcp(gun, p);
} else
mod = gun;
O = vecpermorbite(perm);
P = corpsfixeorbitemod((GEN) gal[3], O, x, mod, (GEN) gal[2], &PL);
S = corpsfixeinclusion(O, PL);
S = vectopol(S, (GEN) gal[3], (GEN) gal[4], (GEN) gal[5], x);
lbot = avma;
res = cgetg(3, t_VEC);
res[1] = (long) gcopy(P);
res[2] = (long) gmodulcp(S, (GEN) gal[1]);
return gerepile(ltop, lbot, res);
}