Testing latest pari + WASM + node.js... and it works?! Wow.
License: GPL3
ubuntu2004
/* Copyright (C) 2000 The PARI group.12This file is part of the PARI/GP package.34PARI/GP is free software; you can redistribute it and/or modify it under the5terms of the GNU General Public License as published by the Free Software6Foundation; either version 2 of the License, or (at your option) any later7version. It is distributed in the hope that it will be useful, but WITHOUT8ANY WARRANTY WHATSOEVER.910Check the License for details. You should have received a copy of it, along11with the package; see the file 'COPYING'. If not, write to the Free Software12Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */1314/*******************************************************************/15/* */16/* BASIC NF OPERATIONS */17/* */18/*******************************************************************/19#include "pari.h"20#include "paripriv.h"2122#define DEBUGLEVEL DEBUGLEVEL_nf2324/*******************************************************************/25/* */26/* OPERATIONS OVER NUMBER FIELD ELEMENTS. */27/* represented as column vectors over the integral basis */28/* */29/*******************************************************************/30static GEN31get_tab(GEN nf, long *N)32{33GEN tab = (typ(nf) == t_MAT)? nf: gel(nf,9);34*N = nbrows(tab); return tab;35}3637/* x != 0, y t_INT. Return x * y (not memory clean if x = 1) */38static GEN39_mulii(GEN x, GEN y) {40return is_pm1(x)? (signe(x) < 0)? negi(y): y41: mulii(x, y);42}4344GEN45tablemul_ei_ej(GEN M, long i, long j)46{47long N;48GEN tab = get_tab(M, &N);49tab += (i-1)*N; return gel(tab,j);50}5152/* Outputs x.ei, where ei is the i-th elt of the algebra basis.53* x an RgV of correct length and arbitrary content (polynomials, scalars...).54* M is the multiplication table ei ej = sum_k M_k^(i,j) ek */55GEN56tablemul_ei(GEN M, GEN x, long i)57{58long j, k, N;59GEN v, tab;6061if (i==1) return gcopy(x);62tab = get_tab(M, &N);63if (typ(x) != t_COL) { v = zerocol(N); gel(v,i) = gcopy(x); return v; }64tab += (i-1)*N; v = cgetg(N+1,t_COL);65/* wi . x = [ sum_j tab[k,j] x[j] ]_k */66for (k=1; k<=N; k++)67{68pari_sp av = avma;69GEN s = gen_0;70for (j=1; j<=N; j++)71{72GEN c = gcoeff(tab,k,j);73if (!gequal0(c)) s = gadd(s, gmul(c, gel(x,j)));74}75gel(v,k) = gerepileupto(av,s);76}77return v;78}79/* as tablemul_ei, assume x a ZV of correct length */80GEN81zk_ei_mul(GEN nf, GEN x, long i)82{83long j, k, N;84GEN v, tab;8586if (i==1) return ZC_copy(x);87tab = get_tab(nf, &N); tab += (i-1)*N;88v = cgetg(N+1,t_COL);89for (k=1; k<=N; k++)90{91pari_sp av = avma;92GEN s = gen_0;93for (j=1; j<=N; j++)94{95GEN c = gcoeff(tab,k,j);96if (signe(c)) s = addii(s, _mulii(c, gel(x,j)));97}98gel(v,k) = gerepileuptoint(av, s);99}100return v;101}102103/* table of multiplication by wi in R[w1,..., wN] */104GEN105ei_multable(GEN TAB, long i)106{107long k,N;108GEN m, tab = get_tab(TAB, &N);109tab += (i-1)*N;110m = cgetg(N+1,t_MAT);111for (k=1; k<=N; k++) gel(m,k) = gel(tab,k);112return m;113}114115GEN116zk_multable(GEN nf, GEN x)117{118long i, l = lg(x);119GEN mul = cgetg(l,t_MAT);120gel(mul,1) = x; /* assume w_1 = 1 */121for (i=2; i<l; i++) gel(mul,i) = zk_ei_mul(nf,x,i);122return mul;123}124GEN125multable(GEN M, GEN x)126{127long i, N;128GEN mul;129if (typ(x) == t_MAT) return x;130M = get_tab(M, &N);131if (typ(x) != t_COL) return scalarmat(x, N);132mul = cgetg(N+1,t_MAT);133gel(mul,1) = x; /* assume w_1 = 1 */134for (i=2; i<=N; i++) gel(mul,i) = tablemul_ei(M,x,i);135return mul;136}137138/* x integral in nf; table of multiplication by x in ZK = Z[w1,..., wN].139* Return a t_INT if x is scalar, and a ZM otherwise */140GEN141zk_scalar_or_multable(GEN nf, GEN x)142{143long tx = typ(x);144if (tx == t_MAT || tx == t_INT) return x;145x = nf_to_scalar_or_basis(nf, x);146return (typ(x) == t_COL)? zk_multable(nf, x): x;147}148149GEN150nftrace(GEN nf, GEN x)151{152pari_sp av = avma;153nf = checknf(nf);154x = nf_to_scalar_or_basis(nf, x);155x = (typ(x) == t_COL)? RgV_dotproduct(x, gel(nf_get_Tr(nf),1))156: gmulgs(x, nf_get_degree(nf));157return gerepileupto(av, x);158}159GEN160rnfelttrace(GEN rnf, GEN x)161{162pari_sp av = avma;163checkrnf(rnf);164x = rnfeltabstorel(rnf, x);165x = (typ(x) == t_POLMOD)? rnfeltdown(rnf, gtrace(x))166: gmulgs(x, rnf_get_degree(rnf));167return gerepileupto(av, x);168}169170/* assume nf is a genuine nf, fa a famat */171static GEN172famat_norm(GEN nf, GEN fa)173{174pari_sp av = avma;175GEN g = gel(fa,1), e = gel(fa,2), N = gen_1;176long i, l = lg(g);177for (i = 1; i < l; i++)178N = gmul(N, powgi(nfnorm(nf, gel(g,i)), gel(e,i)));179return gerepileupto(av, N);180}181GEN182nfnorm(GEN nf, GEN x)183{184pari_sp av = avma;185GEN c, den;186long n;187nf = checknf(nf);188n = nf_get_degree(nf);189if (typ(x) == t_MAT) return famat_norm(nf, x);190x = nf_to_scalar_or_basis(nf, x);191if (typ(x)!=t_COL)192return gerepileupto(av, gpowgs(x, n));193x = nf_to_scalar_or_alg(nf, Q_primitive_part(x, &c));194x = Q_remove_denom(x, &den);195x = ZX_resultant_all(nf_get_pol(nf), x, den, 0);196return gerepileupto(av, c ? gmul(x, gpowgs(c, n)): x);197}198199static GEN200to_RgX(GEN P, long vx)201{202return varn(P) == vx ? P: scalarpol_shallow(P, vx);203}204205GEN206rnfeltnorm(GEN rnf, GEN x)207{208pari_sp av = avma;209GEN nf, pol;210long v = rnf_get_varn(rnf);211checkrnf(rnf);212x = liftpol_shallow(rnfeltabstorel(rnf, x));213nf = rnf_get_nf(rnf); pol = rnf_get_pol(rnf);214x = (typ(x) == t_POL)215? rnfeltdown(rnf, nfX_resultant(nf,pol,to_RgX(x,v)))216: gpowgs(x, rnf_get_degree(rnf));217return gerepileupto(av, x);218}219220/* x + y in nf */221GEN222nfadd(GEN nf, GEN x, GEN y)223{224pari_sp av = avma;225GEN z;226227nf = checknf(nf);228x = nf_to_scalar_or_basis(nf, x);229y = nf_to_scalar_or_basis(nf, y);230if (typ(x) != t_COL)231{ z = (typ(y) == t_COL)? RgC_Rg_add(y, x): gadd(x,y); }232else233{ z = (typ(y) == t_COL)? RgC_add(x, y): RgC_Rg_add(x, y); }234return gerepileupto(av, z);235}236/* x - y in nf */237GEN238nfsub(GEN nf, GEN x, GEN y)239{240pari_sp av = avma;241GEN z;242243nf = checknf(nf);244x = nf_to_scalar_or_basis(nf, x);245y = nf_to_scalar_or_basis(nf, y);246if (typ(x) != t_COL)247{ z = (typ(y) == t_COL)? Rg_RgC_sub(x,y): gsub(x,y); }248else249{ z = (typ(y) == t_COL)? RgC_sub(x,y): RgC_Rg_sub(x,y); }250return gerepileupto(av, z);251}252253/* product of ZC x,y in nf; ( sum_i x_i sum_j y_j m^{i,j}_k )_k */254static GEN255nfmuli_ZC(GEN nf, GEN x, GEN y)256{257long i, j, k, N;258GEN TAB = get_tab(nf, &N), v = cgetg(N+1,t_COL);259260for (k = 1; k <= N; k++)261{262pari_sp av = avma;263GEN s, TABi = TAB;264if (k == 1)265s = mulii(gel(x,1),gel(y,1));266else267s = addii(mulii(gel(x,1),gel(y,k)),268mulii(gel(x,k),gel(y,1)));269for (i=2; i<=N; i++)270{271GEN t, xi = gel(x,i);272TABi += N;273if (!signe(xi)) continue;274275t = NULL;276for (j=2; j<=N; j++)277{278GEN p1, c = gcoeff(TABi, k, j); /* m^{i,j}_k */279if (!signe(c)) continue;280p1 = _mulii(c, gel(y,j));281t = t? addii(t, p1): p1;282}283if (t) s = addii(s, mulii(xi, t));284}285gel(v,k) = gerepileuptoint(av,s);286}287return v;288}289static int290is_famat(GEN x) { return typ(x) == t_MAT && lg(x) == 3; }291/* product of x and y in nf */292GEN293nfmul(GEN nf, GEN x, GEN y)294{295GEN z;296pari_sp av = avma;297298if (x == y) return nfsqr(nf,x);299300nf = checknf(nf);301if (is_famat(x) || is_famat(y)) return famat_mul(x, y);302x = nf_to_scalar_or_basis(nf, x);303y = nf_to_scalar_or_basis(nf, y);304if (typ(x) != t_COL)305{306if (isintzero(x)) return gen_0;307z = (typ(y) == t_COL)? RgC_Rg_mul(y, x): gmul(x,y); }308else309{310if (typ(y) != t_COL)311{312if (isintzero(y)) return gen_0;313z = RgC_Rg_mul(x, y);314}315else316{317GEN dx, dy;318x = Q_remove_denom(x, &dx);319y = Q_remove_denom(y, &dy);320z = nfmuli_ZC(nf,x,y);321dx = mul_denom(dx,dy);322if (dx) z = ZC_Z_div(z, dx);323}324}325return gerepileupto(av, z);326}327/* square of ZC x in nf */328static GEN329nfsqri_ZC(GEN nf, GEN x)330{331long i, j, k, N;332GEN TAB = get_tab(nf, &N), v = cgetg(N+1,t_COL);333334for (k = 1; k <= N; k++)335{336pari_sp av = avma;337GEN s, TABi = TAB;338if (k == 1)339s = sqri(gel(x,1));340else341s = shifti(mulii(gel(x,1),gel(x,k)), 1);342for (i=2; i<=N; i++)343{344GEN p1, c, t, xi = gel(x,i);345TABi += N;346if (!signe(xi)) continue;347348c = gcoeff(TABi, k, i);349t = signe(c)? _mulii(c,xi): NULL;350for (j=i+1; j<=N; j++)351{352c = gcoeff(TABi, k, j);353if (!signe(c)) continue;354p1 = _mulii(c, shifti(gel(x,j),1));355t = t? addii(t, p1): p1;356}357if (t) s = addii(s, mulii(xi, t));358}359gel(v,k) = gerepileuptoint(av,s);360}361return v;362}363/* square of x in nf */364GEN365nfsqr(GEN nf, GEN x)366{367pari_sp av = avma;368GEN z;369370nf = checknf(nf);371if (is_famat(x)) return famat_sqr(x);372x = nf_to_scalar_or_basis(nf, x);373if (typ(x) != t_COL) z = gsqr(x);374else375{376GEN dx;377x = Q_remove_denom(x, &dx);378z = nfsqri_ZC(nf,x);379if (dx) z = RgC_Rg_div(z, sqri(dx));380}381return gerepileupto(av, z);382}383384/* x a ZC, v a t_COL of ZC/Z */385GEN386zkC_multable_mul(GEN v, GEN x)387{388long i, l = lg(v);389GEN y = cgetg(l, t_COL);390for (i = 1; i < l; i++)391{392GEN c = gel(v,i);393if (typ(c)!=t_COL) {394if (!isintzero(c)) c = ZC_Z_mul(gel(x,1), c);395} else {396c = ZM_ZC_mul(x,c);397if (ZV_isscalar(c)) c = gel(c,1);398}399gel(y,i) = c;400}401return y;402}403404GEN405nfC_multable_mul(GEN v, GEN x)406{407long i, l = lg(v);408GEN y = cgetg(l, t_COL);409for (i = 1; i < l; i++)410{411GEN c = gel(v,i);412if (typ(c)!=t_COL) {413if (!isintzero(c)) c = RgC_Rg_mul(gel(x,1), c);414} else {415c = RgM_RgC_mul(x,c);416if (QV_isscalar(c)) c = gel(c,1);417}418gel(y,i) = c;419}420return y;421}422423GEN424nfC_nf_mul(GEN nf, GEN v, GEN x)425{426long tx;427GEN y;428429x = nf_to_scalar_or_basis(nf, x);430tx = typ(x);431if (tx != t_COL)432{433long l, i;434if (tx == t_INT)435{436long s = signe(x);437if (!s) return zerocol(lg(v)-1);438if (is_pm1(x)) return s > 0? leafcopy(v): RgC_neg(v);439}440l = lg(v); y = cgetg(l, t_COL);441for (i=1; i < l; i++)442{443GEN c = gel(v,i);444if (typ(c) != t_COL) c = gmul(c, x); else c = RgC_Rg_mul(c, x);445gel(y,i) = c;446}447return y;448}449else450{451GEN dx;452x = zk_multable(nf, Q_remove_denom(x,&dx));453y = nfC_multable_mul(v, x);454return dx? RgC_Rg_div(y, dx): y;455}456}457static GEN458mulbytab(GEN M, GEN c)459{ return typ(c) == t_COL? RgM_RgC_mul(M,c): RgC_Rg_mul(gel(M,1), c); }460GEN461tablemulvec(GEN M, GEN x, GEN v)462{463long l, i;464GEN y;465466if (typ(x) == t_COL && RgV_isscalar(x))467{468x = gel(x,1);469return typ(v) == t_POL? RgX_Rg_mul(v,x): RgV_Rg_mul(v,x);470}471x = multable(M, x); /* multiplication table by x */472y = cgetg_copy(v, &l);473if (typ(v) == t_POL)474{475y[1] = v[1];476for (i=2; i < l; i++) gel(y,i) = mulbytab(x, gel(v,i));477y = normalizepol(y);478}479else480{481for (i=1; i < l; i++) gel(y,i) = mulbytab(x, gel(v,i));482}483return y;484}485486GEN487zkmultable_capZ(GEN mx) { return Q_denom(zkmultable_inv(mx)); }488GEN489zkmultable_inv(GEN mx) { return ZM_gauss(mx, col_ei(lg(mx)-1,1)); }490/* nf a true nf, x a ZC */491GEN492zk_inv(GEN nf, GEN x) { return zkmultable_inv(zk_multable(nf,x)); }493494/* inverse of x in nf */495GEN496nfinv(GEN nf, GEN x)497{498pari_sp av = avma;499GEN z;500501nf = checknf(nf);502if (is_famat(x)) return famat_inv(x);503x = nf_to_scalar_or_basis(nf, x);504if (typ(x) == t_COL)505{506GEN d;507x = Q_remove_denom(x, &d);508z = zk_inv(nf, x);509if (d) z = RgC_Rg_mul(z, d);510}511else512z = ginv(x);513return gerepileupto(av, z);514}515516/* quotient of x and y in nf */517GEN518nfdiv(GEN nf, GEN x, GEN y)519{520pari_sp av = avma;521GEN z;522523nf = checknf(nf);524if (is_famat(x) || is_famat(y)) return famat_div(x,y);525y = nf_to_scalar_or_basis(nf, y);526if (typ(y) != t_COL)527{528x = nf_to_scalar_or_basis(nf, x);529z = (typ(x) == t_COL)? RgC_Rg_div(x, y): gdiv(x,y);530}531else532{533GEN d;534y = Q_remove_denom(y, &d);535z = nfmul(nf, x, zk_inv(nf,y));536if (d) z = typ(z) == t_COL? RgC_Rg_mul(z, d): gmul(z, d);537}538return gerepileupto(av, z);539}540541/* product of INTEGERS (t_INT or ZC) x and y in nf */542GEN543nfmuli(GEN nf, GEN x, GEN y)544{545if (typ(x) == t_INT) return (typ(y) == t_COL)? ZC_Z_mul(y, x): mulii(x,y);546if (typ(y) == t_INT) return ZC_Z_mul(x, y);547return nfmuli_ZC(nf, x, y);548}549GEN550nfsqri(GEN nf, GEN x)551{ return (typ(x) == t_INT)? sqri(x): nfsqri_ZC(nf, x); }552553/* both x and y are RgV */554GEN555tablemul(GEN TAB, GEN x, GEN y)556{557long i, j, k, N;558GEN s, v;559if (typ(x) != t_COL) return gmul(x, y);560if (typ(y) != t_COL) return gmul(y, x);561N = lg(x)-1;562v = cgetg(N+1,t_COL);563for (k=1; k<=N; k++)564{565pari_sp av = avma;566GEN TABi = TAB;567if (k == 1)568s = gmul(gel(x,1),gel(y,1));569else570s = gadd(gmul(gel(x,1),gel(y,k)),571gmul(gel(x,k),gel(y,1)));572for (i=2; i<=N; i++)573{574GEN t, xi = gel(x,i);575TABi += N;576if (gequal0(xi)) continue;577578t = NULL;579for (j=2; j<=N; j++)580{581GEN p1, c = gcoeff(TABi, k, j); /* m^{i,j}_k */582if (gequal0(c)) continue;583p1 = gmul(c, gel(y,j));584t = t? gadd(t, p1): p1;585}586if (t) s = gadd(s, gmul(xi, t));587}588gel(v,k) = gerepileupto(av,s);589}590return v;591}592GEN593tablesqr(GEN TAB, GEN x)594{595long i, j, k, N;596GEN s, v;597598if (typ(x) != t_COL) return gsqr(x);599N = lg(x)-1;600v = cgetg(N+1,t_COL);601602for (k=1; k<=N; k++)603{604pari_sp av = avma;605GEN TABi = TAB;606if (k == 1)607s = gsqr(gel(x,1));608else609s = gmul2n(gmul(gel(x,1),gel(x,k)), 1);610for (i=2; i<=N; i++)611{612GEN p1, c, t, xi = gel(x,i);613TABi += N;614if (gequal0(xi)) continue;615616c = gcoeff(TABi, k, i);617t = !gequal0(c)? gmul(c,xi): NULL;618for (j=i+1; j<=N; j++)619{620c = gcoeff(TABi, k, j);621if (gequal0(c)) continue;622p1 = gmul(gmul2n(c,1), gel(x,j));623t = t? gadd(t, p1): p1;624}625if (t) s = gadd(s, gmul(xi, t));626}627gel(v,k) = gerepileupto(av,s);628}629return v;630}631632static GEN633_mul(void *data, GEN x, GEN y) { return nfmuli((GEN)data,x,y); }634static GEN635_sqr(void *data, GEN x) { return nfsqri((GEN)data,x); }636637/* Compute z^n in nf, left-shift binary powering */638GEN639nfpow(GEN nf, GEN z, GEN n)640{641pari_sp av = avma;642long s;643GEN x, cx;644645if (typ(n)!=t_INT) pari_err_TYPE("nfpow",n);646nf = checknf(nf);647s = signe(n); if (!s) return gen_1;648if (is_famat(z)) return famat_pow(z, n);649x = nf_to_scalar_or_basis(nf, z);650if (typ(x) != t_COL) return powgi(x,n);651if (s < 0)652{ /* simplified nfinv */653GEN d;654x = Q_remove_denom(x, &d);655x = zk_inv(nf, x);656x = primitive_part(x, &cx);657cx = mul_content(cx, d);658n = negi(n);659}660else661x = primitive_part(x, &cx);662x = gen_pow_i(x, n, (void*)nf, _sqr, _mul);663if (cx)664x = gerepileupto(av, gmul(x, powgi(cx, n)));665else666x = gerepilecopy(av, x);667return x;668}669/* Compute z^n in nf, left-shift binary powering */670GEN671nfpow_u(GEN nf, GEN z, ulong n)672{673pari_sp av = avma;674GEN x, cx;675676nf = checknf(nf);677if (!n) return gen_1;678x = nf_to_scalar_or_basis(nf, z);679if (typ(x) != t_COL) return gpowgs(x,n);680x = primitive_part(x, &cx);681x = gen_powu_i(x, n, (void*)nf, _sqr, _mul);682if (cx)683{684x = gmul(x, powgi(cx, utoipos(n)));685return gerepileupto(av,x);686}687return gerepilecopy(av, x);688}689690static GEN691_nf_red(void *E, GEN x) { (void)E; return x; }692693static GEN694_nf_add(void *E, GEN x, GEN y) { return nfadd((GEN)E,x,y); }695696static GEN697_nf_neg(void *E, GEN x) { (void)E; return gneg(x); }698699static GEN700_nf_mul(void *E, GEN x, GEN y) { return nfmul((GEN)E,x,y); }701702static GEN703_nf_inv(void *E, GEN x) { return nfinv((GEN)E,x); }704705static GEN706_nf_s(void *E, long x) { (void)E; return stoi(x); }707708static const struct bb_field nf_field={_nf_red,_nf_add,_nf_mul,_nf_neg,709_nf_inv,&gequal0,_nf_s };710711const struct bb_field *get_nf_field(void **E, GEN nf)712{ *E = (void*)nf; return &nf_field; }713714GEN715nfM_det(GEN nf, GEN M)716{717void *E;718const struct bb_field *S = get_nf_field(&E, nf);719return gen_det(M, E, S);720}721GEN722nfM_inv(GEN nf, GEN M)723{724void *E;725const struct bb_field *S = get_nf_field(&E, nf);726return gen_Gauss(M, matid(lg(M)-1), E, S);727}728GEN729nfM_mul(GEN nf, GEN A, GEN B)730{731void *E;732const struct bb_field *S = get_nf_field(&E, nf);733return gen_matmul(A, B, E, S);734}735GEN736nfM_nfC_mul(GEN nf, GEN A, GEN B)737{738void *E;739const struct bb_field *S = get_nf_field(&E, nf);740return gen_matcolmul(A, B, E, S);741}742743/* valuation of integral x (ZV), with resp. to prime ideal pr */744long745ZC_nfvalrem(GEN x, GEN pr, GEN *newx)746{747pari_sp av = avma;748long i, v, l;749GEN r, y, p = pr_get_p(pr), mul = pr_get_tau(pr);750751/* p inert */752if (typ(mul) == t_INT) return newx? ZV_pvalrem(x, p, newx):ZV_pval(x, p);753y = cgetg_copy(x, &l); /* will hold the new x */754x = leafcopy(x);755for(v=0;; v++)756{757for (i=1; i<l; i++)758{ /* is (x.b)[i] divisible by p ? */759gel(y,i) = dvmdii(ZMrow_ZC_mul(mul,x,i),p,&r);760if (r != gen_0) { if (newx) *newx = x; return v; }761}762swap(x, y);763if (!newx && (v & 0xf) == 0xf) v += pr_get_e(pr) * ZV_pvalrem(x, p, &x);764if (gc_needed(av,1))765{766if(DEBUGMEM>1) pari_warn(warnmem,"ZC_nfvalrem, v >= %ld", v);767gerepileall(av, 2, &x, &y);768}769}770}771long772ZC_nfval(GEN x, GEN P)773{ return ZC_nfvalrem(x, P, NULL); }774775/* v_P(x) != 0, x a ZV. Simpler version of ZC_nfvalrem */776int777ZC_prdvd(GEN x, GEN P)778{779pari_sp av = avma;780long i, l;781GEN p = pr_get_p(P), mul = pr_get_tau(P);782if (typ(mul) == t_INT) return ZV_Z_dvd(x, p);783l = lg(x);784for (i=1; i<l; i++)785if (!dvdii(ZMrow_ZC_mul(mul,x,i), p)) return gc_bool(av,0);786return gc_bool(av,1);787}788789int790pr_equal(GEN P, GEN Q)791{792GEN gQ, p = pr_get_p(P);793long e = pr_get_e(P), f = pr_get_f(P), n;794if (!equalii(p, pr_get_p(Q)) || e != pr_get_e(Q) || f != pr_get_f(Q))795return 0;796gQ = pr_get_gen(Q); n = lg(gQ)-1;797if (2*e*f > n) return 1; /* room for only one such pr */798return ZV_equal(pr_get_gen(P), gQ) || ZC_prdvd(gQ, P);799}800801GEN802famat_nfvalrem(GEN nf, GEN x, GEN pr, GEN *py)803{804pari_sp av = avma;805GEN P = gel(x,1), E = gel(x,2), V = gen_0, y = NULL;806long l = lg(P), simplify = 0, i;807if (py) { *py = gen_1; y = cgetg(l, t_COL); }808809for (i = 1; i < l; i++)810{811GEN e = gel(E,i);812long v;813if (!signe(e))814{815if (py) gel(y,i) = gen_1;816simplify = 1; continue;817}818v = nfvalrem(nf, gel(P,i), pr, py? &gel(y,i): NULL);819if (v == LONG_MAX) { set_avma(av); if (py) *py = gen_0; return mkoo(); }820V = addmulii(V, stoi(v), e);821}822if (!py) V = gerepileuptoint(av, V);823else824{825y = mkmat2(y, gel(x,2));826if (simplify) y = famat_remove_trivial(y);827gerepileall(av, 2, &V, &y); *py = y;828}829return V;830}831long832nfval(GEN nf, GEN x, GEN pr)833{834pari_sp av = avma;835long w, e;836GEN cx, p;837838if (gequal0(x)) return LONG_MAX;839nf = checknf(nf);840checkprid(pr);841p = pr_get_p(pr);842e = pr_get_e(pr);843x = nf_to_scalar_or_basis(nf, x);844if (typ(x) != t_COL) return e*Q_pval(x,p);845x = Q_primitive_part(x, &cx);846w = ZC_nfval(x,pr);847if (cx) w += e*Q_pval(cx,p);848return gc_long(av,w);849}850851/* want to write p^v = uniformizer^(e*v) * z^v, z coprime to pr */852/* z := tau^e / p^(e-1), algebraic integer coprime to pr; return z^v */853static GEN854powp(GEN nf, GEN pr, long v)855{856GEN b, z;857long e;858if (!v) return gen_1;859b = pr_get_tau(pr);860if (typ(b) == t_INT) return gen_1;861e = pr_get_e(pr);862z = gel(b,1);863if (e != 1) z = gdiv(nfpow_u(nf, z, e), powiu(pr_get_p(pr),e-1));864if (v < 0) { v = -v; z = nfinv(nf, z); }865if (v != 1) z = nfpow_u(nf, z, v);866return z;867}868long869nfvalrem(GEN nf, GEN x, GEN pr, GEN *py)870{871pari_sp av = avma;872long w, e;873GEN cx, p, t;874875if (!py) return nfval(nf,x,pr);876if (gequal0(x)) { *py = gen_0; return LONG_MAX; }877nf = checknf(nf);878checkprid(pr);879p = pr_get_p(pr);880e = pr_get_e(pr);881x = nf_to_scalar_or_basis(nf, x);882if (typ(x) != t_COL) {883w = Q_pvalrem(x,p, py);884if (!w) { *py = gerepilecopy(av, x); return 0; }885*py = gerepileupto(av, gmul(powp(nf, pr, w), *py));886return e*w;887}888x = Q_primitive_part(x, &cx);889w = ZC_nfvalrem(x,pr, py);890if (cx)891{892long v = Q_pvalrem(cx,p, &t);893*py = nfmul(nf, *py, gmul(powp(nf,pr,v), t));894*py = gerepileupto(av, *py);895w += e*v;896}897else898*py = gerepilecopy(av, *py);899return w;900}901GEN902gpnfvalrem(GEN nf, GEN x, GEN pr, GEN *py)903{904long v;905if (is_famat(x)) return famat_nfvalrem(nf, x, pr, py);906v = nfvalrem(nf,x,pr,py);907return v == LONG_MAX? mkoo(): stoi(v);908}909910/* true nf */911GEN912coltoalg(GEN nf, GEN x)913{914return mkpolmod( nf_to_scalar_or_alg(nf, x), nf_get_pol(nf) );915}916917GEN918basistoalg(GEN nf, GEN x)919{920GEN T;921922nf = checknf(nf);923switch(typ(x))924{925case t_COL: {926pari_sp av = avma;927return gerepilecopy(av, coltoalg(nf, x));928}929case t_POLMOD:930T = nf_get_pol(nf);931if (!RgX_equal_var(T,gel(x,1)))932pari_err_MODULUS("basistoalg", T,gel(x,1));933return gcopy(x);934case t_POL:935T = nf_get_pol(nf);936if (varn(T) != varn(x)) pari_err_VAR("basistoalg",x,T);937retmkpolmod(RgX_rem(x, T), ZX_copy(T));938case t_INT:939case t_FRAC:940T = nf_get_pol(nf);941retmkpolmod(gcopy(x), ZX_copy(T));942default:943pari_err_TYPE("basistoalg",x);944return NULL; /* LCOV_EXCL_LINE */945}946}947948/* true nf, x a t_POL */949static GEN950pol_to_scalar_or_basis(GEN nf, GEN x)951{952GEN T = nf_get_pol(nf);953long l = lg(x);954if (varn(x) != varn(T)) pari_err_VAR("nf_to_scalar_or_basis", x,T);955if (l >= lg(T)) { x = RgX_rem(x, T); l = lg(x); }956if (l == 2) return gen_0;957if (l == 3)958{959x = gel(x,2);960if (!is_rational_t(typ(x))) pari_err_TYPE("nf_to_scalar_or_basis",x);961return x;962}963return poltobasis(nf,x);964}965/* Assume nf is a genuine nf. */966GEN967nf_to_scalar_or_basis(GEN nf, GEN x)968{969switch(typ(x))970{971case t_INT: case t_FRAC:972return x;973case t_POLMOD:974x = checknfelt_mod(nf,x,"nf_to_scalar_or_basis");975switch(typ(x))976{977case t_INT: case t_FRAC: return x;978case t_POL: return pol_to_scalar_or_basis(nf,x);979}980break;981case t_POL: return pol_to_scalar_or_basis(nf,x);982case t_COL:983if (lg(x)-1 != nf_get_degree(nf)) break;984return QV_isscalar(x)? gel(x,1): x;985}986pari_err_TYPE("nf_to_scalar_or_basis",x);987return NULL; /* LCOV_EXCL_LINE */988}989/* Let x be a polynomial with coefficients in Q or nf. Return the same990* polynomial with coefficients expressed as vectors (on the integral basis).991* No consistency checks, not memory-clean. */992GEN993RgX_to_nfX(GEN nf, GEN x)994{995long i, l;996GEN y = cgetg_copy(x, &l); y[1] = x[1];997for (i=2; i<l; i++) gel(y,i) = nf_to_scalar_or_basis(nf, gel(x,i));998return y;999}10001001/* Assume nf is a genuine nf. */1002GEN1003nf_to_scalar_or_alg(GEN nf, GEN x)1004{1005switch(typ(x))1006{1007case t_INT: case t_FRAC:1008return x;1009case t_POLMOD:1010x = checknfelt_mod(nf,x,"nf_to_scalar_or_alg");1011if (typ(x) != t_POL) return x;1012/* fall through */1013case t_POL:1014{1015GEN T = nf_get_pol(nf);1016long l = lg(x);1017if (varn(x) != varn(T)) pari_err_VAR("nf_to_scalar_or_alg", x,T);1018if (l >= lg(T)) { x = RgX_rem(x, T); l = lg(x); }1019if (l == 2) return gen_0;1020if (l == 3) return gel(x,2);1021return x;1022}1023case t_COL:1024{1025GEN dx;1026if (lg(x)-1 != nf_get_degree(nf)) break;1027if (QV_isscalar(x)) return gel(x,1);1028x = Q_remove_denom(x, &dx);1029x = RgV_RgC_mul(nf_get_zkprimpart(nf), x);1030dx = mul_denom(dx, nf_get_zkden(nf));1031return gdiv(x,dx);1032}1033}1034pari_err_TYPE("nf_to_scalar_or_alg",x);1035return NULL; /* LCOV_EXCL_LINE */1036}10371038/* gmul(A, RgX_to_RgC(x)), A t_MAT of compatible dimensions */1039GEN1040RgM_RgX_mul(GEN A, GEN x)1041{1042long i, l = lg(x)-1;1043GEN z;1044if (l == 1) return zerocol(nbrows(A));1045z = gmul(gel(x,2), gel(A,1));1046for (i = 2; i < l; i++)1047if (!gequal0(gel(x,i+1))) z = gadd(z, gmul(gel(x,i+1), gel(A,i)));1048return z;1049}1050GEN1051ZM_ZX_mul(GEN A, GEN x)1052{1053long i, l = lg(x)-1;1054GEN z;1055if (l == 1) return zerocol(nbrows(A));1056z = ZC_Z_mul(gel(A,1), gel(x,2));1057for (i = 2; i < l ; i++)1058if (signe(gel(x,i+1))) z = ZC_add(z, ZC_Z_mul(gel(A,i), gel(x,i+1)));1059return z;1060}1061/* x a t_POL, nf a genuine nf. No garbage collecting. No check. */1062GEN1063poltobasis(GEN nf, GEN x)1064{1065GEN d, T = nf_get_pol(nf);1066if (varn(x) != varn(T)) pari_err_VAR( "poltobasis", x,T);1067if (degpol(x) >= degpol(T)) x = RgX_rem(x,T);1068x = Q_remove_denom(x, &d);1069if (!RgX_is_ZX(x)) pari_err_TYPE("poltobasis",x);1070x = ZM_ZX_mul(nf_get_invzk(nf), x);1071if (d) x = RgC_Rg_div(x, d);1072return x;1073}10741075GEN1076algtobasis(GEN nf, GEN x)1077{1078pari_sp av;10791080nf = checknf(nf);1081switch(typ(x))1082{1083case t_POLMOD:1084if (!RgX_equal_var(nf_get_pol(nf),gel(x,1)))1085pari_err_MODULUS("algtobasis", nf_get_pol(nf),gel(x,1));1086x = gel(x,2);1087switch(typ(x))1088{1089case t_INT:1090case t_FRAC: return scalarcol(x, nf_get_degree(nf));1091case t_POL:1092av = avma;1093return gerepileupto(av,poltobasis(nf,x));1094}1095break;10961097case t_POL:1098av = avma;1099return gerepileupto(av,poltobasis(nf,x));11001101case t_COL:1102if (!RgV_is_QV(x)) pari_err_TYPE("nfalgtobasis",x);1103if (lg(x)-1 != nf_get_degree(nf)) pari_err_DIM("nfalgtobasis");1104return gcopy(x);11051106case t_INT:1107case t_FRAC: return scalarcol(x, nf_get_degree(nf));1108}1109pari_err_TYPE("algtobasis",x);1110return NULL; /* LCOV_EXCL_LINE */1111}11121113GEN1114rnfbasistoalg(GEN rnf,GEN x)1115{1116const char *f = "rnfbasistoalg";1117long lx, i;1118pari_sp av = avma;1119GEN z, nf, R, T;11201121checkrnf(rnf);1122nf = rnf_get_nf(rnf);1123T = nf_get_pol(nf);1124R = QXQX_to_mod_shallow(rnf_get_pol(rnf), T);1125switch(typ(x))1126{1127case t_COL:1128z = cgetg_copy(x, &lx);1129for (i=1; i<lx; i++)1130{1131GEN c = nf_to_scalar_or_alg(nf, gel(x,i));1132if (typ(c) == t_POL) c = mkpolmod(c,T);1133gel(z,i) = c;1134}1135z = RgV_RgC_mul(gel(rnf_get_zk(rnf),1), z);1136return gerepileupto(av, gmodulo(z,R));11371138case t_POLMOD:1139x = polmod_nffix(f, rnf, x, 0);1140if (typ(x) != t_POL) break;1141retmkpolmod(RgX_copy(x), RgX_copy(R));1142case t_POL:1143if (varn(x) == varn(T)) { RgX_check_QX(x,f); x = gmodulo(x,T); break; }1144if (varn(x) == varn(R))1145{1146x = RgX_nffix(f,nf_get_pol(nf),x,0);1147return gmodulo(x, R);1148}1149pari_err_VAR(f, x,R);1150}1151retmkpolmod(scalarpol(x, varn(R)), RgX_copy(R));1152}11531154GEN1155matbasistoalg(GEN nf,GEN x)1156{1157long i, j, li, lx;1158GEN z = cgetg_copy(x, &lx);11591160if (lx == 1) return z;1161switch(typ(x))1162{1163case t_VEC: case t_COL:1164for (i=1; i<lx; i++) gel(z,i) = basistoalg(nf, gel(x,i));1165return z;1166case t_MAT: break;1167default: pari_err_TYPE("matbasistoalg",x);1168}1169li = lgcols(x);1170for (j=1; j<lx; j++)1171{1172GEN c = cgetg(li,t_COL), xj = gel(x,j);1173gel(z,j) = c;1174for (i=1; i<li; i++) gel(c,i) = basistoalg(nf, gel(xj,i));1175}1176return z;1177}11781179GEN1180matalgtobasis(GEN nf,GEN x)1181{1182long i, j, li, lx;1183GEN z = cgetg_copy(x, &lx);11841185if (lx == 1) return z;1186switch(typ(x))1187{1188case t_VEC: case t_COL:1189for (i=1; i<lx; i++) gel(z,i) = algtobasis(nf, gel(x,i));1190return z;1191case t_MAT: break;1192default: pari_err_TYPE("matalgtobasis",x);1193}1194li = lgcols(x);1195for (j=1; j<lx; j++)1196{1197GEN c = cgetg(li,t_COL), xj = gel(x,j);1198gel(z,j) = c;1199for (i=1; i<li; i++) gel(c,i) = algtobasis(nf, gel(xj,i));1200}1201return z;1202}1203GEN1204RgM_to_nfM(GEN nf,GEN x)1205{1206long i, j, li, lx;1207GEN z = cgetg_copy(x, &lx);12081209if (lx == 1) return z;1210li = lgcols(x);1211for (j=1; j<lx; j++)1212{1213GEN c = cgetg(li,t_COL), xj = gel(x,j);1214gel(z,j) = c;1215for (i=1; i<li; i++) gel(c,i) = nf_to_scalar_or_basis(nf, gel(xj,i));1216}1217return z;1218}1219GEN1220RgC_to_nfC(GEN nf, GEN x)1221{ pari_APPLY_type(t_COL, nf_to_scalar_or_basis(nf, gel(x,i))) }12221223/* x a t_POLMOD, supposedly in rnf = K[z]/(T), K = Q[y]/(Tnf) */1224GEN1225polmod_nffix(const char *f, GEN rnf, GEN x, int lift)1226{ return polmod_nffix2(f, rnf_get_nfpol(rnf), rnf_get_pol(rnf), x,lift); }1227GEN1228polmod_nffix2(const char *f, GEN T, GEN R, GEN x, int lift)1229{1230if (RgX_equal_var(gel(x,1), R))1231{1232x = gel(x,2);1233if (typ(x) == t_POL && varn(x) == varn(R))1234{1235x = RgX_nffix(f, T, x, lift);1236switch(lg(x))1237{1238case 2: return gen_0;1239case 3: return gel(x,2);1240}1241return x;1242}1243}1244return Rg_nffix(f, T, x, lift);1245}1246GEN1247rnfalgtobasis(GEN rnf,GEN x)1248{1249const char *f = "rnfalgtobasis";1250pari_sp av = avma;1251GEN T, R;12521253checkrnf(rnf);1254R = rnf_get_pol(rnf);1255T = rnf_get_nfpol(rnf);1256switch(typ(x))1257{1258case t_COL:1259if (lg(x)-1 != rnf_get_degree(rnf)) pari_err_DIM(f);1260x = RgV_nffix(f, T, x, 0);1261return gerepilecopy(av, x);12621263case t_POLMOD:1264x = polmod_nffix(f, rnf, x, 0);1265if (typ(x) != t_POL) break;1266return gerepileupto(av, RgM_RgX_mul(rnf_get_invzk(rnf), x));1267case t_POL:1268if (varn(x) == varn(T))1269{1270RgX_check_QX(x,f);1271if (degpol(x) >= degpol(T)) x = RgX_rem(x,T);1272x = mkpolmod(x,T); break;1273}1274x = RgX_nffix(f, T, x, 0);1275if (degpol(x) >= degpol(R)) x = RgX_rem(x, R);1276return gerepileupto(av, RgM_RgX_mul(rnf_get_invzk(rnf), x));1277}1278return gerepileupto(av, scalarcol(x, rnf_get_degree(rnf)));1279}12801281/* Given a and b in nf, gives an algebraic integer y in nf such that a-b.y1282* is "small" */1283GEN1284nfdiveuc(GEN nf, GEN a, GEN b)1285{1286pari_sp av = avma;1287a = nfdiv(nf,a,b);1288return gerepileupto(av, ground(a));1289}12901291/* Given a and b in nf, gives a "small" algebraic integer r in nf1292* of the form a-b.y */1293GEN1294nfmod(GEN nf, GEN a, GEN b)1295{1296pari_sp av = avma;1297GEN p1 = gneg_i(nfmul(nf,b,ground(nfdiv(nf,a,b))));1298return gerepileupto(av, nfadd(nf,a,p1));1299}13001301/* Given a and b in nf, gives a two-component vector [y,r] in nf such1302* that r=a-b.y is "small". */1303GEN1304nfdivrem(GEN nf, GEN a, GEN b)1305{1306pari_sp av = avma;1307GEN p1,z, y = ground(nfdiv(nf,a,b));13081309p1 = gneg_i(nfmul(nf,b,y));1310z = cgetg(3,t_VEC);1311gel(z,1) = gcopy(y);1312gel(z,2) = nfadd(nf,a,p1); return gerepileupto(av, z);1313}13141315/*************************************************************************/1316/** **/1317/** LOGARITHMIC EMBEDDINGS **/1318/** **/1319/*************************************************************************/13201321static int1322low_prec(GEN x)1323{1324switch(typ(x))1325{1326case t_INT: return !signe(x);1327case t_REAL: return !signe(x) || realprec(x) <= DEFAULTPREC;1328default: return 0;1329}1330}13311332static GEN1333cxlog_1(GEN nf) { return zerocol(lg(nf_get_roots(nf))-1); }1334static GEN1335cxlog_m1(GEN nf, long prec)1336{1337long i, l = lg(nf_get_roots(nf)), r1 = nf_get_r1(nf);1338GEN v = cgetg(l, t_COL), p, P;1339p = mppi(prec); P = mkcomplex(gen_0, p);1340for (i = 1; i <= r1; i++) gel(v,i) = P; /* IPi*/1341if (i < l) P = gmul2n(P,1);1342for ( ; i < l; i++) gel(v,i) = P; /* 2IPi */1343return v;1344}1345static GEN1346famat_cxlog(GEN nf, GEN fa, long prec)1347{1348GEN g, e, y = NULL;1349long i, l;13501351if (typ(fa) != t_MAT) pari_err_TYPE("famat_cxlog",fa);1352if (lg(fa) == 1) return cxlog_1(nf);1353g = gel(fa,1);1354e = gel(fa,2); l = lg(e);1355for (i = 1; i < l; i++)1356{1357GEN t, x = nf_to_scalar_or_basis(nf, gel(g,i));1358/* multiplicative arch would be better (save logs), but exponents overflow1359* [ could keep track of expo separately, but not worth it ] */1360t = nf_cxlog(nf,x,prec); if (!t) return NULL;1361if (gel(t,1) == gen_0) continue; /* positive rational */1362t = RgC_Rg_mul(t, gel(e,i));1363y = y? RgV_add(y,t): t;1364}1365return y ? y: cxlog_1(nf);1366}1367/* Archimedean components: [e_i Log( sigma_i(X) )], where X = primpart(x),1368* and e_i = 1 (resp 2.) for i <= R1 (resp. > R1) */1369GEN1370nf_cxlog(GEN nf, GEN x, long prec)1371{1372long i, l, r1;1373GEN v;1374if (typ(x) == t_MAT) return famat_cxlog(nf,x,prec);1375x = nf_to_scalar_or_basis(nf,x);1376if (typ(x) != t_COL) return gsigne(x) > 0? cxlog_1(nf): cxlog_m1(nf, prec);1377x = RgM_RgC_mul(nf_get_M(nf), Q_primpart(x));1378l = lg(x); r1 = nf_get_r1(nf);1379for (i = 1; i <= r1; i++)1380if (low_prec(gel(x,i))) return NULL;1381for ( ; i < l; i++)1382if (low_prec(gnorm(gel(x,i)))) return NULL;1383v = cgetg(l,t_COL);1384for (i = 1; i <= r1; i++) gel(v,i) = glog(gel(x,i),prec);1385for ( ; i < l; i++) gel(v,i) = gmul2n(glog(gel(x,i),prec),1);1386return v;1387}1388GEN1389nfV_cxlog(GEN nf, GEN x, long prec)1390{1391long i, l;1392GEN v = cgetg_copy(x, &l);1393for (i = 1; i < l; i++)1394if (!(gel(v,i) = nf_cxlog(nf, gel(x,i), prec))) return NULL;1395return v;1396}13971398static GEN1399scalar_logembed(GEN nf, GEN u, GEN *emb)1400{1401GEN v, logu;1402long i, s = signe(u), RU = lg(nf_get_roots(nf))-1, R1 = nf_get_r1(nf);14031404if (!s) pari_err_DOMAIN("nflogembed","argument","=",gen_0,u);1405v = cgetg(RU+1, t_COL); logu = logr_abs(u);1406for (i = 1; i <= R1; i++) gel(v,i) = logu;1407if (i <= RU)1408{1409GEN logu2 = shiftr(logu,1);1410for ( ; i <= RU; i++) gel(v,i) = logu2;1411}1412if (emb) *emb = const_col(RU, u);1413return v;1414}14151416static GEN1417famat_logembed(GEN nf,GEN x,GEN *emb,long prec)1418{1419GEN A, M, T, a, t, g = gel(x,1), e = gel(x,2);1420long i, l = lg(e);14211422if (l == 1) return scalar_logembed(nf, real_1(prec), emb);1423A = NULL; T = emb? cgetg(l, t_COL): NULL;1424if (emb) *emb = M = mkmat2(T, e);1425for (i = 1; i < l; i++)1426{1427a = nflogembed(nf, gel(g,i), &t, prec);1428if (!a) return NULL;1429a = RgC_Rg_mul(a, gel(e,i));1430A = A? RgC_add(A, a): a;1431if (emb) gel(T,i) = t;1432}1433return A;1434}14351436/* Get archimedean components: [e_i log( | sigma_i(x) | )], with e_i = 11437* (resp 2.) for i <= R1 (resp. > R1) and set emb to the embeddings of x.1438* Return NULL if precision problem */1439GEN1440nflogembed(GEN nf, GEN x, GEN *emb, long prec)1441{1442long i, l, r1;1443GEN v, t;14441445if (typ(x) == t_MAT) return famat_logembed(nf,x,emb,prec);1446x = nf_to_scalar_or_basis(nf,x);1447if (typ(x) != t_COL) return scalar_logembed(nf, gtofp(x,prec), emb);1448x = RgM_RgC_mul(nf_get_M(nf), x);1449l = lg(x); r1 = nf_get_r1(nf); v = cgetg(l,t_COL);1450for (i = 1; i <= r1; i++)1451{1452t = gabs(gel(x,i),prec); if (low_prec(t)) return NULL;1453gel(v,i) = glog(t,prec);1454}1455for ( ; i < l; i++)1456{1457t = gnorm(gel(x,i)); if (low_prec(t)) return NULL;1458gel(v,i) = glog(t,prec);1459}1460if (emb) *emb = x;1461return v;1462}14631464/*************************************************************************/1465/** **/1466/** REAL EMBEDDINGS **/1467/** **/1468/*************************************************************************/1469static GEN1470sarch_get_cyc(GEN sarch) { return gel(sarch,1); }1471static GEN1472sarch_get_archp(GEN sarch) { return gel(sarch,2); }1473static GEN1474sarch_get_MI(GEN sarch) { return gel(sarch,3); }1475static GEN1476sarch_get_lambda(GEN sarch) { return gel(sarch,4); }1477static GEN1478sarch_get_F(GEN sarch) { return gel(sarch,5); }14791480/* x not a scalar, true nf, return number of positive roots of char_x */1481static long1482num_positive(GEN nf, GEN x)1483{1484GEN T = nf_get_pol(nf), B, charx;1485long dnf, vnf, N;1486x = nf_to_scalar_or_alg(nf, x); /* not a scalar */1487charx = ZXQ_charpoly(x, T, 0);1488charx = ZX_radical(charx);1489N = degpol(T) / degpol(charx);1490/* real places are unramified ? */1491if (N == 1 || ZX_sturm(charx) * N == nf_get_r1(nf))1492return ZX_sturmpart(charx, mkvec2(gen_0,mkoo())) * N;1493/* painful case, multiply by random square until primitive */1494dnf = nf_get_degree(nf);1495vnf = varn(T);1496B = int2n(10);1497for(;;)1498{1499GEN y = RgXQ_sqr(random_FpX(dnf, vnf, B), T);1500y = RgXQ_mul(x, y, T);1501charx = ZXQ_charpoly(y, T, 0);1502if (ZX_is_squarefree(charx))1503return ZX_sturmpart(charx, mkvec2(gen_0,mkoo())) * N;1504}1505}15061507/* x a QC: return sigma_k(x) where 1 <= k <= r1+r2; correct but inefficient1508* if x in Q. M = nf_get_M(nf) */1509static GEN1510nfembed_i(GEN M, GEN x, long k)1511{1512long i, l = lg(M);1513GEN z = gel(x,1);1514for (i = 2; i < l; i++) z = gadd(z, gmul(gcoeff(M,k,i), gel(x,i)));1515return z;1516}1517GEN1518nfembed(GEN nf, GEN x, long k)1519{1520pari_sp av = avma;1521nf = checknf(nf);1522x = nf_to_scalar_or_basis(nf,x);1523if (typ(x) != t_COL) return gerepilecopy(av, x);1524return gerepileupto(av, nfembed_i(nf_get_M(nf),x,k));1525}15261527/* x a ZC */1528static GEN1529zk_embed(GEN M, GEN x, long k)1530{1531long i, l = lg(x);1532GEN z = gel(x,1); /* times M[k,1], which is 1 */1533for (i = 2; i < l; i++) z = mpadd(z, mpmul(gcoeff(M,k,i), gel(x,i)));1534return z;1535}15361537/* Given floating point approximation z of sigma_k(x), decide its sign1538* [0/+, 1/- and -1 for FAIL] */1539static long1540eval_sign_embed(GEN z)1541{ /* dubious, fail */1542if (typ(z) == t_REAL && realprec(z) <= LOWDEFAULTPREC) return -1;1543return (signe(z) < 1)? 1: 0;1544}1545/* return v such that (-1)^v = sign(sigma_k(x)), x primitive ZC */1546static long1547eval_sign(GEN M, GEN x, long k)1548{ return eval_sign_embed( zk_embed(M, x, k) ); }15491550/* check that signs[i..#signs] == s; signs = NULL encodes "totally positive" */1551static int1552oksigns(long l, GEN signs, long i, long s)1553{1554if (!signs) return s == 0;1555for (; i < l; i++)1556if (signs[i] != s) return 0;1557return 1;1558}1559/* check that signs[i] = s and signs[i+1..#signs] = 1-s */1560static int1561oksigns2(long l, GEN signs, long i, long s)1562{1563if (!signs) return s == 0 && i == l-1;1564return signs[i] == s && oksigns(l, signs, i+1, 1-s);1565}15661567/* true nf, x a ZC (primitive for efficiency), embx its embeddings or NULL */1568static int1569nfchecksigns_i(GEN nf, GEN x, GEN embx, GEN signs, GEN archp)1570{1571long l = lg(archp), i;1572GEN M = nf_get_M(nf), sarch = NULL;1573long np = -1;1574for (i = 1; i < l; i++)1575{1576long s;1577if (embx)1578s = eval_sign_embed(gel(embx,i));1579else1580s = eval_sign(M, x, archp[i]);1581/* 0 / + or 1 / -; -1 for FAIL */1582if (s < 0) /* failure */1583{1584long ni, r1 = nf_get_r1(nf);1585GEN xi;1586if (np < 0)1587{1588np = num_positive(nf, x);1589if (np == 0) return oksigns(l, signs, i, 1);1590if (np == r1) return oksigns(l, signs, i, 0);1591sarch = nfarchstar(nf, NULL, identity_perm(r1));1592}1593xi = set_sign_mod_divisor(nf, vecsmall_ei(r1, archp[i]), gen_1, sarch);1594xi = Q_primpart(xi);1595ni = num_positive(nf, nfmuli(nf,x,xi));1596if (ni == 0) return oksigns2(l, signs, i, 0);1597if (ni == r1) return oksigns2(l, signs, i, 1);1598s = ni < np? 0: 1;1599}1600if (s != (signs? signs[i]: 0)) return 0;1601}1602return 1;1603}1604static void1605pl_convert(GEN pl, GEN *psigns, GEN *parchp)1606{1607long i, j, l = lg(pl);1608GEN signs = cgetg(l, t_VECSMALL);1609GEN archp = cgetg(l, t_VECSMALL);1610for (i = j = 1; i < l; i++)1611{1612if (!pl[i]) continue;1613archp[j] = i;1614signs[j] = (pl[i] < 0)? 1: 0;1615j++;1616}1617setlg(archp, j); *parchp = archp;1618setlg(signs, j); *psigns = signs;1619}1620/* pl : requested signs for real embeddings, 0 = no sign constraint */1621int1622nfchecksigns(GEN nf, GEN x, GEN pl)1623{1624pari_sp av = avma;1625GEN signs, archp;1626nf = checknf(nf);1627x = nf_to_scalar_or_basis(nf,x);1628if (typ(x) != t_COL)1629{1630long i, l = lg(pl), s = gsigne(x);1631for (i = 1; i < l; i++)1632if (pl[i] && pl[i] != s) return gc_bool(av,0);1633return gc_bool(av,1);1634}1635pl_convert(pl, &signs, &archp);1636return gc_bool(av, nfchecksigns_i(nf, x, NULL, signs, archp));1637}16381639/* signs = NULL: totally positive, else sign[i] = 0 (+) or 1 (-) */1640static GEN1641get_C(GEN lambda, long l, GEN signs)1642{1643long i;1644GEN C, mlambda;1645if (!signs) return const_vec(l-1, lambda);1646C = cgetg(l, t_COL); mlambda = gneg(lambda);1647for (i = 1; i < l; i++) gel(C,i) = signs[i]? mlambda: lambda;1648return C;1649}1650/* signs = NULL: totally positive at archp */1651static GEN1652nfsetsigns(GEN nf, GEN signs, GEN x, GEN sarch)1653{1654long i, l = lg(sarch_get_archp(sarch));1655GEN ex;1656/* Is signature already correct ? */1657if (typ(x) != t_COL)1658{1659long s = gsigne(x);1660if (!s) i = 1;1661else if (!signs)1662i = (s < 0)? 1: l;1663else1664{1665s = s < 0? 1: 0;1666for (i = 1; i < l; i++)1667if (signs[i] != s) break;1668}1669ex = (i < l)? const_col(l-1, x): NULL;1670}1671else1672{1673pari_sp av = avma;1674GEN cex, M = nf_get_M(nf), archp = sarch_get_archp(sarch);1675GEN xp = Q_primitive_part(x,&cex);1676ex = cgetg(l,t_COL);1677for (i = 1; i < l; i++) gel(ex,i) = zk_embed(M,xp,archp[i]);1678if (nfchecksigns_i(nf, xp, ex, signs, archp)) { ex = NULL; set_avma(av); }1679else if (cex) ex = RgC_Rg_mul(ex, cex); /* put back content */1680}1681if (ex)1682{ /* If no, fix it */1683GEN MI = sarch_get_MI(sarch), F = sarch_get_F(sarch);1684GEN lambda = sarch_get_lambda(sarch);1685GEN t = RgC_sub(get_C(lambda, l, signs), ex);1686long e;1687t = grndtoi(RgM_RgC_mul(MI,t), &e);1688if (lg(F) != 1) t = ZM_ZC_mul(F, t);1689x = typ(x) == t_COL? RgC_add(t, x): RgC_Rg_add(t, x);1690}1691return x;1692}1693/* - sarch = nfarchstar(nf, F);1694* - x encodes a vector of signs at arch.archp: either a t_VECSMALL1695* (vector of signs as {0,1}-vector), NULL (totally positive at archp),1696* or a nonzero number field element (replaced by its signature at archp);1697* - y is a nonzero number field element1698* Return z = y (mod F) with signs(y, archp) = signs(x) (a {0,1}-vector) */1699GEN1700set_sign_mod_divisor(GEN nf, GEN x, GEN y, GEN sarch)1701{1702GEN archp = sarch_get_archp(sarch);1703if (lg(archp) == 1) return y;1704nf = checknf(nf);1705if (x && typ(x) != t_VECSMALL) x = nfsign_arch(nf, x, archp);1706y = nf_to_scalar_or_basis(nf,y);1707return nfsetsigns(nf, x, y, sarch);1708}17091710static GEN1711setsigns_init(GEN nf, GEN archp, GEN F, GEN DATA)1712{1713GEN lambda, Mr = rowpermute(nf_get_M(nf), archp), MI = F? RgM_mul(Mr,F): Mr;1714lambda = gmul2n(matrixnorm(MI,DEFAULTPREC), -1);1715if (typ(lambda) != t_REAL) lambda = gmul(lambda, sstoQ(1001,1000));1716if (lg(archp) < lg(MI))1717{1718GEN perm = gel(indexrank(MI), 2);1719if (!F) F = matid(nf_get_degree(nf));1720MI = vecpermute(MI, perm);1721F = vecpermute(F, perm);1722}1723if (!F) F = cgetg(1,t_MAT);1724MI = RgM_inv(MI);1725return mkvec5(DATA, archp, MI, lambda, F);1726}1727/* F nonzero integral ideal in HNF (or NULL: Z_K), compute elements in 1+F1728* whose sign matrix at archp is identity; archp in 'indices' format */1729GEN1730nfarchstar(GEN nf, GEN F, GEN archp)1731{1732long nba = lg(archp) - 1;1733if (!nba) return mkvec2(cgetg(1,t_VEC), archp);1734if (F && equali1(gcoeff(F,1,1))) F = NULL;1735if (F) F = idealpseudored(F, nf_get_roundG(nf));1736return setsigns_init(nf, archp, F, const_vec(nba, gen_2));1737}17381739/*************************************************************************/1740/** **/1741/** IDEALCHINESE **/1742/** **/1743/*************************************************************************/1744static int1745isprfact(GEN x)1746{1747long i, l;1748GEN L, E;1749if (typ(x) != t_MAT || lg(x) != 3) return 0;1750L = gel(x,1); l = lg(L);1751E = gel(x,2);1752for(i=1; i<l; i++)1753{1754checkprid(gel(L,i));1755if (typ(gel(E,i)) != t_INT) return 0;1756}1757return 1;1758}17591760/* initialize projectors mod pr[i]^e[i] for idealchinese */1761static GEN1762pr_init(GEN nf, GEN fa, GEN w, GEN dw)1763{1764GEN U, E, F, L = gel(fa,1), E0 = gel(fa,2);1765long i, r = lg(L);17661767if (w && lg(w) != r) pari_err_TYPE("idealchinese", w);1768if (r == 1 && !dw) return cgetg(1,t_VEC);1769E = leafcopy(E0); /* do not destroy fa[2] */1770for (i = 1; i < r; i++)1771if (signe(gel(E,i)) < 0) gel(E,i) = gen_0;1772F = factorbackprime(nf, L, E);1773if (dw)1774{1775F = ZM_Z_mul(F, dw);1776for (i = 1; i < r; i++)1777{1778GEN pr = gel(L,i);1779long e = itos(gel(E0,i)), v = idealval(nf, dw, pr);1780if (e >= 0)1781gel(E,i) = addiu(gel(E,i), v);1782else if (v + e <= 0)1783F = idealmulpowprime(nf, F, pr, stoi(-v)); /* coprime to pr */1784else1785{1786F = idealmulpowprime(nf, F, pr, stoi(e));1787gel(E,i) = stoi(v + e);1788}1789}1790}1791U = cgetg(r, t_VEC);1792for (i = 1; i < r; i++)1793{1794GEN u;1795if (w && gequal0(gel(w,i))) u = gen_0; /* unused */1796else1797{1798GEN pr = gel(L,i), e = gel(E,i), t;1799t = idealdivpowprime(nf,F, pr, e);1800u = hnfmerge_get_1(t, idealpow(nf, pr, e));1801if (!u) pari_err_COPRIME("idealchinese", t,pr);1802}1803gel(U,i) = u;1804}1805F = idealpseudored(F, nf_get_roundG(nf));1806return mkvec2(F, U);1807}18081809static GEN1810pl_normalize(GEN nf, GEN pl)1811{1812const char *fun = "idealchinese";1813if (lg(pl)-1 != nf_get_r1(nf)) pari_err_TYPE(fun,pl);1814switch(typ(pl))1815{1816case t_VEC: RgV_check_ZV(pl,fun); pl = ZV_to_zv(pl);1817/* fall through */1818case t_VECSMALL: break;1819default: pari_err_TYPE(fun,pl);1820}1821return pl;1822}18231824static int1825is_chineseinit(GEN x)1826{1827GEN fa, pl;1828long l;1829if (typ(x) != t_VEC || lg(x)!=3) return 0;1830fa = gel(x,1);1831pl = gel(x,2);1832if (typ(fa) != t_VEC || typ(pl) != t_VEC) return 0;1833l = lg(fa);1834if (l != 1)1835{1836if (l != 3 || typ(gel(fa,1)) != t_MAT || typ(gel(fa,2)) != t_VEC)1837return 0;1838}1839l = lg(pl);1840if (l != 1)1841{1842if (l != 6 || typ(gel(pl,3)) != t_MAT || typ(gel(pl,1)) != t_VECSMALL1843|| typ(gel(pl,2)) != t_VECSMALL)1844return 0;1845}1846return 1;1847}18481849/* nf a true 'nf' */1850static GEN1851chineseinit_i(GEN nf, GEN fa, GEN w, GEN dw)1852{1853const char *fun = "idealchineseinit";1854GEN archp = NULL, pl = NULL;1855switch(typ(fa))1856{1857case t_VEC:1858if (is_chineseinit(fa))1859{1860if (dw) pari_err_DOMAIN(fun, "denom(y)", "!=", gen_1, w);1861return fa;1862}1863if (lg(fa) != 3) pari_err_TYPE(fun, fa);1864/* of the form [x,s] */1865pl = pl_normalize(nf, gel(fa,2));1866fa = gel(fa,1);1867archp = vecsmall01_to_indices(pl);1868/* keep pr_init, reset pl */1869if (is_chineseinit(fa)) { fa = gel(fa,1); break; }1870/* fall through */1871case t_MAT: /* factorization? */1872if (isprfact(fa)) { fa = pr_init(nf, fa, w, dw); break; }1873default: pari_err_TYPE(fun,fa);1874}18751876if (!pl) pl = cgetg(1,t_VEC);1877else1878{1879long r = lg(archp);1880if (r == 1) pl = cgetg(1, t_VEC);1881else1882{1883GEN F = (lg(fa) == 1)? NULL: gel(fa,1), signs = cgetg(r, t_VECSMALL);1884long i;1885for (i = 1; i < r; i++) signs[i] = (pl[archp[i]] < 0)? 1: 0;1886pl = setsigns_init(nf, archp, F, signs);1887}1888}1889return mkvec2(fa, pl);1890}18911892/* Given a prime ideal factorization x, possibly with 0 or negative exponents,1893* and a vector w of elements of nf, gives b such that1894* v_p(b-w_p)>=v_p(x) for all prime ideals p in the ideal factorization1895* and v_p(b)>=0 for all other p, using the standard proof given in GTM 138. */1896GEN1897idealchinese(GEN nf, GEN x, GEN w)1898{1899const char *fun = "idealchinese";1900pari_sp av = avma;1901GEN x1, x2, s, dw, F;19021903nf = checknf(nf);1904if (!w) return gerepilecopy(av, chineseinit_i(nf,x,NULL,NULL));19051906if (typ(w) != t_VEC) pari_err_TYPE(fun,w);1907w = Q_remove_denom(matalgtobasis(nf,w), &dw);1908if (!is_chineseinit(x)) x = chineseinit_i(nf,x,w,dw);1909/* x is a 'chineseinit' */1910x1 = gel(x,1); s = NULL;1911x2 = gel(x,2);1912if (lg(x1) == 1) F = NULL;1913else1914{1915GEN U = gel(x1,2);1916long i, r = lg(w);1917F = gel(x1,1);1918for (i=1; i<r; i++)1919if (!gequal0(gel(w,i)))1920{1921GEN t = nfmuli(nf, gel(U,i), gel(w,i));1922s = s? ZC_add(s,t): t;1923}1924if (s) s = ZC_reducemodmatrix(s, F);1925}1926if (lg(x2) != 1) s = nfsetsigns(nf, gel(x2,1), s? s: gen_0, x2);1927if (!s) { s = zerocol(nf_get_degree(nf)); dw = NULL; }19281929if (dw) s = RgC_Rg_div(s,dw);1930return gerepileupto(av, s);1931}19321933/*************************************************************************/1934/** **/1935/** (Z_K/I)^* **/1936/** **/1937/*************************************************************************/1938GEN1939vecsmall01_to_indices(GEN v)1940{1941long i, k, l = lg(v);1942GEN p = new_chunk(l) + l;1943for (k=1, i=l-1; i; i--)1944if (v[i]) { *--p = i; k++; }1945*--p = evallg(k) | evaltyp(t_VECSMALL);1946set_avma((pari_sp)p); return p;1947}1948GEN1949vec01_to_indices(GEN v)1950{1951long i, k, l;1952GEN p;19531954switch (typ(v))1955{1956case t_VECSMALL: return v;1957case t_VEC: break;1958default: pari_err_TYPE("vec01_to_indices",v);1959}1960l = lg(v);1961p = new_chunk(l) + l;1962for (k=1, i=l-1; i; i--)1963if (signe(gel(v,i))) { *--p = i; k++; }1964*--p = evallg(k) | evaltyp(t_VECSMALL);1965set_avma((pari_sp)p); return p;1966}1967GEN1968indices_to_vec01(GEN p, long r)1969{1970long i, l = lg(p);1971GEN v = zerovec(r);1972for (i = 1; i < l; i++) gel(v, p[i]) = gen_1;1973return v;1974}19751976/* return (column) vector of R1 signatures of x (0 or 1) */1977GEN1978nfsign_arch(GEN nf, GEN x, GEN arch)1979{1980GEN sarch, M, V, archp = vec01_to_indices(arch);1981long i, s, np, n = lg(archp)-1;1982pari_sp av;19831984if (!n) return cgetg(1,t_VECSMALL);1985nf = checknf(nf);1986if (typ(x) == t_MAT)1987{ /* factorisation */1988GEN g = gel(x,1), e = gel(x,2);1989long l = lg(g);1990V = zero_zv(n);1991for (i = 1; i < l; i++)1992if (mpodd(gel(e,i)))1993Flv_add_inplace(V, nfsign_arch(nf,gel(g,i),archp), 2);1994set_avma((pari_sp)V); return V;1995}1996av = avma; V = cgetg(n+1,t_VECSMALL);1997x = nf_to_scalar_or_basis(nf, x);1998switch(typ(x))1999{2000case t_INT:2001s = signe(x);2002if (!s) pari_err_DOMAIN("nfsign_arch","element","=",gen_0,x);2003set_avma(av); return const_vecsmall(n, (s < 0)? 1: 0);2004case t_FRAC:2005s = signe(gel(x,1));2006set_avma(av); return const_vecsmall(n, (s < 0)? 1: 0);2007}2008x = Q_primpart(x); M = nf_get_M(nf); sarch = NULL; np = -1;2009for (i = 1; i <= n; i++)2010{2011long s = eval_sign(M, x, archp[i]);2012if (s < 0) /* failure */2013{2014long ni, r1 = nf_get_r1(nf);2015GEN xi;2016if (np < 0)2017{2018np = num_positive(nf, x);2019if (np == 0) { set_avma(av); return const_vecsmall(n, 1); }2020if (np == r1){ set_avma(av); return const_vecsmall(n, 0); }2021sarch = nfarchstar(nf, NULL, identity_perm(r1));2022}2023xi = set_sign_mod_divisor(nf, vecsmall_ei(r1, archp[i]), gen_1, sarch);2024xi = Q_primpart(xi);2025ni = num_positive(nf, nfmuli(nf,x,xi));2026if (ni == 0) { set_avma(av); V = const_vecsmall(n, 1); V[i] = 0; return V; }2027if (ni == r1){ set_avma(av); V = const_vecsmall(n, 0); V[i] = 1; return V; }2028s = ni < np? 0: 1;2029}2030V[i] = s;2031}2032set_avma((pari_sp)V); return V;2033}2034static void2035chk_ind(const char *s, long i, long r1)2036{2037if (i <= 0) pari_err_DOMAIN(s, "index", "<=", gen_0, stoi(i));2038if (i > r1) pari_err_DOMAIN(s, "index", ">", utoi(r1), utoi(i));2039}2040static GEN2041parse_embed(GEN ind, long r, const char *f)2042{2043long l, i;2044if (!ind) return identity_perm(r);2045switch(typ(ind))2046{2047case t_INT: case t_VEC: case t_COL: ind = gtovecsmall(ind); break;2048case t_VECSMALL: break;2049default: pari_err_TYPE(f, ind);2050}2051l = lg(ind);2052for (i = 1; i < l; i++) chk_ind(f, ind[i], r);2053return ind;2054}2055GEN2056nfeltsign(GEN nf, GEN x, GEN ind0)2057{2058pari_sp av = avma;2059long i, l;2060GEN v, ind;2061nf = checknf(nf);2062ind = parse_embed(ind0, nf_get_r1(nf), "nfeltsign");2063l = lg(ind);2064if (is_rational_t(typ(x)))2065{ /* nfsign_arch would test this, but avoid converting t_VECSMALL -> t_VEC */2066GEN s;2067switch(gsigne(x))2068{2069case -1:s = gen_m1; break;2070case 1: s = gen_1; break;2071default: s = gen_0; break;2072}2073set_avma(av);2074return (ind0 && typ(ind0) == t_INT)? s: const_vec(l-1, s);2075}2076v = nfsign_arch(nf, x, ind);2077if (ind0 && typ(ind0) == t_INT) { set_avma(av); return v[1]? gen_m1: gen_1; }2078settyp(v, t_VEC);2079for (i = 1; i < l; i++) gel(v,i) = v[i]? gen_m1: gen_1;2080return gerepileupto(av, v);2081}20822083GEN2084nfeltembed(GEN nf, GEN x, GEN ind0, long prec0)2085{2086pari_sp av = avma;2087long i, e, l, r1, r2, prec, prec1;2088GEN v, ind, cx;2089nf = checknf(nf); nf_get_sign(nf,&r1,&r2);2090x = nf_to_scalar_or_basis(nf, x);2091ind = parse_embed(ind0, r1+r2, "nfeltembed");2092l = lg(ind);2093if (typ(x) != t_COL)2094{2095if (!(ind0 && typ(ind0) == t_INT)) x = const_vec(l-1, x);2096return gerepilecopy(av, x);2097}2098x = Q_primitive_part(x, &cx);2099prec1 = prec0; e = gexpo(x);2100if (e > 8) prec1 += nbits2extraprec(e);2101prec = prec1;2102if (nf_get_prec(nf) < prec) nf = nfnewprec_shallow(nf, prec);2103v = cgetg(l, t_VEC);2104for(;;)2105{2106GEN M = nf_get_M(nf);2107for (i = 1; i < l; i++)2108{2109GEN t = nfembed_i(M, x, ind[i]);2110long e = gexpo(t);2111if (gequal0(t) || precision(t) < prec02112|| (e < 0 && prec < prec1 + nbits2extraprec(-e)) ) break;2113if (cx) t = gmul(t, cx);2114gel(v,i) = t;2115}2116if (i == l) break;2117prec = precdbl(prec);2118if (DEBUGLEVEL>1) pari_warn(warnprec,"eltnfembed", prec);2119nf = nfnewprec_shallow(nf, prec);2120}2121if (ind0 && typ(ind0) == t_INT) v = gel(v,1);2122return gerepilecopy(av, v);2123}21242125/* number of distinct roots of sigma(f) */2126GEN2127nfpolsturm(GEN nf, GEN f, GEN ind0)2128{2129pari_sp av = avma;2130long d, l, r1, single;2131GEN ind, u, v, vr1, T, s, t;21322133nf = checknf(nf); T = nf_get_pol(nf); r1 = nf_get_r1(nf);2134ind = parse_embed(ind0, r1, "nfpolsturm");2135single = ind0 && typ(ind0) == t_INT;2136l = lg(ind);21372138if (gequal0(f)) pari_err_ROOTS0("nfpolsturm");2139if (typ(f) == t_POL && varn(f) != varn(T))2140{2141f = RgX_nffix("nfpolsturm", T, f,1);2142if (lg(f) == 3) f = NULL;2143}2144else2145{2146(void)Rg_nffix("nfpolsturm", T, f, 0);2147f = NULL;2148}2149if (!f) { set_avma(av); return single? gen_0: zerovec(l-1); }2150d = degpol(f);2151if (d == 1) { set_avma(av); return single? gen_1: const_vec(l-1,gen_1); }21522153vr1 = const_vecsmall(l-1, 1);2154u = Q_primpart(f); s = ZV_to_zv(nfeltsign(nf, gel(u,d+2), ind));2155v = RgX_deriv(u); t = odd(d)? leafcopy(s): zv_neg(s);2156for(;;)2157{2158GEN r = RgX_neg( Q_primpart(RgX_pseudorem(u, v)) ), sr;2159long i, dr = degpol(r);2160if (dr < 0) break;2161sr = ZV_to_zv(nfeltsign(nf, gel(r,dr+2), ind));2162for (i = 1; i < l; i++)2163if (sr[i] != s[i]) { s[i] = sr[i], vr1[i]--; }2164if (odd(dr)) sr = zv_neg(sr);2165for (i = 1; i < l; i++)2166if (sr[i] != t[i]) { t[i] = sr[i], vr1[i]++; }2167if (!dr) break;2168u = v; v = r;2169}2170if (single) { set_avma(av); return stoi(vr1[1]); }2171return gerepileupto(av, zv_to_ZV(vr1));2172}21732174/* return the vector of signs of x; the matrix of such if x is a vector2175* of nf elements */2176GEN2177nfsign(GEN nf, GEN x)2178{2179long i, l;2180GEN archp, S;21812182nf = checknf(nf);2183archp = identity_perm( nf_get_r1(nf) );2184if (typ(x) != t_VEC) return nfsign_arch(nf, x, archp);2185l = lg(x); S = cgetg(l, t_MAT);2186for (i=1; i<l; i++) gel(S,i) = nfsign_arch(nf, gel(x,i), archp);2187return S;2188}21892190/* x integral elt, A integral ideal in HNF; reduce x mod A */2191static GEN2192zk_modHNF(GEN x, GEN A)2193{ return (typ(x) == t_COL)? ZC_hnfrem(x, A): modii(x, gcoeff(A,1,1)); }21942195/* given an element x in Z_K and an integral ideal y in HNF, coprime with x,2196outputs an element inverse of x modulo y */2197GEN2198nfinvmodideal(GEN nf, GEN x, GEN y)2199{2200pari_sp av = avma;2201GEN a, yZ = gcoeff(y,1,1);22022203if (equali1(yZ)) return gen_0;2204x = nf_to_scalar_or_basis(nf, x);2205if (typ(x) == t_INT) return gerepileupto(av, Fp_inv(x, yZ));22062207a = hnfmerge_get_1(idealhnf_principal(nf,x), y);2208if (!a) pari_err_INV("nfinvmodideal", x);2209return gerepileupto(av, zk_modHNF(nfdiv(nf,a,x), y));2210}22112212static GEN2213nfsqrmodideal(GEN nf, GEN x, GEN id)2214{ return zk_modHNF(nfsqri(nf,x), id); }2215static GEN2216nfmulmodideal(GEN nf, GEN x, GEN y, GEN id)2217{ return x? zk_modHNF(nfmuli(nf,x,y), id): y; }2218/* assume x integral, k integer, A in HNF */2219GEN2220nfpowmodideal(GEN nf,GEN x,GEN k,GEN A)2221{2222long s = signe(k);2223pari_sp av;2224GEN y;22252226if (!s) return gen_1;2227av = avma;2228x = nf_to_scalar_or_basis(nf, x);2229if (typ(x) != t_COL) return Fp_pow(x, k, gcoeff(A,1,1));2230if (s < 0) { x = nfinvmodideal(nf, x,A); k = negi(k); }2231for(y = NULL;;)2232{2233if (mpodd(k)) y = nfmulmodideal(nf,y,x,A);2234k = shifti(k,-1); if (!signe(k)) break;2235x = nfsqrmodideal(nf,x,A);2236}2237return gerepileupto(av, y);2238}22392240/* a * g^n mod id */2241static GEN2242nfmulpowmodideal(GEN nf, GEN a, GEN g, GEN n, GEN id)2243{2244return nfmulmodideal(nf, a, nfpowmodideal(nf,g,n,id), id);2245}22462247/* assume (num(g[i]), id) = 1 for all i. Return prod g[i]^e[i] mod id.2248* EX = multiple of exponent of (O_K/id)^* */2249GEN2250famat_to_nf_modideal_coprime(GEN nf, GEN g, GEN e, GEN id, GEN EX)2251{2252GEN EXo2, plus = NULL, minus = NULL, idZ = gcoeff(id,1,1);2253long i, lx = lg(g);22542255if (equali1(idZ)) return gen_1; /* id = Z_K */2256EXo2 = (expi(EX) > 10)? shifti(EX,-1): NULL;2257for (i = 1; i < lx; i++)2258{2259GEN h, n = centermodii(gel(e,i), EX, EXo2);2260long sn = signe(n);2261if (!sn) continue;22622263h = nf_to_scalar_or_basis(nf, gel(g,i));2264switch(typ(h))2265{2266case t_INT: break;2267case t_FRAC:2268h = Fp_div(gel(h,1), gel(h,2), idZ); break;2269default:2270{2271GEN dh;2272h = Q_remove_denom(h, &dh);2273if (dh) h = FpC_Fp_mul(h, Fp_inv(dh,idZ), idZ);2274}2275}2276if (sn > 0)2277plus = nfmulpowmodideal(nf, plus, h, n, id);2278else /* sn < 0 */2279minus = nfmulpowmodideal(nf, minus, h, negi(n), id);2280}2281if (minus) plus = nfmulmodideal(nf, plus, nfinvmodideal(nf,minus,id), id);2282return plus? plus: gen_1;2283}22842285/* given 2 integral ideals x, y in HNF s.t x | y | x^2, compute (1+x)/(1+y) in2286* the form [[cyc],[gen], U], where U := ux^-1 as a pair [ZM, denom(U)] */2287static GEN2288zidealij(GEN x, GEN y)2289{2290GEN U, G, cyc, xp = gcoeff(x,1,1), xi = hnf_invscale(x, xp);2291long j, N;22922293/* x^(-1) y = relations between the 1 + x_i (HNF) */2294cyc = ZM_snf_group(ZM_Z_divexact(ZM_mul(xi, y), xp), &U, &G);2295N = lg(cyc); G = ZM_mul(x,G); settyp(G, t_VEC); /* new generators */2296for (j=1; j<N; j++)2297{2298GEN c = gel(G,j);2299gel(c,1) = addiu(gel(c,1), 1); /* 1 + g_j */2300if (ZV_isscalar(c)) gel(G,j) = gel(c,1);2301}2302return mkvec4(cyc, G, ZM_mul(U,xi), xp);2303}23042305/* lg(x) > 1, x + 1; shallow */2306static GEN2307ZC_add1(GEN x)2308{2309long i, l = lg(x);2310GEN y = cgetg(l, t_COL);2311for (i = 2; i < l; i++) gel(y,i) = gel(x,i);2312gel(y,1) = addiu(gel(x,1), 1); return y;2313}2314/* lg(x) > 1, x - 1; shallow */2315static GEN2316ZC_sub1(GEN x)2317{2318long i, l = lg(x);2319GEN y = cgetg(l, t_COL);2320for (i = 2; i < l; i++) gel(y,i) = gel(x,i);2321gel(y,1) = subiu(gel(x,1), 1); return y;2322}23232324/* x,y are t_INT or ZC */2325static GEN2326zkadd(GEN x, GEN y)2327{2328long tx = typ(x);2329if (tx == typ(y))2330return tx == t_INT? addii(x,y): ZC_add(x,y);2331else2332return tx == t_INT? ZC_Z_add(y,x): ZC_Z_add(x,y);2333}2334/* x a t_INT or ZC, x+1; shallow */2335static GEN2336zkadd1(GEN x)2337{2338long tx = typ(x);2339return tx == t_INT? addiu(x,1): ZC_add1(x);2340}2341/* x a t_INT or ZC, x-1; shallow */2342static GEN2343zksub1(GEN x)2344{2345long tx = typ(x);2346return tx == t_INT? subiu(x,1): ZC_sub1(x);2347}2348/* x,y are t_INT or ZC; x - y */2349static GEN2350zksub(GEN x, GEN y)2351{2352long tx = typ(x), ty = typ(y);2353if (tx == ty)2354return tx == t_INT? subii(x,y): ZC_sub(x,y);2355else2356return tx == t_INT? Z_ZC_sub(x,y): ZC_Z_sub(x,y);2357}2358/* x is t_INT or ZM (mult. map), y is t_INT or ZC; x * y */2359static GEN2360zkmul(GEN x, GEN y)2361{2362long tx = typ(x), ty = typ(y);2363if (ty == t_INT)2364return tx == t_INT? mulii(x,y): ZC_Z_mul(gel(x,1),y);2365else2366return tx == t_INT? ZC_Z_mul(y,x): ZM_ZC_mul(x,y);2367}23682369/* (U,V) = 1 coprime ideals. Want z = x mod U, = y mod V; namely2370* z =vx + uy = v(x-y) + y, where u + v = 1, u in U, v in V.2371* zkc = [v, UV], v a t_INT or ZM (mult. by v map), UV a ZM (ideal in HNF);2372* shallow */2373GEN2374zkchinese(GEN zkc, GEN x, GEN y)2375{2376GEN v = gel(zkc,1), UV = gel(zkc,2), z = zkadd(zkmul(v, zksub(x,y)), y);2377return zk_modHNF(z, UV);2378}2379/* special case z = x mod U, = 1 mod V; shallow */2380GEN2381zkchinese1(GEN zkc, GEN x)2382{2383GEN v = gel(zkc,1), UV = gel(zkc,2), z = zkadd1(zkmul(v, zksub1(x)));2384return (typ(z) == t_INT)? z: ZC_hnfrem(z, UV);2385}2386static GEN2387zkVchinese1(GEN zkc, GEN v)2388{2389long i, ly;2390GEN y = cgetg_copy(v, &ly);2391for (i=1; i<ly; i++) gel(y,i) = zkchinese1(zkc, gel(v,i));2392return y;2393}23942395/* prepare to solve z = x (mod A), z = y mod (B) [zkchinese or zkchinese1] */2396GEN2397zkchineseinit(GEN nf, GEN A, GEN B, GEN AB)2398{2399GEN v;2400long e;2401nf = checknf(nf);2402v = idealaddtoone_raw(nf, A, B);2403if ((e = gexpo(v)) > 5)2404{2405GEN b = (typ(v) == t_COL)? v: scalarcol_shallow(v, nf_get_degree(nf));2406b= ZC_reducemodlll(b, AB);2407if (gexpo(b) < e) v = b;2408}2409return mkvec2(zk_scalar_or_multable(nf,v), AB);2410}2411/* prepare to solve z = x (mod A), z = 1 mod (B)2412* and then z = 1 (mod A), z = y mod (B) [zkchinese1 twice] */2413static GEN2414zkchinese1init2(GEN nf, GEN A, GEN B, GEN AB)2415{2416GEN zkc = zkchineseinit(nf, A, B, AB);2417GEN mv = gel(zkc,1), mu;2418if (typ(mv) == t_INT) return mkvec2(zkc, mkvec2(subui(1,mv),AB));2419mu = RgM_Rg_add_shallow(ZM_neg(mv), gen_1);2420return mkvec2(mkvec2(mv,AB), mkvec2(mu,AB));2421}24222423static GEN2424apply_U(GEN L, GEN a)2425{2426GEN e, U = gel(L,3), dU = gel(L,4);2427if (typ(a) == t_INT)2428e = ZC_Z_mul(gel(U,1), subiu(a, 1));2429else2430{ /* t_COL */2431GEN t = shallowcopy(a);2432gel(t,1) = subiu(gel(t,1), 1); /* t = a - 1 */2433e = ZM_ZC_mul(U, t);2434}2435return gdiv(e, dU);2436}24372438/* true nf; vectors of [[cyc],[g],U.X^-1]. Assume k > 1. */2439static GEN2440principal_units(GEN nf, GEN pr, long k, GEN prk)2441{2442GEN list, prb;2443ulong mask = quadratic_prec_mask(k);2444long a = 1;24452446prb = pr_hnf(nf,pr);2447list = vectrunc_init(k);2448while (mask > 1)2449{2450GEN pra = prb;2451long b = a << 1;24522453if (mask & 1) b--;2454mask >>= 1;2455/* compute 1 + pr^a / 1 + pr^b, 2a <= b */2456prb = (b >= k)? prk: idealpows(nf,pr,b);2457vectrunc_append(list, zidealij(pra, prb));2458a = b;2459}2460return list;2461}2462/* a = 1 mod (pr) return log(a) on local-gens of 1+pr/1+pr^k */2463static GEN2464log_prk1(GEN nf, GEN a, long nh, GEN L2, GEN prk)2465{2466GEN y = cgetg(nh+1, t_COL);2467long j, iy, c = lg(L2)-1;2468for (j = iy = 1; j <= c; j++)2469{2470GEN L = gel(L2,j), cyc = gel(L,1), gen = gel(L,2), E = apply_U(L,a);2471long i, nc = lg(cyc)-1;2472int last = (j == c);2473for (i = 1; i <= nc; i++, iy++)2474{2475GEN t, e = gel(E,i);2476if (typ(e) != t_INT) pari_err_COPRIME("zlog_prk1", a, prk);2477t = Fp_neg(e, gel(cyc,i));2478gel(y,iy) = negi(t);2479if (!last && signe(t)) a = nfmulpowmodideal(nf, a, gel(gen,i), t, prk);2480}2481}2482return y;2483}2484/* true nf */2485static GEN2486principal_units_relations(GEN nf, GEN L2, GEN prk, long nh)2487{2488GEN h = cgetg(nh+1,t_MAT);2489long ih, j, c = lg(L2)-1;2490for (j = ih = 1; j <= c; j++)2491{2492GEN L = gel(L2,j), F = gel(L,1), G = gel(L,2);2493long k, lG = lg(G);2494for (k = 1; k < lG; k++,ih++)2495{ /* log(g^f) mod pr^e */2496GEN a = nfpowmodideal(nf,gel(G,k),gel(F,k),prk);2497gel(h,ih) = ZC_neg(log_prk1(nf, a, nh, L2, prk));2498gcoeff(h,ih,ih) = gel(F,k);2499}2500}2501return h;2502}2503/* true nf; k > 1; multiplicative group (1 + pr) / (1 + pr^k) */2504static GEN2505idealprincipalunits_i(GEN nf, GEN pr, long k, GEN *pU)2506{2507GEN cyc, gen, L2, prk = idealpows(nf, pr, k);25082509L2 = principal_units(nf, pr, k, prk);2510if (k == 2)2511{2512GEN L = gel(L2,1);2513cyc = gel(L,1);2514gen = gel(L,2);2515if (pU) *pU = matid(lg(gen)-1);2516}2517else2518{2519long c = lg(L2), j;2520GEN EX, h, Ui, vg = cgetg(c, t_VEC);2521for (j = 1; j < c; j++) gel(vg, j) = gmael(L2,j,2);2522vg = shallowconcat1(vg);2523h = principal_units_relations(nf, L2, prk, lg(vg)-1);2524h = ZM_hnfall_i(h, NULL, 0);2525cyc = ZM_snf_group(h, pU, &Ui);2526c = lg(Ui); gen = cgetg(c, t_VEC); EX = cyc_get_expo(cyc);2527for (j = 1; j < c; j++)2528gel(gen,j) = famat_to_nf_modideal_coprime(nf, vg, gel(Ui,j), prk, EX);2529}2530return mkvec4(cyc, gen, prk, L2);2531}2532GEN2533idealprincipalunits(GEN nf, GEN pr, long k)2534{2535pari_sp av;2536GEN v;2537nf = checknf(nf);2538if (k == 1) { checkprid(pr); retmkvec3(gen_1,cgetg(1,t_VEC),cgetg(1,t_VEC)); }2539av = avma; v = idealprincipalunits_i(nf, pr, k, NULL);2540return gerepilecopy(av, mkvec3(powiu(pr_norm(pr), k-1), gel(v,1), gel(v,2)));2541}25422543/* true nf; given an ideal pr^k dividing an integral ideal x (in HNF form)2544* compute an 'sprk', the structure of G = (Z_K/pr^k)^* [ x = NULL for x=pr^k ]2545* Return a vector with at least 4 components [cyc],[gen],[HNF pr^k,pr,k],ff,2546* where2547* cyc : type of G as abelian group (SNF)2548* gen : generators of G, coprime to x2549* pr^k: in HNF2550* ff : data for log_g in (Z_K/pr)^*2551* Two extra components are present iff k > 1: L2, U2552* L2 : list of data structures to compute local DL in (Z_K/pr)^*,2553* and 1 + pr^a/ 1 + pr^b for various a < b <= min(2a, k)2554* U : base change matrices to convert a vector of local DL to DL wrt gen2555* If MOD is not NULL, initialize G / G^MOD instead */2556static GEN2557sprkinit(GEN nf, GEN pr, long k, GEN x, GEN MOD)2558{2559GEN T, p, Ld, modpr, cyc, gen, g, g0, A, prk, U, L2, ord0 = NULL;2560long f = pr_get_f(pr);25612562if(DEBUGLEVEL>3) err_printf("treating pr^%ld, pr = %Ps\n",k,pr);2563modpr = nf_to_Fq_init(nf, &pr,&T,&p);2564if (MOD)2565{2566GEN A = subiu(powiu(p,f), 1), d = gcdii(A, MOD), fa = Z_factor(d);2567ord0 = mkvec2(A, fa); /* true order, factorization of order in G/G^MOD */2568Ld = gel(fa,1);2569if (lg(Ld) > 1 && equaliu(gel(Ld,1),2)) Ld = vecslice(Ld,2,lg(Ld)-1);2570}2571/* (Z_K / pr)^* */2572if (f == 1)2573{2574g0 = g = MOD? pgener_Fp_local(p, Ld): pgener_Fp(p);2575if (!ord0) ord0 = get_arith_ZZM(subiu(p,1));2576}2577else2578{2579g0 = g = MOD? gener_FpXQ_local(T, p, Ld): gener_FpXQ(T,p, &ord0);2580g = Fq_to_nf(g, modpr);2581if (typ(g) == t_POL) g = poltobasis(nf, g);2582}2583A = gel(ord0, 1); /* Norm(pr)-1 */2584/* If MOD != NULL, d = gcd(A, MOD): g^(A/d) has order d */2585if (k == 1)2586{2587cyc = mkvec(A);2588gen = mkvec(g);2589prk = pr_hnf(nf,pr);2590L2 = U = NULL;2591}2592else2593{ /* local-gens of (1 + pr)/(1 + pr^k) = SNF-gens * U */2594GEN AB, B, u, v, w;2595long j, l;2596w = idealprincipalunits_i(nf, pr, k, &U);2597/* incorporate (Z_K/pr)^*, order A coprime to B = expo(1+pr/1+pr^k)*/2598cyc = leafcopy(gel(w,1)); B = cyc_get_expo(cyc); AB = mulii(A,B);2599gen = leafcopy(gel(w,2));2600prk = gel(w,3);2601g = nfpowmodideal(nf, g, B, prk);2602g0 = Fq_pow(g0, modii(B,A), T, p); /* update primitive root */2603L2 = mkvec3(A, g, gel(w,4));2604gel(cyc,1) = AB;2605gel(gen,1) = nfmulmodideal(nf, gel(gen,1), g, prk);2606u = mulii(Fp_inv(A,B), A);2607v = subui(1, u); l = lg(U);2608for (j = 1; j < l; j++) gcoeff(U,1,j) = Fp_mul(u, gcoeff(U,1,j), AB);2609U = mkvec2(Rg_col_ei(v, lg(gen)-1, 1), U);2610}2611/* local-gens of (Z_K/pr^k)^* = SNF-gens * U */2612if (x)2613{2614GEN uv = zkchineseinit(nf, idealmulpowprime(nf,x,pr,utoineg(k)), prk, x);2615gen = zkVchinese1(uv, gen);2616}2617return mkvecn(U? 6: 4, cyc, gen, prk, mkvec3(modpr,g0,ord0), L2, U);2618}2619static GEN2620sprk_get_cyc(GEN s) { return gel(s,1); }2621static GEN2622sprk_get_expo(GEN s) { return cyc_get_expo(sprk_get_cyc(s)); }2623static GEN2624sprk_get_gen(GEN s) { return gel(s,2); }2625static GEN2626sprk_get_prk(GEN s) { return gel(s,3); }2627static GEN2628sprk_get_ff(GEN s) { return gel(s,4); }2629static GEN2630sprk_get_pr(GEN s) { GEN ff = gel(s,4); return modpr_get_pr(gel(ff,1)); }2631/* L2 to 1 + pr / 1 + pr^k */2632static GEN2633sprk_get_L2(GEN s) { return gmael(s,5,3); }2634/* lift to nf of primitive root of k(pr) */2635static GEN2636sprk_get_gnf(GEN s) { return gmael(s,5,2); }2637static void2638sprk_get_U2(GEN s, GEN *U1, GEN *U2)2639{ GEN v = gel(s,6); *U1 = gel(v,1); *U2 = gel(v,2); }2640static int2641sprk_is_prime(GEN s) { return lg(s) == 5; }26422643static GEN2644famat_zlog_pr(GEN nf, GEN g, GEN e, GEN sprk, GEN mod)2645{2646GEN x, expo = sprk_get_expo(sprk);2647if (mod) expo = gcdii(expo,mod);2648x = famat_makecoprime(nf, g, e, sprk_get_pr(sprk), sprk_get_prk(sprk), expo);2649return log_prk(nf, x, sprk, mod);2650}2651/* famat_zlog_pr assuming (g,sprk.pr) = 1 */2652static GEN2653famat_zlog_pr_coprime(GEN nf, GEN g, GEN e, GEN sprk, GEN MOD)2654{2655GEN x = famat_to_nf_modideal_coprime(nf, g, e, sprk_get_prk(sprk),2656sprk_get_expo(sprk));2657return log_prk(nf, x, sprk, MOD);2658}26592660/* o t_INT, O = [ord,fa] format for multiple of o (for Fq_log);2661* return o in [ord,fa] format */2662static GEN2663order_update(GEN o, GEN O)2664{2665GEN p = gmael(O,2,1), z = o, P, E;2666long i, j, l = lg(p);2667P = cgetg(l, t_COL);2668E = cgetg(l, t_COL);2669for (i = j = 1; i < l; i++)2670{2671long v = Z_pvalrem(z, gel(p,i), &z);2672if (v)2673{2674gel(P,j) = gel(p,i);2675gel(E,j) = utoipos(v); j++;2676if (is_pm1(z)) break;2677}2678}2679setlg(P, j);2680setlg(E, j); return mkvec2(o, mkmat2(P,E));2681}26822683/* a in Z_K (t_COL or t_INT), pr prime ideal, sprk = sprkinit(nf,pr,k,x),2684* mod positive t_INT or NULL (meaning mod=0).2685* return log(a) modulo mod on SNF-generators of (Z_K/pr^k)^* */2686GEN2687log_prk(GEN nf, GEN a, GEN sprk, GEN mod)2688{2689GEN e, prk, g, U1, U2, y, ff, O, o, oN, gN, N, T, p, modpr, pr, cyc;26902691if (typ(a) == t_MAT) return famat_zlog_pr(nf, gel(a,1), gel(a,2), sprk, mod);2692N = NULL;2693ff = sprk_get_ff(sprk);2694pr = gel(ff,1); /* modpr */2695g = gN = gel(ff,2);2696O = gel(ff,3); /* order of g = |Fq^*|, in [ord, fa] format */2697o = oN = gel(O,1); /* order as a t_INT */2698prk = sprk_get_prk(sprk);2699modpr = nf_to_Fq_init(nf, &pr, &T, &p);2700if (mod)2701{2702GEN d = gcdii(o,mod);2703if (!equalii(o, d))2704{2705N = diviiexact(o,d); /* > 1, coprime to p */2706a = nfpowmodideal(nf, a, N, prk);2707oN = d; /* order of g^N mod pr */2708}2709}2710if (equali1(oN))2711e = gen_0;2712else2713{2714if (N) { O = order_update(oN, O); gN = Fq_pow(g, N, T, p); }2715e = Fq_log(nf_to_Fq(nf,a,modpr), gN, O, T, p);2716}2717/* 0 <= e < oN is correct modulo oN */2718if (sprk_is_prime(sprk)) return mkcol(e); /* k = 1 */27192720sprk_get_U2(sprk, &U1,&U2);2721cyc = sprk_get_cyc(sprk);2722if (mod)2723{2724cyc = ZV_snf_gcd(cyc, mod);2725if (signe(remii(mod,p))) return vecmodii(ZC_Z_mul(U1,e), cyc);2726}2727if (signe(e))2728{2729GEN E = N? mulii(e, N): e;2730a = nfmulpowmodideal(nf, a, sprk_get_gnf(sprk), Fp_neg(E, o), prk);2731}2732/* a = 1 mod pr */2733y = log_prk1(nf, a, lg(U2)-1, sprk_get_L2(sprk), prk);2734if (N)2735{ /* from DL(a^N) to DL(a) */2736GEN E = gel(sprk_get_cyc(sprk), 1), q = powiu(p, Z_pval(E, p));2737y = ZC_Z_mul(y, Fp_inv(N, q));2738}2739y = ZC_lincomb(gen_1, e, ZM_ZC_mul(U2,y), U1);2740return vecmodii(y, cyc);2741}2742GEN2743log_prk_init(GEN nf, GEN pr, long k, GEN MOD)2744{ return sprkinit(checknf(nf),pr,k,NULL,MOD);}2745GEN2746veclog_prk(GEN nf, GEN v, GEN sprk)2747{2748long l = lg(v), i;2749GEN w = cgetg(l, t_MAT);2750for (i = 1; i < l; i++) gel(w,i) = log_prk(nf, gel(v,i), sprk, NULL);2751return w;2752}27532754static GEN2755famat_zlog(GEN nf, GEN fa, GEN sgn, zlog_S *S)2756{2757long i, l0, l = lg(S->U);2758GEN g = gel(fa,1), e = gel(fa,2), y = cgetg(l, t_COL);2759l0 = lg(S->sprk); /* = l (trivial arch. part), or l-1 */2760for (i=1; i < l0; i++) gel(y,i) = famat_zlog_pr(nf, g, e, gel(S->sprk,i), S->mod);2761if (l0 != l)2762{2763if (!sgn) sgn = nfsign_arch(nf, fa, S->archp);2764gel(y,l0) = Flc_to_ZC(sgn);2765}2766return y;2767}27682769/* assume that cyclic factors are normalized, in particular != [1] */2770static GEN2771split_U(GEN U, GEN Sprk)2772{2773long t = 0, k, n, l = lg(Sprk);2774GEN vU = cgetg(l+1, t_VEC);2775for (k = 1; k < l; k++)2776{2777n = lg(sprk_get_cyc(gel(Sprk,k))) - 1; /* > 0 */2778gel(vU,k) = vecslice(U, t+1, t+n);2779t += n;2780}2781/* t+1 .. lg(U)-1 */2782n = lg(U) - t - 1; /* can be 0 */2783if (!n) setlg(vU,l); else gel(vU,l) = vecslice(U, t+1, t+n);2784return vU;2785}27862787static void2788init_zlog_mod(zlog_S *S, GEN bid, GEN mod)2789{2790GEN fa2 = bid_get_fact2(bid);2791S->U = bid_get_U(bid);2792S->hU = lg(bid_get_cyc(bid))-1;2793S->archp = bid_get_archp(bid);2794S->sprk = bid_get_sprk(bid);2795S->bid = bid;2796S->mod = mod;2797S->P = gel(fa2,1);2798S->k = gel(fa2,2);2799S->no2 = lg(S->P) == lg(gel(bid_get_fact(bid),1));2800}2801void2802init_zlog(zlog_S *S, GEN bid)2803{2804return init_zlog_mod(S, bid, NULL);2805}28062807/* a a t_FRAC/t_INT, reduce mod bid */2808static GEN2809Q_mod_bid(GEN bid, GEN a)2810{2811GEN xZ = gcoeff(bid_get_ideal(bid),1,1);2812GEN b = Rg_to_Fp(a, xZ);2813if (gsigne(a) < 0) b = subii(b, xZ);2814return signe(b)? b: xZ;2815}2816/* Return decomposition of a on the CRT generators blocks attached to the2817* S->sprk and sarch; sgn = sign(a, S->arch), NULL if unknown */2818static GEN2819zlog(GEN nf, GEN a, GEN sgn, zlog_S *S)2820{2821long k, l;2822GEN y;2823a = nf_to_scalar_or_basis(nf, a);2824switch(typ(a))2825{2826case t_INT: break;2827case t_FRAC: a = Q_mod_bid(S->bid, a); break;2828default: /* case t_COL: */2829{2830GEN den;2831check_nfelt(a, &den);2832if (den)2833{2834a = Q_muli_to_int(a, den);2835a = mkmat2(mkcol2(a, den), mkcol2(gen_1, gen_m1));2836return famat_zlog(nf, a, sgn, S);2837}2838}2839}2840if (sgn)2841sgn = (lg(sgn) == 1)? NULL: leafcopy(sgn);2842else2843sgn = (lg(S->archp) == 1)? NULL: nfsign_arch(nf, a, S->archp);2844l = lg(S->sprk);2845y = cgetg(sgn? l+1: l, t_COL);2846for (k = 1; k < l; k++)2847{2848GEN sprk = gel(S->sprk,k);2849gel(y,k) = log_prk(nf, a, sprk, S->mod);2850}2851if (sgn) gel(y,l) = Flc_to_ZC(sgn);2852return y;2853}28542855/* true nf */2856GEN2857pr_basis_perm(GEN nf, GEN pr)2858{2859long f = pr_get_f(pr);2860GEN perm;2861if (f == nf_get_degree(nf)) return identity_perm(f);2862perm = cgetg(f+1, t_VECSMALL);2863perm[1] = 1;2864if (f > 1)2865{2866GEN H = pr_hnf(nf,pr);2867long i, k;2868for (i = k = 2; k <= f; i++)2869if (!equali1(gcoeff(H,i,i))) perm[k++] = i;2870}2871return perm;2872}28732874/* \sum U[i]*y[i], U[i] ZM, y[i] ZC. We allow lg(y) > lg(U). */2875static GEN2876ZMV_ZCV_mul(GEN U, GEN y)2877{2878long i, l = lg(U);2879GEN z = NULL;2880if (l == 1) return cgetg(1,t_COL);2881for (i = 1; i < l; i++)2882{2883GEN u = ZM_ZC_mul(gel(U,i), gel(y,i));2884z = z? ZC_add(z, u): u;2885}2886return z;2887}2888/* A * (U[1], ..., U[d] */2889static GEN2890ZM_ZMV_mul(GEN A, GEN U)2891{2892long i, l;2893GEN V = cgetg_copy(U,&l);2894for (i = 1; i < l; i++) gel(V,i) = ZM_mul(A,gel(U,i));2895return V;2896}28972898/* a = 1 mod pr, sprk mod pr^e, e >= 1 */2899static GEN2900sprk_log_prk1_2(GEN nf, GEN a, GEN sprk)2901{2902GEN U1, U2, y, L2 = sprk_get_L2(sprk);2903sprk_get_U2(sprk, &U1,&U2);2904y = ZM_ZC_mul(U2, log_prk1(nf, a, lg(U2)-1, L2, sprk_get_prk(sprk)));2905return vecmodii(y, sprk_get_cyc(sprk));2906}2907/* assume e >= 2 */2908static GEN2909sprk_log_gen_pr2(GEN nf, GEN sprk, long e)2910{2911GEN M, G, pr = sprk_get_pr(sprk);2912long i, l;2913if (e == 2)2914{2915GEN L2 = sprk_get_L2(sprk), L = gel(L2,1);2916G = gel(L,2); l = lg(G);2917}2918else2919{2920GEN perm = pr_basis_perm(nf,pr), PI = nfpow_u(nf, pr_get_gen(pr), e-1);2921l = lg(perm);2922G = cgetg(l, t_VEC);2923if (typ(PI) == t_INT)2924{ /* zk_ei_mul doesn't allow t_INT */2925long N = nf_get_degree(nf);2926gel(G,1) = addiu(PI,1);2927for (i = 2; i < l; i++)2928{2929GEN z = col_ei(N, 1);2930gel(G,i) = z; gel(z, perm[i]) = PI;2931}2932}2933else2934{2935gel(G,1) = nfadd(nf, gen_1, PI);2936for (i = 2; i < l; i++)2937gel(G,i) = nfadd(nf, gen_1, zk_ei_mul(nf, PI, perm[i]));2938}2939}2940M = cgetg(l, t_MAT);2941for (i = 1; i < l; i++) gel(M,i) = sprk_log_prk1_2(nf, gel(G,i), sprk);2942return M;2943}2944/* Log on bid.gen of generators of P_{1,I pr^{e-1}} / P_{1,I pr^e} (I,pr) = 1,2945* defined implicitly via CRT. 'ind' is the index of pr in modulus2946* factorization */2947GEN2948log_gen_pr(zlog_S *S, long ind, GEN nf, long e)2949{2950GEN Uind = gel(S->U, ind);2951if (e == 1) retmkmat( gel(Uind,1) );2952return ZM_mul(Uind, sprk_log_gen_pr2(nf, gel(S->sprk,ind), e));2953}2954GEN2955sprk_log_gen_pr(GEN nf, GEN sprk, long e)2956{2957if (e == 1)2958{2959long n = lg(sprk_get_cyc(sprk))-1;2960retmkmat(col_ei(n, 1));2961}2962return sprk_log_gen_pr2(nf, sprk, e);2963}2964/* a = 1 mod pr */2965GEN2966sprk_log_prk1(GEN nf, GEN a, GEN sprk)2967{2968if (lg(sprk) == 5) return mkcol(gen_0); /* mod pr */2969return sprk_log_prk1_2(nf, a, sprk);2970}2971/* Log on bid.gen of generator of P_{1,f} / P_{1,f v[index]}2972* v = vector of r1 real places */2973GEN2974log_gen_arch(zlog_S *S, long index)2975{2976GEN U = gel(S->U, lg(S->U)-1);2977return gel(U, index);2978}29792980/* compute bid.clgp: [h,cyc] or [h,cyc,gen] */2981static GEN2982bid_grp(GEN nf, GEN U, GEN cyc, GEN g, GEN F, GEN sarch)2983{2984GEN G, h = ZV_prod(cyc);2985long c;2986if (!U) return mkvec2(h,cyc);2987c = lg(U);2988G = cgetg(c,t_VEC);2989if (c > 1)2990{2991GEN U0, Uoo, EX = cyc_get_expo(cyc); /* exponent of bid */2992long i, hU = nbrows(U), nba = lg(sarch_get_cyc(sarch))-1; /* #f_oo */2993if (!nba) { U0 = U; Uoo = NULL; }2994else if (nba == hU) { U0 = NULL; Uoo = U; }2995else2996{2997U0 = rowslice(U, 1, hU-nba);2998Uoo = rowslice(U, hU-nba+1, hU);2999}3000for (i = 1; i < c; i++)3001{3002GEN t = gen_1;3003if (U0) t = famat_to_nf_modideal_coprime(nf, g, gel(U0,i), F, EX);3004if (Uoo) t = set_sign_mod_divisor(nf, ZV_to_Flv(gel(Uoo,i),2), t, sarch);3005gel(G,i) = t;3006}3007}3008return mkvec3(h, cyc, G);3009}30103011/* remove prime ideals of norm 2 with exponent 1 from factorization */3012static GEN3013famat_strip2(GEN fa)3014{3015GEN P = gel(fa,1), E = gel(fa,2), Q, F;3016long l = lg(P), i, j;3017Q = cgetg(l, t_COL);3018F = cgetg(l, t_COL);3019for (i = j = 1; i < l; i++)3020{3021GEN pr = gel(P,i), e = gel(E,i);3022if (!absequaliu(pr_get_p(pr), 2) || itou(e) != 1 || pr_get_f(pr) != 1)3023{3024gel(Q,j) = pr;3025gel(F,j) = e; j++;3026}3027}3028setlg(Q,j);3029setlg(F,j); return mkmat2(Q,F);3030}3031static int3032checkarchp(GEN v, long r1)3033{3034long i, l = lg(v);3035pari_sp av = avma;3036GEN p;3037if (l == 1) return 1;3038if (l == 2) return v[1] > 0 && v[1] <= r1;3039p = zero_zv(r1);3040for (i = 1; i < l; i++)3041{3042long j = v[i];3043if (j <= 0 || j > r1 || p[j]) return gc_long(av, 0);3044p[j] = 1;3045}3046return gc_long(av, 1);3047}30483049/* Compute [[ideal,arch], [h,[cyc],[gen]], idealfact, [liste], U]3050flag may include nf_GEN | nf_INIT */3051static GEN3052Idealstarmod_i(GEN nf, GEN ideal, long flag, GEN MOD)3053{3054long i, nbp, R1;3055GEN y, cyc, U, u1 = NULL, fa, fa2, sprk, x, arch, archp, E, P, sarch, gen;30563057nf = checknf(nf);3058R1 = nf_get_r1(nf);3059if (typ(ideal) == t_VEC && lg(ideal) == 3)3060{3061arch = gel(ideal,2);3062ideal= gel(ideal,1);3063switch(typ(arch))3064{3065case t_VEC:3066if (lg(arch) != R1+1)3067pari_err_TYPE("Idealstar [incorrect archimedean component]",arch);3068archp = vec01_to_indices(arch);3069break;3070case t_VECSMALL:3071if (!checkarchp(arch, R1))3072pari_err_TYPE("Idealstar [incorrect archimedean component]",arch);3073archp = arch;3074arch = indices_to_vec01(archp, R1);3075break;3076default:3077pari_err_TYPE("Idealstar [incorrect archimedean component]",arch);3078return NULL;/*LCOV_EXCL_LINE*/3079}3080}3081else3082{3083arch = zerovec(R1);3084archp = cgetg(1, t_VECSMALL);3085}3086if (MOD)3087{3088if (typ(MOD) != t_INT) pari_err_TYPE("bnrinit [incorrect cycmod]", MOD);3089if (mpodd(MOD) && lg(archp) != 1)3090MOD = shifti(MOD, 1); /* ensure elements of G^MOD are >> 0 */3091}3092if (is_nf_factor(ideal))3093{3094fa = ideal;3095x = factorbackprime(nf, gel(fa,1), gel(fa,2));3096}3097else3098{3099fa = idealfactor(nf, ideal);3100x = ideal;3101}3102if (typ(x) != t_MAT) x = idealhnf_shallow(nf, x);3103if (lg(x) == 1) pari_err_DOMAIN("Idealstar", "ideal","=",gen_0,x);3104if (typ(gcoeff(x,1,1)) != t_INT)3105pari_err_DOMAIN("Idealstar","denominator(ideal)", "!=",gen_1,x);3106sarch = nfarchstar(nf, x, archp);3107fa2 = famat_strip2(fa);3108P = gel(fa2,1);3109E = gel(fa2,2);3110nbp = lg(P)-1;3111sprk = cgetg(nbp+1,t_VEC);3112if (nbp)3113{3114GEN t = (lg(gel(fa,1))==2)? NULL: x; /* beware fa != fa2 */3115cyc = cgetg(nbp+2,t_VEC);3116gen = cgetg(nbp+1,t_VEC);3117for (i = 1; i <= nbp; i++)3118{3119GEN L = sprkinit(nf, gel(P,i), itou(gel(E,i)), t, MOD);3120gel(sprk,i) = L;3121gel(cyc,i) = sprk_get_cyc(L);3122/* true gens are congruent to those mod x AND positive at archp */3123gel(gen,i) = sprk_get_gen(L);3124}3125gel(cyc,i) = sarch_get_cyc(sarch);3126cyc = shallowconcat1(cyc);3127gen = shallowconcat1(gen);3128cyc = ZV_snf_group(cyc, &U, (flag & nf_GEN)? &u1: NULL);3129}3130else3131{3132cyc = sarch_get_cyc(sarch);3133gen = cgetg(1,t_VEC);3134U = matid(lg(cyc)-1);3135if (flag & nf_GEN) u1 = U;3136}3137y = bid_grp(nf, u1, cyc, gen, x, sarch);3138if (!(flag & nf_INIT)) return y;3139U = split_U(U, sprk);3140return mkvec5(mkvec2(x, arch), y, mkvec2(fa,fa2), mkvec2(sprk, sarch), U);3141}3142GEN3143Idealstarmod(GEN nf, GEN ideal, long flag, GEN MOD)3144{3145pari_sp av = avma;3146if (!nf) nf = nfinit(pol_x(0), DEFAULTPREC);3147return gerepilecopy(av, Idealstarmod_i(nf, ideal, flag, MOD));3148}3149GEN3150Idealstar(GEN nf, GEN ideal, long flag) { return Idealstarmod(nf, ideal, flag, NULL); }3151GEN3152Idealstarprk(GEN nf, GEN pr, long k, long flag)3153{3154pari_sp av = avma;3155GEN z = Idealstarmod_i(nf, mkmat2(mkcol(pr),mkcols(k)), flag, NULL);3156return gerepilecopy(av, z);3157}31583159/* FIXME: obsolete */3160GEN3161zidealstarinitgen(GEN nf, GEN ideal)3162{ return Idealstar(nf,ideal, nf_INIT|nf_GEN); }3163GEN3164zidealstarinit(GEN nf, GEN ideal)3165{ return Idealstar(nf,ideal, nf_INIT); }3166GEN3167zidealstar(GEN nf, GEN ideal)3168{ return Idealstar(nf,ideal, nf_GEN); }31693170GEN3171idealstarmod(GEN nf, GEN ideal, long flag, GEN MOD)3172{3173switch(flag)3174{3175case 0: return Idealstarmod(nf,ideal, nf_GEN, MOD);3176case 1: return Idealstarmod(nf,ideal, nf_INIT, MOD);3177case 2: return Idealstarmod(nf,ideal, nf_INIT|nf_GEN, MOD);3178default: pari_err_FLAG("idealstar");3179}3180return NULL; /* LCOV_EXCL_LINE */3181}3182GEN3183idealstar0(GEN nf, GEN ideal,long flag) { return idealstarmod(nf, ideal, flag, NULL); }31843185void3186check_nfelt(GEN x, GEN *den)3187{3188long l = lg(x), i;3189GEN t, d = NULL;3190if (typ(x) != t_COL) pari_err_TYPE("check_nfelt", x);3191for (i=1; i<l; i++)3192{3193t = gel(x,i);3194switch (typ(t))3195{3196case t_INT: break;3197case t_FRAC:3198if (!d) d = gel(t,2); else d = lcmii(d, gel(t,2));3199break;3200default: pari_err_TYPE("check_nfelt", x);3201}3202}3203*den = d;3204}32053206GEN3207vecmodii(GEN x, GEN y)3208{ pari_APPLY_same(modii(gel(x,i), gel(y,i))) }3209GEN3210ZV_snf_gcd(GEN x, GEN mod)3211{ pari_APPLY_same(gcdii(gel(x,i), mod)); }32123213GEN3214vecmoduu(GEN x, GEN y)3215{ pari_APPLY_ulong(uel(x,i) % uel(y,i)) }32163217/* assume a true bnf and bid */3218GEN3219ideallog_units0(GEN bnf, GEN bid, GEN MOD)3220{3221GEN nf = bnf_get_nf(bnf), D, y, C, cyc;3222long j, lU = lg(bnf_get_logfu(bnf)); /* r1+r2 */3223zlog_S S;3224init_zlog_mod(&S, bid, MOD);3225if (!S.hU) return zeromat(0,lU);3226cyc = bid_get_cyc(bid);3227if (MOD) cyc = ZV_snf_gcd(cyc, MOD);3228D = nfsign_fu(bnf, bid_get_archp(bid));3229y = cgetg(lU, t_MAT);3230if ((C = bnf_build_cheapfu(bnf)))3231{ for (j = 1; j < lU; j++) gel(y,j) = zlog(nf, gel(C,j), gel(D,j), &S); }3232else3233{3234long i, l = lg(S.U), l0 = lg(S.sprk);3235GEN X, U;3236if (!(C = bnf_compactfu_mat(bnf))) bnf_build_units(bnf); /* error */3237X = gel(C,1); U = gel(C,2);3238for (j = 1; j < lU; j++) gel(y,j) = cgetg(l, t_COL);3239for (i = 1; i < l0; i++)3240{3241GEN sprk = gel(S.sprk, i);3242GEN Xi = sunits_makecoprime(X, sprk_get_pr(sprk), sprk_get_prk(sprk));3243for (j = 1; j < lU; j++)3244gcoeff(y,i,j) = famat_zlog_pr_coprime(nf, Xi, gel(U,j), sprk, MOD);3245}3246if (l0 != l)3247for (j = 1; j < lU; j++) gcoeff(y,l0,j) = Flc_to_ZC(gel(D,j));3248}3249y = vec_prepend(y, zlog(nf, bnf_get_tuU(bnf), nfsign_tu(bnf, S.archp), &S));3250for (j = 1; j <= lU; j++)3251gel(y,j) = vecmodii(ZMV_ZCV_mul(S.U, gel(y,j)), cyc);3252return y;3253}3254GEN3255ideallog_units(GEN bnf, GEN bid)3256{ return ideallog_units0(bnf, bid, NULL); }3257GEN3258log_prk_units(GEN nf, GEN D, GEN sprk)3259{3260GEN L, Ltu = log_prk(nf, gel(D,1), sprk, NULL);3261D = gel(D,2);3262if (lg(D) != 3 || typ(gel(D,2)) != t_MAT) L = veclog_prk(nf, D, sprk);3263else3264{3265GEN X = gel(D,1), U = gel(D,2);3266long j, lU = lg(U);3267X = sunits_makecoprime(X, sprk_get_pr(sprk), sprk_get_prk(sprk));3268L = cgetg(lU, t_MAT);3269for (j = 1; j < lU; j++)3270gel(L,j) = famat_zlog_pr_coprime(nf, X, gel(U,j), sprk, NULL);3271}3272return vec_prepend(L, Ltu);3273}32743275static GEN3276ideallog_i(GEN nf, GEN x, zlog_S *S)3277{3278pari_sp av = avma;3279GEN y;3280if (!S->hU) return cgetg(1, t_COL);3281if (typ(x) == t_MAT)3282y = famat_zlog(nf, x, NULL, S);3283else3284y = zlog(nf, x, NULL, S);3285y = ZMV_ZCV_mul(S->U, y);3286return gerepileupto(av, vecmodii(y, bid_get_cyc(S->bid)));3287}3288GEN3289ideallogmod(GEN nf, GEN x, GEN bid, GEN mod)3290{3291zlog_S S;3292if (!nf)3293{3294if (mod) pari_err_IMPL("Zideallogmod");3295return Zideallog(bid, x);3296}3297checkbid(bid); init_zlog_mod(&S, bid, mod);3298return ideallog_i(checknf(nf), x, &S);3299}3300GEN3301ideallog(GEN nf, GEN x, GEN bid) { return ideallogmod(nf, x, bid, NULL); }33023303/*************************************************************************/3304/** **/3305/** JOIN BID STRUCTURES, IDEAL LISTS **/3306/** **/3307/*************************************************************************/3308/* bid1, bid2: for coprime modules m1 and m2 (without arch. part).3309* Output: bid for m1 m2 */3310static GEN3311join_bid(GEN nf, GEN bid1, GEN bid2)3312{3313pari_sp av = avma;3314long nbgen, l1,l2;3315GEN I1,I2, G1,G2, sprk1,sprk2, cyc1,cyc2, sarch;3316GEN sprk, fa,fa2, U, cyc, y, u1 = NULL, x, gen;33173318I1 = bid_get_ideal(bid1);3319I2 = bid_get_ideal(bid2);3320if (gequal1(gcoeff(I1,1,1))) return bid2; /* frequent trivial case */3321G1 = bid_get_grp(bid1);3322G2 = bid_get_grp(bid2);3323x = idealmul(nf, I1,I2);3324fa = famat_mul_shallow(bid_get_fact(bid1), bid_get_fact(bid2));3325fa2= famat_mul_shallow(bid_get_fact2(bid1), bid_get_fact2(bid2));3326sprk1 = bid_get_sprk(bid1);3327sprk2 = bid_get_sprk(bid2);3328sprk = shallowconcat(sprk1, sprk2);33293330cyc1 = abgrp_get_cyc(G1); l1 = lg(cyc1);3331cyc2 = abgrp_get_cyc(G2); l2 = lg(cyc2);3332gen = (lg(G1)>3 && lg(G2)>3)? gen_1: NULL;3333nbgen = l1+l2-2;3334cyc = ZV_snf_group(shallowconcat(cyc1,cyc2), &U, gen? &u1: NULL);3335if (nbgen)3336{3337GEN U1 = bid_get_U(bid1), U2 = bid_get_U(bid2);3338U1 = l1==1? const_vec(lg(sprk1), cgetg(1,t_MAT))3339: ZM_ZMV_mul(vecslice(U, 1, l1-1), U1);3340U2 = l2==1? const_vec(lg(sprk2), cgetg(1,t_MAT))3341: ZM_ZMV_mul(vecslice(U, l1, nbgen), U2);3342U = shallowconcat(U1, U2);3343}3344else3345U = const_vec(lg(sprk), cgetg(1,t_MAT));33463347if (gen)3348{3349GEN uv = zkchinese1init2(nf, I2, I1, x);3350gen = shallowconcat(zkVchinese1(gel(uv,1), abgrp_get_gen(G1)),3351zkVchinese1(gel(uv,2), abgrp_get_gen(G2)));3352}3353sarch = bid_get_sarch(bid1); /* trivial */3354y = bid_grp(nf, u1, cyc, gen, x, sarch);3355x = mkvec2(x, bid_get_arch(bid1));3356y = mkvec5(x, y, mkvec2(fa, fa2), mkvec2(sprk, sarch), U);3357return gerepilecopy(av,y);3358}33593360typedef struct _ideal_data {3361GEN nf, emb, L, pr, prL, sgnU, archp;3362} ideal_data;33633364/* z <- ( z | f(v[i])_{i=1..#v} ) */3365static void3366concat_join(GEN *pz, GEN v, GEN (*f)(ideal_data*,GEN), ideal_data *data)3367{3368long i, nz, lv = lg(v);3369GEN z, Z;3370if (lv == 1) return;3371z = *pz; nz = lg(z)-1;3372*pz = Z = cgetg(lv + nz, typ(z));3373for (i = 1; i <=nz; i++) gel(Z,i) = gel(z,i);3374Z += nz;3375for (i = 1; i < lv; i++) gel(Z,i) = f(data, gel(v,i));3376}3377static GEN3378join_idealinit(ideal_data *D, GEN x)3379{ return join_bid(D->nf, x, D->prL); }3380static GEN3381join_ideal(ideal_data *D, GEN x)3382{ return idealmulpowprime(D->nf, x, D->pr, D->L); }3383static GEN3384join_unit(ideal_data *D, GEN x)3385{3386GEN bid = join_idealinit(D, gel(x,1)), u = gel(x,2), v = mkvec(D->emb);3387if (lg(u) != 1) v = shallowconcat(u, v);3388return mkvec2(bid, v);3389}33903391GEN3392log_prk_units_init(GEN bnf)3393{3394GEN U = bnf_has_fu(bnf);3395if (U) U = matalgtobasis(bnf_get_nf(bnf), U);3396else if (!(U = bnf_compactfu_mat(bnf))) (void)bnf_build_units(bnf);3397return mkvec2(bnf_get_tuU(bnf), U);3398}3399/* flag & nf_GEN : generators, otherwise no3400* flag &2 : units, otherwise no3401* flag &4 : ideals in HNF, otherwise bid3402* flag &8 : omit ideals which cannot be conductors (pr^1 with Npr=2) */3403static GEN3404Ideallist(GEN bnf, ulong bound, long flag)3405{3406const long do_units = flag & 2, big_id = !(flag & 4), cond = flag & 8;3407const long istar_flag = (flag & nf_GEN) | nf_INIT;3408pari_sp av;3409long i, j;3410GEN nf, z, p, fa, id, BOUND, U, empty = cgetg(1,t_VEC);3411forprime_t S;3412ideal_data ID;3413GEN (*join_z)(ideal_data*, GEN);34143415if (do_units)3416{3417bnf = checkbnf(bnf);3418nf = bnf_get_nf(bnf);3419join_z = &join_unit;3420}3421else3422{3423nf = checknf(bnf);3424join_z = big_id? &join_idealinit: &join_ideal;3425}3426if ((long)bound <= 0) return empty;3427id = matid(nf_get_degree(nf));3428if (big_id) id = Idealstar(nf,id, istar_flag);34293430/* z[i] will contain all "objects" of norm i. Depending on flag, this means3431* an ideal, a bid, or a couple [bid, log(units)]. Such objects are stored3432* in vectors, computed one primary component at a time; join_z3433* reconstructs the global object */3434BOUND = utoipos(bound);3435z = const_vec(bound, empty);3436U = do_units? log_prk_units_init(bnf): NULL;3437gel(z,1) = mkvec(U? mkvec2(id, empty): id);3438ID.nf = nf;34393440p = cgetipos(3);3441u_forprime_init(&S, 2, bound);3442av = avma;3443while ((p[2] = u_forprime_next(&S)))3444{3445if (DEBUGLEVEL>1) err_printf("%ld ",p[2]);3446fa = idealprimedec_limit_norm(nf, p, BOUND);3447for (j = 1; j < lg(fa); j++)3448{3449GEN pr = gel(fa,j), z2 = leafcopy(z);3450ulong Q, q = upr_norm(pr);3451long l;3452ID.pr = ID.prL = pr;3453if (cond && q == 2) { l = 2; Q = 4; } else { l = 1; Q = q; }3454for (; Q <= bound; l++, Q *= q) /* add pr^l */3455{3456ulong iQ;3457ID.L = utoipos(l);3458if (big_id) {3459ID.prL = Idealstarprk(nf, pr, l, istar_flag);3460if (U)3461ID.emb = Q == 2? empty3462: log_prk_units(nf, U, gel(bid_get_sprk(ID.prL),1));3463}3464for (iQ = Q,i = 1; iQ <= bound; iQ += Q,i++)3465concat_join(&gel(z,iQ), gel(z2,i), join_z, &ID);3466}3467}3468if (gc_needed(av,1))3469{3470if(DEBUGMEM>1) pari_warn(warnmem,"Ideallist");3471z = gerepilecopy(av, z);3472}3473}3474return z;3475}3476GEN3477gideallist(GEN bnf, GEN B, long flag)3478{3479pari_sp av = avma;3480if (typ(B) != t_INT)3481{3482B = gfloor(B);3483if (typ(B) != t_INT) pari_err_TYPE("ideallist", B);3484if (signe(B) < 0) B = gen_0;3485}3486if (signe(B) < 0)3487{3488if (flag != 4) pari_err_IMPL("ideallist with bid for single norm");3489return gerepilecopy(av, ideals_by_norm(bnf, absi(B)));3490}3491if (flag < 0 || flag > 15) pari_err_FLAG("ideallist");3492return gerepilecopy(av, Ideallist(bnf, itou(B), flag));3493}3494GEN3495ideallist0(GEN bnf, long bound, long flag)3496{3497pari_sp av = avma;3498if (flag < 0 || flag > 15) pari_err_FLAG("ideallist");3499return gerepilecopy(av, Ideallist(bnf, bound, flag));3500}3501GEN3502ideallist(GEN bnf,long bound) { return ideallist0(bnf,bound,4); }35033504/* bid = for module m (without arch. part), arch = archimedean part.3505* Output: bid for [m,arch] */3506static GEN3507join_bid_arch(GEN nf, GEN bid, GEN archp)3508{3509pari_sp av = avma;3510GEN G, U;3511GEN sprk, cyc, y, u1 = NULL, x, sarch, gen;35123513checkbid(bid);3514G = bid_get_grp(bid);3515x = bid_get_ideal(bid);3516sarch = nfarchstar(nf, bid_get_ideal(bid), archp);3517sprk = bid_get_sprk(bid);35183519gen = (lg(G)>3)? gel(G,3): NULL;3520cyc = diagonal_shallow(shallowconcat(gel(G,2), sarch_get_cyc(sarch)));3521cyc = ZM_snf_group(cyc, &U, gen? &u1: NULL);3522y = bid_grp(nf, u1, cyc, gen, x, sarch);3523U = split_U(U, sprk);3524y = mkvec5(mkvec2(x, archp), y, gel(bid,3), mkvec2(sprk, sarch), U);3525return gerepilecopy(av,y);3526}3527static GEN3528join_arch(ideal_data *D, GEN x) {3529return join_bid_arch(D->nf, x, D->archp);3530}3531static GEN3532join_archunit(ideal_data *D, GEN x) {3533GEN bid = join_arch(D, gel(x,1)), u = gel(x,2), v = mkvec(D->emb);3534if (lg(u) != 1) v = shallowconcat(u, v);3535return mkvec2(bid, v);3536}35373538/* L from ideallist, add archimedean part */3539GEN3540ideallistarch(GEN bnf, GEN L, GEN arch)3541{3542pari_sp av;3543long i, j, l = lg(L), lz;3544GEN v, z, V;3545ideal_data ID;3546GEN (*join_z)(ideal_data*, GEN);35473548if (typ(L) != t_VEC) pari_err_TYPE("ideallistarch",L);3549if (l == 1) return cgetg(1,t_VEC);3550z = gel(L,1);3551if (typ(z) != t_VEC) pari_err_TYPE("ideallistarch",z);3552z = gel(z,1); /* either a bid or [bid,U] */3553ID.nf = checknf(bnf);3554ID.archp = vec01_to_indices(arch);3555if (lg(z) == 3) { /* the latter: do units */3556if (typ(z) != t_VEC) pari_err_TYPE("ideallistarch",z);3557ID.emb = zm_to_ZM( rowpermute(nfsign_units(bnf,NULL,1), ID.archp) );3558join_z = &join_archunit;3559} else3560join_z = &join_arch;3561av = avma; V = cgetg(l, t_VEC);3562for (i = 1; i < l; i++)3563{3564z = gel(L,i); lz = lg(z);3565gel(V,i) = v = cgetg(lz,t_VEC);3566for (j=1; j<lz; j++) gel(v,j) = join_z(&ID, gel(z,j));3567}3568return gerepilecopy(av,V);3569}357035713572