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/* (continued) */18/* */19/*******************************************************************/20#include "pari.h"21#include "paripriv.h"2223#define DEBUGLEVEL DEBUGLEVEL_nf2425/*******************************************************************/26/* */27/* IDEAL OPERATIONS */28/* */29/*******************************************************************/3031/* A valid ideal is either principal (valid nf_element), or prime, or a matrix32* on the integer basis in HNF.33* A prime ideal is of the form [p,a,e,f,b], where the ideal is p.Z_K+a.Z_K,34* p is a rational prime, a belongs to Z_K, e=e(P/p), f=f(P/p), and b35* is Lenstra's constant, such that p.P^(-1)= p Z_K + b Z_K.36*37* An extended ideal is a couple [I,F] where I is an ideal and F is either an38* algebraic number, or a factorization matrix attached to an algebraic number.39* All routines work with either extended ideals or ideals (an omitted F is40* assumed to be factor(1)). All ideals are output in HNF form. */4142/* types and conversions */4344long45idealtyp(GEN *ideal, GEN *arch)46{47GEN x = *ideal;48long t,lx,tx = typ(x);4950if (tx!=t_VEC || lg(x)!=3) *arch = NULL;51else52{53GEN a = gel(x,2);54if (typ(a) == t_MAT && lg(a) != 3)55{ /* allow [;] */56if (lg(a) != 1) pari_err_TYPE("idealtyp [extended ideal]",x);57a = trivial_fact();58}59*arch = a;60x = gel(x,1); tx = typ(x);61}62switch(tx)63{64case t_MAT: lx = lg(x);65if (lx == 1) { t = id_PRINCIPAL; x = gen_0; break; }66if (lx != lgcols(x)) pari_err_TYPE("idealtyp [nonsquare t_MAT]",x);67t = id_MAT;68break;6970case t_VEC: if (lg(x)!=6) pari_err_TYPE("idealtyp",x);71t = id_PRIME; break;7273case t_POL: case t_POLMOD: case t_COL:74case t_INT: case t_FRAC:75t = id_PRINCIPAL; break;76default:77pari_err_TYPE("idealtyp",x);78return 0; /*LCOV_EXCL_LINE*/79}80*ideal = x; return t;81}8283/* true nf; v = [a,x,...], a in Z. Return (a,x) */84GEN85idealhnf_two(GEN nf, GEN v)86{87GEN p = gel(v,1), pi = gel(v,2), m = zk_scalar_or_multable(nf, pi);88if (typ(m) == t_INT) return scalarmat(gcdii(m,p), nf_get_degree(nf));89return ZM_hnfmodid(m, p);90}91/* true nf */92GEN93pr_hnf(GEN nf, GEN pr)94{95GEN p = pr_get_p(pr), m;96if (pr_is_inert(pr)) return scalarmat(p, nf_get_degree(nf));97m = zk_scalar_or_multable(nf, pr_get_gen(pr));98return ZM_hnfmodprime(m, p);99}100101GEN102idealhnf_principal(GEN nf, GEN x)103{104GEN cx;105x = nf_to_scalar_or_basis(nf, x);106switch(typ(x))107{108case t_COL: break;109case t_INT: if (!signe(x)) return cgetg(1,t_MAT);110return scalarmat(absi_shallow(x), nf_get_degree(nf));111case t_FRAC:112return scalarmat(Q_abs_shallow(x), nf_get_degree(nf));113default: pari_err_TYPE("idealhnf",x);114}115x = Q_primitive_part(x, &cx);116RgV_check_ZV(x, "idealhnf");117x = zk_multable(nf, x);118x = ZM_hnfmodid(x, zkmultable_capZ(x));119return cx? ZM_Q_mul(x,cx): x;120}121122/* x integral ideal in t_MAT form, nx columns */123static GEN124vec_mulid(GEN nf, GEN x, long nx, long N)125{126GEN m = cgetg(nx*N + 1, t_MAT);127long i, j, k;128for (i=k=1; i<=nx; i++)129for (j=1; j<=N; j++) gel(m, k++) = zk_ei_mul(nf, gel(x,i),j);130return m;131}132/* true nf */133GEN134idealhnf_shallow(GEN nf, GEN x)135{136long tx = typ(x), lx = lg(x), N;137138/* cannot use idealtyp because here we allow nonsquare matrices */139if (tx == t_VEC && lx == 3) { x = gel(x,1); tx = typ(x); lx = lg(x); }140if (tx == t_VEC && lx == 6) return pr_hnf(nf,x); /* PRIME */141switch(tx)142{143case t_MAT:144{145GEN cx;146long nx = lx-1;147N = nf_get_degree(nf);148if (nx == 0) return cgetg(1, t_MAT);149if (nbrows(x) != N) pari_err_TYPE("idealhnf [wrong dimension]",x);150if (nx == 1) return idealhnf_principal(nf, gel(x,1));151152if (nx == N && RgM_is_ZM(x) && ZM_ishnf(x)) return x;153x = Q_primitive_part(x, &cx);154if (nx < N) x = vec_mulid(nf, x, nx, N);155x = ZM_hnfmod(x, ZM_detmult(x));156return cx? ZM_Q_mul(x,cx): x;157}158case t_QFB:159{160pari_sp av = avma;161GEN u, D = nf_get_disc(nf), T = nf_get_pol(nf), f = nf_get_index(nf);162GEN A = gel(x,1), B = gel(x,2);163N = nf_get_degree(nf);164if (N != 2)165pari_err_TYPE("idealhnf [Qfb for nonquadratic fields]", x);166if (!equalii(qfb_disc(x), D))167pari_err_DOMAIN("idealhnf [Qfb]", "disc(q)", "!=", D, x);168/* x -> A Z + (-B + sqrt(D)) / 2 Z169K = Q[t]/T(t), t^2 + ut + v = 0, u^2 - 4v = Df^2170=> t = (-u + sqrt(D) f)/2171=> sqrt(D)/2 = (t + u/2)/f */172u = gel(T,3);173B = deg1pol_shallow(ginv(f),174gsub(gdiv(u, shifti(f,1)), gdiv(B,gen_2)),175varn(T));176return gerepileupto(av, idealhnf_two(nf, mkvec2(A,B)));177}178default: return idealhnf_principal(nf, x); /* PRINCIPAL */179}180}181GEN182idealhnf(GEN nf, GEN x)183{184pari_sp av = avma;185GEN y = idealhnf_shallow(checknf(nf), x);186return (avma == av)? gcopy(y): gerepileupto(av, y);187}188189/* GP functions */190191GEN192idealtwoelt0(GEN nf, GEN x, GEN a)193{194if (!a) return idealtwoelt(nf,x);195return idealtwoelt2(nf,x,a);196}197198GEN199idealpow0(GEN nf, GEN x, GEN n, long flag)200{201if (flag) return idealpowred(nf,x,n);202return idealpow(nf,x,n);203}204205GEN206idealmul0(GEN nf, GEN x, GEN y, long flag)207{208if (flag) return idealmulred(nf,x,y);209return idealmul(nf,x,y);210}211212GEN213idealdiv0(GEN nf, GEN x, GEN y, long flag)214{215switch(flag)216{217case 0: return idealdiv(nf,x,y);218case 1: return idealdivexact(nf,x,y);219default: pari_err_FLAG("idealdiv");220}221return NULL; /* LCOV_EXCL_LINE */222}223224GEN225idealaddtoone0(GEN nf, GEN arg1, GEN arg2)226{227if (!arg2) return idealaddmultoone(nf,arg1);228return idealaddtoone(nf,arg1,arg2);229}230231/* b not a scalar */232static GEN233hnf_Z_ZC(GEN nf, GEN a, GEN b) { return hnfmodid(zk_multable(nf,b), a); }234/* b not a scalar */235static GEN236hnf_Z_QC(GEN nf, GEN a, GEN b)237{238GEN db;239b = Q_remove_denom(b, &db);240if (db) a = mulii(a, db);241b = hnf_Z_ZC(nf,a,b);242return db? RgM_Rg_div(b, db): b;243}244/* b not a scalar (not point in trying to optimize for this case) */245static GEN246hnf_Q_QC(GEN nf, GEN a, GEN b)247{248GEN da, db;249if (typ(a) == t_INT) return hnf_Z_QC(nf, a, b);250da = gel(a,2);251a = gel(a,1);252b = Q_remove_denom(b, &db);253/* write da = d*A, db = d*B, gcd(A,B) = 1254* gcd(a/(d A), b/(d B)) = gcd(a B, A b) / A B d = gcd(a B, b) / A B d */255if (db)256{257GEN d = gcdii(da,db);258if (!is_pm1(d)) db = diviiexact(db,d); /* B */259if (!is_pm1(db))260{261a = mulii(a, db); /* a B */262da = mulii(da, db); /* A B d = lcm(denom(a),denom(b)) */263}264}265return RgM_Rg_div(hnf_Z_ZC(nf,a,b), da);266}267static GEN268hnf_QC_QC(GEN nf, GEN a, GEN b)269{270GEN da, db, d, x;271a = Q_remove_denom(a, &da);272b = Q_remove_denom(b, &db);273if (da) b = ZC_Z_mul(b, da);274if (db) a = ZC_Z_mul(a, db);275d = mul_denom(da, db);276a = zk_multable(nf,a); da = zkmultable_capZ(a);277b = zk_multable(nf,b); db = zkmultable_capZ(b);278x = ZM_hnfmodid(shallowconcat(a,b), gcdii(da,db));279return d? RgM_Rg_div(x, d): x;280}281static GEN282hnf_Q_Q(GEN nf, GEN a, GEN b) {return scalarmat(Q_gcd(a,b), nf_get_degree(nf));}283GEN284idealhnf0(GEN nf, GEN a, GEN b)285{286long ta, tb;287pari_sp av;288GEN x;289if (!b) return idealhnf(nf,a);290291/* HNF of aZ_K+bZ_K */292av = avma; nf = checknf(nf);293a = nf_to_scalar_or_basis(nf,a); ta = typ(a);294b = nf_to_scalar_or_basis(nf,b); tb = typ(b);295if (ta == t_COL)296x = (tb==t_COL)? hnf_QC_QC(nf, a,b): hnf_Q_QC(nf, b,a);297else298x = (tb==t_COL)? hnf_Q_QC(nf, a,b): hnf_Q_Q(nf, a,b);299return gerepileupto(av, x);300}301302/*******************************************************************/303/* */304/* TWO-ELEMENT FORM */305/* */306/*******************************************************************/307static GEN idealapprfact_i(GEN nf, GEN x, int nored);308309static int310ok_elt(GEN x, GEN xZ, GEN y)311{312pari_sp av = avma;313return gc_bool(av, ZM_equal(x, ZM_hnfmodid(y, xZ)));314}315316static GEN317addmul_col(GEN a, long s, GEN b)318{319long i,l;320if (!s) return a? leafcopy(a): a;321if (!a) return gmulsg(s,b);322l = lg(a);323for (i=1; i<l; i++)324if (signe(gel(b,i))) gel(a,i) = addii(gel(a,i), mulsi(s, gel(b,i)));325return a;326}327328/* a <-- a + s * b, all coeffs integers */329static GEN330addmul_mat(GEN a, long s, GEN b)331{332long j,l;333/* copy otherwise next call corrupts a */334if (!s) return a? RgM_shallowcopy(a): a;335if (!a) return gmulsg(s,b);336l = lg(a);337for (j=1; j<l; j++)338(void)addmul_col(gel(a,j), s, gel(b,j));339return a;340}341342static GEN343get_random_a(GEN nf, GEN x, GEN xZ)344{345pari_sp av;346long i, lm, l = lg(x);347GEN a, z, beta, mul;348349beta= cgetg(l, t_VEC);350mul = cgetg(l, t_VEC); lm = 1; /* = lg(mul) */351/* look for a in x such that a O/xZ = x O/xZ */352for (i = 2; i < l; i++)353{354GEN xi = gel(x,i);355GEN t = FpM_red(zk_multable(nf,xi), xZ); /* ZM, cannot be a scalar */356if (gequal0(t)) continue;357if (ok_elt(x,xZ, t)) return xi;358gel(beta,lm) = xi;359/* mul[i] = { canonical generators for x[i] O/xZ as Z-module } */360gel(mul,lm) = t; lm++;361}362setlg(mul, lm);363setlg(beta,lm);364z = cgetg(lm, t_VECSMALL);365for(av = avma;; set_avma(av))366{367for (a=NULL,i=1; i<lm; i++)368{369long t = random_bits(4) - 7; /* in [-7,8] */370z[i] = t;371a = addmul_mat(a, t, gel(mul,i));372}373/* a = matrix (NOT HNF) of ideal generated by beta.z in O/xZ */374if (a && ok_elt(x,xZ, a)) break;375}376for (a=NULL,i=1; i<lm; i++)377a = addmul_col(a, z[i], gel(beta,i));378return a;379}380381/* x square matrix, assume it is HNF */382static GEN383mat_ideal_two_elt(GEN nf, GEN x)384{385GEN y, a, cx, xZ;386long N = nf_get_degree(nf);387pari_sp av, tetpil;388389if (lg(x)-1 != N) pari_err_DIM("idealtwoelt");390if (N == 2) return mkvec2copy(gcoeff(x,1,1), gel(x,2));391392y = cgetg(3,t_VEC); av = avma;393cx = Q_content(x);394xZ = gcoeff(x,1,1);395if (gequal(xZ, cx)) /* x = (cx) */396{397gel(y,1) = cx;398gel(y,2) = gen_0; return y;399}400if (equali1(cx)) cx = NULL;401else402{403x = Q_div_to_int(x, cx);404xZ = gcoeff(x,1,1);405}406if (N < 6)407a = get_random_a(nf, x, xZ);408else409{410const long FB[] = { _evallg(15+1) | evaltyp(t_VECSMALL),4112, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47412};413GEN P, E, a1 = Z_lsmoothen(xZ, (GEN)FB, &P, &E);414if (!a1) /* factors completely */415a = idealapprfact_i(nf, idealfactor(nf,x), 1);416else if (lg(P) == 1) /* no small factors */417a = get_random_a(nf, x, xZ);418else /* general case */419{420GEN A0, A1, a0, u0, u1, v0, v1, pi0, pi1, t, u;421a0 = diviiexact(xZ, a1);422A0 = ZM_hnfmodid(x, a0); /* smooth part of x */423A1 = ZM_hnfmodid(x, a1); /* cofactor */424pi0 = idealapprfact_i(nf, idealfactor(nf,A0), 1);425pi1 = get_random_a(nf, A1, a1);426(void)bezout(a0, a1, &v0,&v1);427u0 = mulii(a0, v0);428u1 = mulii(a1, v1);429if (typ(pi0) != t_COL) t = addmulii(u0, pi0, u1);430else431{ t = ZC_Z_mul(pi0, u1); gel(t,1) = addii(gel(t,1), u0); }432u = ZC_Z_mul(pi1, u0); gel(u,1) = addii(gel(u,1), u1);433a = nfmuli(nf, centermod(u, xZ), centermod(t, xZ));434}435}436if (cx)437{438a = centermod(a, xZ);439tetpil = avma;440if (typ(cx) == t_INT)441{442gel(y,1) = mulii(xZ, cx);443gel(y,2) = ZC_Z_mul(a, cx);444}445else446{447gel(y,1) = gmul(xZ, cx);448gel(y,2) = RgC_Rg_mul(a, cx);449}450}451else452{453tetpil = avma;454gel(y,1) = icopy(xZ);455gel(y,2) = centermod(a, xZ);456}457gerepilecoeffssp(av,tetpil,y+1,2); return y;458}459460/* Given an ideal x, returns [a,alpha] such that a is in Q,461* x = a Z_K + alpha Z_K, alpha in K^*462* a = 0 or alpha = 0 are possible, but do not try to determine whether463* x is principal. */464GEN465idealtwoelt(GEN nf, GEN x)466{467pari_sp av;468GEN z;469long tx = idealtyp(&x,&z);470nf = checknf(nf);471if (tx == id_MAT) return mat_ideal_two_elt(nf,x);472if (tx == id_PRIME) return mkvec2copy(gel(x,1), gel(x,2));473/* id_PRINCIPAL */474av = avma; x = nf_to_scalar_or_basis(nf, x);475return gerepilecopy(av, typ(x)==t_COL? mkvec2(gen_0,x):476mkvec2(Q_abs_shallow(x),gen_0));477}478479/*******************************************************************/480/* */481/* FACTORIZATION */482/* */483/*******************************************************************/484/* x integral ideal in HNF, Zval = v_p(x \cap Z) > 0; return v_p(Nx) */485static long486idealHNF_norm_pval(GEN x, GEN p, long Zval)487{488long i, v = Zval, l = lg(x);489for (i = 2; i < l; i++) v += Z_pval(gcoeff(x,i,i), p);490return v;491}492493/* x integral in HNF, f0 = partial factorization of a multiple of494* x[1,1] = x\cap Z */495GEN496idealHNF_Z_factor_i(GEN x, GEN f0, GEN *pvN, GEN *pvZ)497{498GEN P, E, vN, vZ, xZ = gcoeff(x,1,1), f = f0? f0: Z_factor(xZ);499long i, l;500P = gel(f,1); l = lg(P);501E = gel(f,2);502*pvN = vN = cgetg(l, t_VECSMALL);503*pvZ = vZ = cgetg(l, t_VECSMALL);504for (i = 1; i < l; i++)505{506GEN p = gel(P,i);507vZ[i] = f0? Z_pval(xZ, p): (long) itou(gel(E,i));508vN[i] = idealHNF_norm_pval(x,p, vZ[i]);509}510return P;511}512/* return P, primes dividing Nx and xZ = x\cap Z, set v_p(Nx), v_p(xZ);513* x integral in HNF */514GEN515idealHNF_Z_factor(GEN x, GEN *pvN, GEN *pvZ)516{ return idealHNF_Z_factor_i(x, NULL, pvN, pvZ); }517518/* v_P(A)*f(P) <= Nval [e.g. Nval = v_p(Norm A)], Zval = v_p(A \cap Z).519* Return v_P(A) */520static long521idealHNF_val(GEN A, GEN P, long Nval, long Zval)522{523long f = pr_get_f(P), vmax, v, e, i, j, k, l;524GEN mul, B, a, y, r, p, pk, cx, vals;525pari_sp av;526527if (Nval < f) return 0;528p = pr_get_p(P);529e = pr_get_e(P);530/* v_P(A) <= max [ e * v_p(A \cap Z), floor[v_p(Nix) / f ] */531vmax = minss(Zval * e, Nval / f);532mul = pr_get_tau(P);533l = lg(mul);534B = cgetg(l,t_MAT);535/* B[1] not needed: v_pr(A[1]) = v_pr(A \cap Z) is known already */536gel(B,1) = gen_0; /* dummy */537for (j = 2; j < l; j++)538{539GEN x = gel(A,j);540gel(B,j) = y = cgetg(l, t_COL);541for (i = 1; i < l; i++)542{ /* compute a = (x.t0)_i, A in HNF ==> x[j+1..l-1] = 0 */543a = mulii(gel(x,1), gcoeff(mul,i,1));544for (k = 2; k <= j; k++) a = addii(a, mulii(gel(x,k), gcoeff(mul,i,k)));545/* p | a ? */546gel(y,i) = dvmdii(a,p,&r); if (signe(r)) return 0;547}548}549vals = cgetg(l, t_VECSMALL);550/* vals[1] not needed */551for (j = 2; j < l; j++)552{553gel(B,j) = Q_primitive_part(gel(B,j), &cx);554vals[j] = cx? 1 + e * Q_pval(cx, p): 1;555}556pk = powiu(p, ceildivuu(vmax, e));557av = avma; y = cgetg(l,t_COL);558/* can compute mod p^ceil((vmax-v)/e) */559for (v = 1; v < vmax; v++)560{ /* we know v_pr(Bj) >= v for all j */561if (e == 1 || (vmax - v) % e == 0) pk = diviiexact(pk, p);562for (j = 2; j < l; j++)563{564GEN x = gel(B,j); if (v < vals[j]) continue;565for (i = 1; i < l; i++)566{567pari_sp av2 = avma;568a = mulii(gel(x,1), gcoeff(mul,i,1));569for (k = 2; k < l; k++) a = addii(a, mulii(gel(x,k), gcoeff(mul,i,k)));570/* a = (x.t_0)_i; p | a ? */571a = dvmdii(a,p,&r); if (signe(r)) return v;572if (lgefint(a) > lgefint(pk)) a = remii(a, pk);573gel(y,i) = gerepileuptoint(av2, a);574}575gel(B,j) = y; y = x;576if (gc_needed(av,3))577{578if(DEBUGMEM>1) pari_warn(warnmem,"idealval");579gerepileall(av,3, &y,&B,&pk);580}581}582}583return v;584}585/* true nf, x != 0 integral ideal in HNF, cx t_INT or NULL,586* FA integer factorization matrix or NULL. Return partial factorization of587* cx * x above primes in FA (complete factorization if !FA)*/588static GEN589idealHNF_factor_i(GEN nf, GEN x, GEN cx, GEN FA)590{591const long N = lg(x)-1;592long i, j, k, l, v;593GEN vN, vZ, vP, vE, vp = idealHNF_Z_factor_i(x, FA, &vN,&vZ);594595l = lg(vp);596i = cx? expi(cx)+1: 1;597vP = cgetg((l+i-2)*N+1, t_COL);598vE = cgetg((l+i-2)*N+1, t_COL);599for (i = k = 1; i < l; i++)600{601GEN L, p = gel(vp,i);602long Nval = vN[i], Zval = vZ[i], vc = cx? Z_pvalrem(cx,p,&cx): 0;603if (vc)604{605L = idealprimedec(nf,p);606if (is_pm1(cx)) cx = NULL;607}608else609L = idealprimedec_limit_f(nf,p,Nval);610for (j = 1; Nval && j < lg(L); j++) /* !Nval => only cx contributes */611{612GEN P = gel(L,j);613pari_sp av = avma;614v = idealHNF_val(x, P, Nval, Zval);615set_avma(av);616Nval -= v*pr_get_f(P);617v += vc * pr_get_e(P); if (!v) continue;618gel(vP,k) = P;619gel(vE,k) = utoipos(v); k++;620}621if (vc) for (; j<lg(L); j++)622{623GEN P = gel(L,j);624gel(vP,k) = P;625gel(vE,k) = utoipos(vc * pr_get_e(P)); k++;626}627}628if (cx && !FA)629{ /* complete factorization */630GEN f = Z_factor(cx), cP = gel(f,1), cE = gel(f,2);631long lc = lg(cP);632for (i=1; i<lc; i++)633{634GEN p = gel(cP,i), L = idealprimedec(nf,p);635long vc = itos(gel(cE,i));636for (j=1; j<lg(L); j++)637{638GEN P = gel(L,j);639gel(vP,k) = P;640gel(vE,k) = utoipos(vc * pr_get_e(P)); k++;641}642}643}644setlg(vP, k);645setlg(vE, k); return mkmat2(vP, vE);646}647/* true nf, x integral ideal */648static GEN649idealHNF_factor(GEN nf, GEN x, ulong lim)650{651GEN cx, F = NULL;652if (lim)653{654GEN P, E;655long i;656/* strict useless because of prime table */657F = absZ_factor_limit(gcoeff(x,1,1), lim);658P = gel(F,1);659E = gel(F,2);660/* filter out entries > lim */661for (i = lg(P)-1; i; i--)662if (cmpiu(gel(P,i), lim) <= 0) break;663setlg(P, i+1);664setlg(E, i+1);665}666x = Q_primitive_part(x, &cx);667return idealHNF_factor_i(nf, x, cx, F);668}669/* c * vector(#L,i,L[i].e), assume results fit in ulong */670static GEN671prV_e_muls(GEN L, long c)672{673long j, l = lg(L);674GEN z = cgetg(l, t_COL);675for (j = 1; j < l; j++) gel(z,j) = stoi(c * pr_get_e(gel(L,j)));676return z;677}678/* true nf, y in Q */679static GEN680Q_nffactor(GEN nf, GEN y, ulong lim)681{682GEN f, P, E;683long l, i;684if (typ(y) == t_INT)685{686if (!signe(y)) pari_err_DOMAIN("idealfactor", "ideal", "=",gen_0,y);687if (is_pm1(y)) return trivial_fact();688}689y = Q_abs_shallow(y);690if (!lim) f = Q_factor(y);691else692{693f = Q_factor_limit(y, lim);694P = gel(f,1);695E = gel(f,2);696for (i = lg(P)-1; i > 0; i--)697if (abscmpiu(gel(P,i), lim) < 0) break;698setlg(P,i+1); setlg(E,i+1);699}700P = gel(f,1); l = lg(P); if (l == 1) return f;701E = gel(f,2);702for (i = 1; i < l; i++)703{704gel(P,i) = idealprimedec(nf, gel(P,i));705gel(E,i) = prV_e_muls(gel(P,i), itos(gel(E,i)));706}707P = shallowconcat1(P); gel(f,1) = P; settyp(P, t_COL);708E = shallowconcat1(E); gel(f,2) = E; return f;709}710711GEN712idealfactor_partial(GEN nf, GEN x, GEN L)713{714pari_sp av = avma;715long i, j, l;716GEN P, E;717if (!L) return idealfactor(nf, x);718if (typ(L) == t_INT) return idealfactor_limit(nf, x, itou(L));719l = lg(L); if (l == 1) return trivial_fact();720P = cgetg(l, t_VEC);721for (i = 1; i < l; i++)722{723GEN p = gel(L,i);724gel(P,i) = typ(p) == t_INT? idealprimedec(nf, p): mkvec(p);725}726P = shallowconcat1(P); settyp(P, t_COL);727P = gen_sort_uniq(P, (void*)&cmp_prime_ideal, &cmp_nodata);728E = cgetg_copy(P, &l);729for (i = j = 1; i < l; i++)730{731long v = idealval(nf, x, gel(P,i));732if (v) { gel(P,j) = gel(P,i); gel(E,j) = stoi(v); j++; }733}734setlg(P,j);735setlg(E,j); return gerepilecopy(av, mkmat2(P, E));736}737GEN738idealfactor_limit(GEN nf, GEN x, ulong lim)739{740pari_sp av = avma;741GEN fa, y;742long tx = idealtyp(&x,&y);743744if (tx == id_PRIME)745{746if (lim && abscmpiu(pr_get_p(x), lim) >= 0) return trivial_fact();747retmkmat2(mkcolcopy(x), mkcol(gen_1));748}749nf = checknf(nf);750if (tx == id_PRINCIPAL)751{752y = nf_to_scalar_or_basis(nf, x);753if (typ(y) != t_COL) return gerepilecopy(av, Q_nffactor(nf, y, lim));754}755y = idealnumden(nf, x);756fa = idealHNF_factor(nf, gel(y,1), lim);757if (!isint1(gel(y,2)))758fa = famat_div_shallow(fa, idealHNF_factor(nf, gel(y,2), lim));759fa = gerepilecopy(av, fa);760return sort_factor(fa, (void*)&cmp_prime_ideal, &cmp_nodata);761}762GEN763idealfactor(GEN nf, GEN x) { return idealfactor_limit(nf, x, 0); }764GEN765gpidealfactor(GEN nf, GEN x, GEN lim)766{767ulong L = 0;768if (lim)769{770if (typ(lim) != t_INT || signe(lim) < 0) pari_err_FLAG("idealfactor");771L = itou(lim);772}773return idealfactor_limit(nf, x, L);774}775776static GEN777ramified_root(GEN nf, GEN R, GEN A, long n)778{779GEN v, P = gel(idealfactor(nf, R), 1);780long i, l = lg(P);781v = cgetg(l, t_VECSMALL);782for (i = 1; i < l; i++)783{784long w = idealval(nf, A, gel(P,i));785if (w % n) return NULL;786v[i] = w / n;787}788return idealfactorback(nf, P, v, 0);789}790static int791ramified_root_simple(GEN nf, long n, GEN P, GEN v)792{793long i, l = lg(v);794for (i = 1; i < l; i++) if (v[i])795{796GEN vpr = idealprimedec(nf, gel(P,i));797long lpr = lg(vpr), j;798for (j = 1; j < lpr; j++)799{800long e = pr_get_e(gel(vpr,j));801if ((e * v[i]) % n) return 0;802}803}804return 1;805}806/* true nf; A is assumed to be the n-th power of an integral ideal,807* return its n-th root; n > 1 */808static long809idealsqrtn_int(GEN nf, GEN A, long n, GEN *pB)810{811GEN C, root;812long i, l;813814if (typ(A) == t_INT) /* > 0 */815{816GEN P = nf_get_ramified_primes(nf), v, q;817l = lg(P); v = cgetg(l, t_VECSMALL);818for (i = 1; i < l; i++) v[i] = Z_pvalrem(A, gel(P,i), &A);819C = gen_1;820if (!isint1(A) && !Z_ispowerall(A, n, pB? &C: NULL)) return 0;821if (!pB) return ramified_root_simple(nf, n, P, v);822q = factorback2(P, v);823root = ramified_root(nf, q, q, n);824if (!root) return 0;825if (!equali1(C)) root = isint1(root)? C: ZM_Z_mul(root, C);826*pB = root; return 1;827}828/* compute valuations at ramified primes */829root = ramified_root(nf, idealadd(nf, nf_get_diff(nf), A), A, n);830if (!root) return 0;831/* remove ramified primes */832if (isint1(root))833root = matid(nf_get_degree(nf));834else835A = idealdivexact(nf, A, idealpows(nf,root,n));836A = Q_primitive_part(A, &C);837if (C)838{839if (!Z_ispowerall(C,n,&C)) return 0;840if (pB) root = ZM_Z_mul(root, C);841}842843/* compute final n-th root, at most degree(nf)-1 iterations */844for (i = 0;; i++)845{846GEN J, b, a = gcoeff(A,1,1); /* A \cap Z */847if (is_pm1(a)) break;848if (!Z_ispowerall(a,n,&b)) return 0;849J = idealadd(nf, b, A);850A = idealdivexact(nf, idealpows(nf,J,n), A);851/* div and not divexact here */852if (pB) root = odd(i)? idealdiv(nf, root, J): idealmul(nf, root, J);853}854if (pB) *pB = root;855return 1;856}857858/* A is assumed to be the n-th power of an ideal in nf859returns its n-th root. */860long861idealispower(GEN nf, GEN A, long n, GEN *pB)862{863pari_sp av = avma;864GEN v, N, D;865nf = checknf(nf);866if (n <= 0) pari_err_DOMAIN("idealispower", "n", "<=", gen_0, stoi(n));867if (n == 1) { if (pB) *pB = idealhnf(nf,A); return 1; }868v = idealnumden(nf,A);869if (gequal0(gel(v,1))) { set_avma(av); if (pB) *pB = cgetg(1,t_MAT); return 1; }870if (!idealsqrtn_int(nf, gel(v,1), n, pB? &N: NULL)) return 0;871if (!idealsqrtn_int(nf, gel(v,2), n, pB? &D: NULL)) return 0;872if (pB) *pB = gerepileupto(av, idealdiv(nf,N,D)); else set_avma(av);873return 1;874}875876/* x t_INT or integral nonzero ideal in HNF */877static GEN878idealredmodpower_i(GEN nf, GEN x, ulong k, ulong B)879{880GEN cx, y, U, N, F, Q;881if (typ(x) == t_INT)882{883if (!signe(x) || is_pm1(x)) return gen_1;884F = Z_factor_limit(x, B);885gel(F,2) = gdiventgs(gel(F,2), k);886return ginv(factorback(F));887}888N = gcoeff(x,1,1); if (is_pm1(N)) return gen_1;889F = absZ_factor_limit_strict(N, B, &U);890if (U)891{892GEN M = powii(gel(U,1), gel(U,2));893y = hnfmodid(x, M); /* coprime part to B! */894if (!idealispower(nf, y, k, &U)) U = NULL;895x = hnfmodid(x, diviiexact(N, M));896}897/* x = B-smooth part of initial x */898x = Q_primitive_part(x, &cx);899F = idealHNF_factor_i(nf, x, cx, F);900gel(F,2) = gdiventgs(gel(F,2), k);901Q = idealfactorback(nf, gel(F,1), gel(F,2), 0);902if (U) Q = idealmul(nf,Q,U);903if (typ(Q) == t_INT) return Q;904y = idealred_elt(nf, idealHNF_inv_Z(nf, Q));905return gdiv(y, gcoeff(Q,1,1));906}907GEN908idealredmodpower(GEN nf, GEN x, ulong n, ulong B)909{910pari_sp av = avma;911GEN a, b;912nf = checknf(nf);913if (!n) pari_err_DOMAIN("idealredmodpower","n", "=", gen_0, gen_0);914x = idealnumden(nf, x);915a = gel(x,1);916if (isintzero(a)) { set_avma(av); return gen_1; }917a = idealredmodpower_i(nf, gel(x,1), n, B);918b = idealredmodpower_i(nf, gel(x,2), n, B);919if (!isint1(b)) a = nf_to_scalar_or_basis(nf, nfdiv(nf, a, b));920return gerepilecopy(av, a);921}922923/* P prime ideal in idealprimedec format. Return valuation(A) at P */924long925idealval(GEN nf, GEN A, GEN P)926{927pari_sp av = avma;928GEN a, p, cA;929long vcA, v, Zval, tx = idealtyp(&A,&a);930931if (tx == id_PRINCIPAL) return nfval(nf,A,P);932checkprid(P);933if (tx == id_PRIME) return pr_equal(P, A)? 1: 0;934/* id_MAT */935nf = checknf(nf);936A = Q_primitive_part(A, &cA);937p = pr_get_p(P);938vcA = cA? Q_pval(cA,p): 0;939if (pr_is_inert(P)) return gc_long(av,vcA);940Zval = Z_pval(gcoeff(A,1,1), p);941if (!Zval) v = 0;942else943{944long Nval = idealHNF_norm_pval(A, p, Zval);945v = idealHNF_val(A, P, Nval, Zval);946}947return gc_long(av, vcA? v + vcA*pr_get_e(P): v);948}949GEN950gpidealval(GEN nf, GEN ix, GEN P)951{952long v = idealval(nf,ix,P);953return v == LONG_MAX? mkoo(): stoi(v);954}955956/* gcd and generalized Bezout */957958GEN959idealadd(GEN nf, GEN x, GEN y)960{961pari_sp av = avma;962long tx, ty;963GEN z, a, dx, dy, dz;964965tx = idealtyp(&x,&z);966ty = idealtyp(&y,&z); nf = checknf(nf);967if (tx != id_MAT) x = idealhnf_shallow(nf,x);968if (ty != id_MAT) y = idealhnf_shallow(nf,y);969if (lg(x) == 1) return gerepilecopy(av,y);970if (lg(y) == 1) return gerepilecopy(av,x); /* check for 0 ideal */971dx = Q_denom(x);972dy = Q_denom(y); dz = lcmii(dx,dy);973if (is_pm1(dz)) dz = NULL; else {974x = Q_muli_to_int(x, dz);975y = Q_muli_to_int(y, dz);976}977a = gcdii(gcoeff(x,1,1), gcoeff(y,1,1));978if (is_pm1(a))979{980long N = lg(x)-1;981if (!dz) { set_avma(av); return matid(N); }982return gerepileupto(av, scalarmat(ginv(dz), N));983}984z = ZM_hnfmodid(shallowconcat(x,y), a);985if (dz) z = RgM_Rg_div(z,dz);986return gerepileupto(av,z);987}988989static GEN990trivial_merge(GEN x)991{ return (lg(x) == 1 || !is_pm1(gcoeff(x,1,1)))? NULL: gen_1; }992/* true nf */993static GEN994_idealaddtoone(GEN nf, GEN x, GEN y, long red)995{996GEN a;997long tx = idealtyp(&x, &a/*junk*/);998long ty = idealtyp(&y, &a/*junk*/);999long ea;1000if (tx != id_MAT) x = idealhnf_shallow(nf, x);1001if (ty != id_MAT) y = idealhnf_shallow(nf, y);1002if (lg(x) == 1)1003a = trivial_merge(y);1004else if (lg(y) == 1)1005a = trivial_merge(x);1006else1007a = hnfmerge_get_1(x, y);1008if (!a) pari_err_COPRIME("idealaddtoone",x,y);1009if (red && (ea = gexpo(a)) > 10)1010{1011GEN b = (typ(a) == t_COL)? a: scalarcol_shallow(a, nf_get_degree(nf));1012b = ZC_reducemodlll(b, idealHNF_mul(nf,x,y));1013if (gexpo(b) < ea) a = b;1014}1015return a;1016}1017/* true nf */1018GEN1019idealaddtoone_i(GEN nf, GEN x, GEN y)1020{ return _idealaddtoone(nf, x, y, 1); }1021/* true nf */1022GEN1023idealaddtoone_raw(GEN nf, GEN x, GEN y)1024{ return _idealaddtoone(nf, x, y, 0); }10251026GEN1027idealaddtoone(GEN nf, GEN x, GEN y)1028{1029GEN z = cgetg(3,t_VEC), a;1030pari_sp av = avma;1031nf = checknf(nf);1032a = gerepileupto(av, idealaddtoone_i(nf,x,y));1033gel(z,1) = a;1034gel(z,2) = typ(a) == t_COL? Z_ZC_sub(gen_1,a): subui(1,a);1035return z;1036}10371038/* assume elements of list are integral ideals */1039GEN1040idealaddmultoone(GEN nf, GEN list)1041{1042pari_sp av = avma;1043long N, i, l, nz, tx = typ(list);1044GEN H, U, perm, L;10451046nf = checknf(nf); N = nf_get_degree(nf);1047if (!is_vec_t(tx)) pari_err_TYPE("idealaddmultoone",list);1048l = lg(list);1049L = cgetg(l, t_VEC);1050if (l == 1)1051pari_err_DOMAIN("idealaddmultoone", "sum(ideals)", "!=", gen_1, L);1052nz = 0; /* number of nonzero ideals in L */1053for (i=1; i<l; i++)1054{1055GEN I = gel(list,i);1056if (typ(I) != t_MAT) I = idealhnf_shallow(nf,I);1057if (lg(I) != 1)1058{1059nz++; RgM_check_ZM(I,"idealaddmultoone");1060if (lgcols(I) != N+1) pari_err_TYPE("idealaddmultoone [not an ideal]", I);1061}1062gel(L,i) = I;1063}1064H = ZM_hnfperm(shallowconcat1(L), &U, &perm);1065if (lg(H) == 1 || !equali1(gcoeff(H,1,1)))1066pari_err_DOMAIN("idealaddmultoone", "sum(ideals)", "!=", gen_1, L);1067for (i=1; i<=N; i++)1068if (perm[i] == 1) break;1069U = gel(U,(nz-1)*N + i); /* (L[1]|...|L[nz]) U = 1 */1070nz = 0;1071for (i=1; i<l; i++)1072{1073GEN c = gel(L,i);1074if (lg(c) == 1)1075c = gen_0;1076else {1077c = ZM_ZC_mul(c, vecslice(U, nz*N + 1, (nz+1)*N));1078nz++;1079}1080gel(L,i) = c;1081}1082return gerepilecopy(av, L);1083}10841085/* multiplication */10861087/* x integral ideal (without archimedean component) in HNF form1088* y = [a,alpha] corresponds to the integral ideal aZ_K+alpha Z_K, a in Z,1089* alpha a ZV or a ZM (multiplication table). Multiply them */1090static GEN1091idealHNF_mul_two(GEN nf, GEN x, GEN y)1092{1093GEN m, a = gel(y,1), alpha = gel(y,2);1094long i, N;10951096if (typ(alpha) != t_MAT)1097{1098alpha = zk_scalar_or_multable(nf, alpha);1099if (typ(alpha) == t_INT) /* e.g. y inert ? 0 should not (but may) occur */1100return signe(a)? ZM_Z_mul(x, gcdii(a, alpha)): cgetg(1,t_MAT);1101}1102N = lg(x)-1; m = cgetg((N<<1)+1,t_MAT);1103for (i=1; i<=N; i++) gel(m,i) = ZM_ZC_mul(alpha,gel(x,i));1104for (i=1; i<=N; i++) gel(m,i+N) = ZC_Z_mul(gel(x,i), a);1105return ZM_hnfmodid(m, mulii(a, gcoeff(x,1,1)));1106}11071108/* Assume x and y are integral in HNF form [NOT extended]. Not memory clean.1109* HACK: ideal in y can be of the form [a,b], a in Z, b in Z_K */1110GEN1111idealHNF_mul(GEN nf, GEN x, GEN y)1112{1113GEN z;1114if (typ(y) == t_VEC)1115z = idealHNF_mul_two(nf,x,y);1116else1117{ /* reduce one ideal to two-elt form. The smallest */1118GEN xZ = gcoeff(x,1,1), yZ = gcoeff(y,1,1);1119if (cmpii(xZ, yZ) < 0)1120{1121if (is_pm1(xZ)) return gcopy(y);1122z = idealHNF_mul_two(nf, y, mat_ideal_two_elt(nf,x));1123}1124else1125{1126if (is_pm1(yZ)) return gcopy(x);1127z = idealHNF_mul_two(nf, x, mat_ideal_two_elt(nf,y));1128}1129}1130return z;1131}11321133/* operations on elements in factored form */11341135GEN1136famat_mul_shallow(GEN f, GEN g)1137{1138if (typ(f) != t_MAT) f = to_famat_shallow(f,gen_1);1139if (typ(g) != t_MAT) g = to_famat_shallow(g,gen_1);1140if (lgcols(f) == 1) return g;1141if (lgcols(g) == 1) return f;1142return mkmat2(shallowconcat(gel(f,1), gel(g,1)),1143shallowconcat(gel(f,2), gel(g,2)));1144}1145GEN1146famat_mulpow_shallow(GEN f, GEN g, GEN e)1147{1148if (!signe(e)) return f;1149return famat_mul_shallow(f, famat_pow_shallow(g, e));1150}11511152GEN1153famat_mulpows_shallow(GEN f, GEN g, long e)1154{1155if (e==0) return f;1156return famat_mul_shallow(f, famat_pows_shallow(g, e));1157}11581159GEN1160famat_div_shallow(GEN f, GEN g)1161{ return famat_mul_shallow(f, famat_inv_shallow(g)); }11621163GEN1164to_famat(GEN x, GEN y) { retmkmat2(mkcolcopy(x), mkcolcopy(y)); }1165GEN1166to_famat_shallow(GEN x, GEN y) { return mkmat2(mkcol(x), mkcol(y)); }11671168/* concat the single elt x; not gconcat since x may be a t_COL */1169static GEN1170append(GEN v, GEN x)1171{1172long i, l = lg(v);1173GEN w = cgetg(l+1, typ(v));1174for (i=1; i<l; i++) gel(w,i) = gcopy(gel(v,i));1175gel(w,i) = gcopy(x); return w;1176}1177/* add x^1 to famat f */1178static GEN1179famat_add(GEN f, GEN x)1180{1181GEN h = cgetg(3,t_MAT);1182if (lgcols(f) == 1)1183{1184gel(h,1) = mkcolcopy(x);1185gel(h,2) = mkcol(gen_1);1186}1187else1188{1189gel(h,1) = append(gel(f,1), x);1190gel(h,2) = gconcat(gel(f,2), gen_1);1191}1192return h;1193}1194/* add x^-1 to famat f */1195static GEN1196famat_sub(GEN f, GEN x)1197{1198GEN h = cgetg(3,t_MAT);1199if (lgcols(f) == 1)1200{1201gel(h,1) = mkcolcopy(x);1202gel(h,2) = mkcol(gen_m1);1203}1204else1205{1206gel(h,1) = append(gel(f,1), x);1207gel(h,2) = gconcat(gel(f,2), gen_m1);1208}1209return h;1210}12111212GEN1213famat_mul(GEN f, GEN g)1214{1215GEN h;1216if (typ(g) != t_MAT) {1217if (typ(f) == t_MAT) return famat_add(f, g);1218h = cgetg(3, t_MAT);1219gel(h,1) = mkcol2(gcopy(f), gcopy(g));1220gel(h,2) = mkcol2(gen_1, gen_1);1221}1222if (typ(f) != t_MAT) return famat_add(g, f);1223if (lgcols(f) == 1) return gcopy(g);1224if (lgcols(g) == 1) return gcopy(f);1225h = cgetg(3,t_MAT);1226gel(h,1) = gconcat(gel(f,1), gel(g,1));1227gel(h,2) = gconcat(gel(f,2), gel(g,2));1228return h;1229}12301231GEN1232famat_div(GEN f, GEN g)1233{1234GEN h;1235if (typ(g) != t_MAT) {1236if (typ(f) == t_MAT) return famat_sub(f, g);1237h = cgetg(3, t_MAT);1238gel(h,1) = mkcol2(gcopy(f), gcopy(g));1239gel(h,2) = mkcol2(gen_1, gen_m1);1240}1241if (typ(f) != t_MAT) return famat_sub(g, f);1242if (lgcols(f) == 1) return famat_inv(g);1243if (lgcols(g) == 1) return gcopy(f);1244h = cgetg(3,t_MAT);1245gel(h,1) = gconcat(gel(f,1), gel(g,1));1246gel(h,2) = gconcat(gel(f,2), gneg(gel(g,2)));1247return h;1248}12491250GEN1251famat_sqr(GEN f)1252{1253GEN h;1254if (typ(f) != t_MAT) return to_famat(f,gen_2);1255if (lgcols(f) == 1) return gcopy(f);1256h = cgetg(3,t_MAT);1257gel(h,1) = gcopy(gel(f,1));1258gel(h,2) = gmul2n(gel(f,2),1);1259return h;1260}12611262GEN1263famat_inv_shallow(GEN f)1264{1265if (typ(f) != t_MAT) return to_famat_shallow(f,gen_m1);1266if (lgcols(f) == 1) return f;1267return mkmat2(gel(f,1), ZC_neg(gel(f,2)));1268}1269GEN1270famat_inv(GEN f)1271{1272if (typ(f) != t_MAT) return to_famat(f,gen_m1);1273if (lgcols(f) == 1) return gcopy(f);1274retmkmat2(gcopy(gel(f,1)), ZC_neg(gel(f,2)));1275}1276GEN1277famat_pow(GEN f, GEN n)1278{1279if (typ(f) != t_MAT) return to_famat(f,n);1280if (lgcols(f) == 1) return gcopy(f);1281retmkmat2(gcopy(gel(f,1)), ZC_Z_mul(gel(f,2),n));1282}1283GEN1284famat_pow_shallow(GEN f, GEN n)1285{1286if (is_pm1(n)) return signe(n) > 0? f: famat_inv_shallow(f);1287if (typ(f) != t_MAT) return to_famat_shallow(f,n);1288if (lgcols(f) == 1) return f;1289return mkmat2(gel(f,1), ZC_Z_mul(gel(f,2),n));1290}12911292GEN1293famat_pows_shallow(GEN f, long n)1294{1295if (n==1) return f;1296if (n==-1) return famat_inv_shallow(f);1297if (typ(f) != t_MAT) return to_famat_shallow(f, stoi(n));1298if (lgcols(f) == 1) return f;1299return mkmat2(gel(f,1), ZC_z_mul(gel(f,2),n));1300}13011302GEN1303famat_Z_gcd(GEN M, GEN n)1304{1305pari_sp av=avma;1306long i, j, l=lgcols(M);1307GEN F=cgetg(3,t_MAT);1308gel(F,1)=cgetg(l,t_COL);1309gel(F,2)=cgetg(l,t_COL);1310for (i=1, j=1; i<l; i++)1311{1312GEN p = gcoeff(M,i,1);1313GEN e = gminsg(Z_pval(n,p),gcoeff(M,i,2));1314if (signe(e))1315{1316gcoeff(F,j,1)=p;1317gcoeff(F,j,2)=e;1318j++;1319}1320}1321setlg(gel(F,1),j); setlg(gel(F,2),j);1322return gerepilecopy(av,F);1323}13241325/* x assumed to be a t_MATs (factorization matrix), or compatible with1326* the element_* functions. */1327static GEN1328ext_sqr(GEN nf, GEN x)1329{ return (typ(x)==t_MAT)? famat_sqr(x): nfsqr(nf, x); }1330static GEN1331ext_mul(GEN nf, GEN x, GEN y)1332{ return (typ(x)==t_MAT)? famat_mul(x,y): nfmul(nf, x, y); }1333static GEN1334ext_inv(GEN nf, GEN x)1335{ return (typ(x)==t_MAT)? famat_inv(x): nfinv(nf, x); }1336static GEN1337ext_pow(GEN nf, GEN x, GEN n)1338{ return (typ(x)==t_MAT)? famat_pow(x,n): nfpow(nf, x, n); }13391340GEN1341famat_to_nf(GEN nf, GEN f)1342{1343GEN t, x, e;1344long i;1345if (lgcols(f) == 1) return gen_1;1346x = gel(f,1);1347e = gel(f,2);1348t = nfpow(nf, gel(x,1), gel(e,1));1349for (i=lg(x)-1; i>1; i--)1350t = nfmul(nf, t, nfpow(nf, gel(x,i), gel(e,i)));1351return t;1352}13531354GEN1355famat_idealfactor(GEN nf, GEN x)1356{1357long i, l;1358GEN g = gel(x,1), e = gel(x,2), h = cgetg_copy(g, &l);1359for (i = 1; i < l; i++) gel(h,i) = idealfactor(nf, gel(g,i));1360h = famat_reduce(famatV_factorback(h,e));1361return sort_factor(h, (void*)&cmp_prime_ideal, &cmp_nodata);1362}13631364GEN1365famat_reduce(GEN fa)1366{1367GEN E, G, L, g, e;1368long i, k, l;13691370if (typ(fa) != t_MAT || lgcols(fa) == 1) return fa;1371g = gel(fa,1); l = lg(g);1372e = gel(fa,2);1373L = gen_indexsort(g, (void*)&cmp_universal, &cmp_nodata);1374G = cgetg(l, t_COL);1375E = cgetg(l, t_COL);1376/* merge */1377for (k=i=1; i<l; i++,k++)1378{1379gel(G,k) = gel(g,L[i]);1380gel(E,k) = gel(e,L[i]);1381if (k > 1 && gidentical(gel(G,k), gel(G,k-1)))1382{1383gel(E,k-1) = addii(gel(E,k), gel(E,k-1));1384k--;1385}1386}1387/* kill 0 exponents */1388l = k;1389for (k=i=1; i<l; i++)1390if (!gequal0(gel(E,i)))1391{1392gel(G,k) = gel(G,i);1393gel(E,k) = gel(E,i); k++;1394}1395setlg(G, k);1396setlg(E, k); return mkmat2(G,E);1397}1398GEN1399matreduce(GEN f)1400{ pari_sp av = avma;1401switch(typ(f))1402{1403case t_VEC: case t_COL:1404{1405GEN e; f = vec_reduce(f, &e); settyp(f, t_COL);1406return gerepilecopy(av, mkmat2(f, zc_to_ZC(e)));1407}1408case t_MAT:1409if (lg(f) == 3) break;1410default:1411pari_err_TYPE("matreduce", f);1412}1413if (typ(gel(f,1)) == t_VECSMALL)1414f = famatsmall_reduce(f);1415else1416{1417if (!RgV_is_ZV(gel(f,2))) pari_err_TYPE("matreduce",f);1418f = famat_reduce(f);1419}1420return gerepilecopy(av, f);1421}14221423GEN1424famatsmall_reduce(GEN fa)1425{1426GEN E, G, L, g, e;1427long i, k, l;1428if (lgcols(fa) == 1) return fa;1429g = gel(fa,1); l = lg(g);1430e = gel(fa,2);1431L = vecsmall_indexsort(g);1432G = cgetg(l, t_VECSMALL);1433E = cgetg(l, t_VECSMALL);1434/* merge */1435for (k=i=1; i<l; i++,k++)1436{1437G[k] = g[L[i]];1438E[k] = e[L[i]];1439if (k > 1 && G[k] == G[k-1])1440{1441E[k-1] += E[k];1442k--;1443}1444}1445/* kill 0 exponents */1446l = k;1447for (k=i=1; i<l; i++)1448if (E[i])1449{1450G[k] = G[i];1451E[k] = E[i]; k++;1452}1453setlg(G, k);1454setlg(E, k); return mkmat2(G,E);1455}14561457GEN1458famat_remove_trivial(GEN fa)1459{1460GEN P, E, p = gel(fa,1), e = gel(fa,2);1461long j, k, l = lg(p);1462P = cgetg(l, t_COL);1463E = cgetg(l, t_COL);1464for (j = k = 1; j < l; j++)1465if (signe(gel(e,j))) { gel(P,k) = gel(p,j); gel(E,k++) = gel(e,j); }1466setlg(P, k); setlg(E, k); return mkmat2(P,E);1467}14681469GEN1470famatV_factorback(GEN v, GEN e)1471{1472long i, l = lg(e);1473GEN V;1474if (l == 1) return trivial_fact();1475V = signe(gel(e,1))? famat_pow_shallow(gel(v,1), gel(e,1)): trivial_fact();1476for (i = 2; i < l; i++) V = famat_mulpow_shallow(V, gel(v,i), gel(e,i));1477return V;1478}14791480GEN1481famatV_zv_factorback(GEN v, GEN e)1482{1483long i, l = lg(e);1484GEN V;1485if (l == 1) return trivial_fact();1486V = uel(e,1)? famat_pows_shallow(gel(v,1), uel(e,1)): trivial_fact();1487for (i = 2; i < l; i++) V = famat_mulpows_shallow(V, gel(v,i), uel(e,i));1488return V;1489}14901491GEN1492ZM_famat_limit(GEN fa, GEN limit)1493{1494pari_sp av;1495GEN E, G, g, e, r;1496long i, k, l, n, lG;14971498if (lgcols(fa) == 1) return fa;1499g = gel(fa,1); l = lg(g);1500e = gel(fa,2);1501for(n=0, i=1; i<l; i++)1502if (cmpii(gel(g,i),limit)<=0) n++;1503lG = n<l-1 ? n+2 : n+1;1504G = cgetg(lG, t_COL);1505E = cgetg(lG, t_COL);1506av = avma;1507for (i=1, k=1, r = gen_1; i<l; i++)1508{1509if (cmpii(gel(g,i),limit)<=0)1510{1511gel(G,k) = gel(g,i);1512gel(E,k) = gel(e,i);1513k++;1514} else r = mulii(r, powii(gel(g,i), gel(e,i)));1515}1516if (k<i)1517{1518gel(G, k) = gerepileuptoint(av, r);1519gel(E, k) = gen_1;1520}1521return mkmat2(G,E);1522}15231524/* assume pr has degree 1 and coprime to Q_denom(x) */1525static GEN1526to_Fp_coprime(GEN nf, GEN x, GEN modpr)1527{1528GEN d, r, p = modpr_get_p(modpr);1529x = nf_to_scalar_or_basis(nf,x);1530if (typ(x) != t_COL) return Rg_to_Fp(x,p);1531x = Q_remove_denom(x, &d);1532r = zk_to_Fq(x, modpr);1533if (d) r = Fp_div(r, d, p);1534return r;1535}15361537/* pr coprime to all denominators occurring in x */1538static GEN1539famat_to_Fp_coprime(GEN nf, GEN x, GEN modpr)1540{1541GEN p = modpr_get_p(modpr);1542GEN t = NULL, g = gel(x,1), e = gel(x,2), q = subiu(p,1);1543long i, l = lg(g);1544for (i = 1; i < l; i++)1545{1546GEN n = modii(gel(e,i), q);1547if (signe(n))1548{1549GEN h = to_Fp_coprime(nf, gel(g,i), modpr);1550h = Fp_pow(h, n, p);1551t = t? Fp_mul(t, h, p): h;1552}1553}1554return t? modii(t, p): gen_1;1555}15561557/* cf famat_to_nf_modideal_coprime, modpr attached to prime of degree 1 */1558GEN1559nf_to_Fp_coprime(GEN nf, GEN x, GEN modpr)1560{1561return typ(x)==t_MAT? famat_to_Fp_coprime(nf, x, modpr)1562: to_Fp_coprime(nf, x, modpr);1563}15641565static long1566zk_pvalrem(GEN x, GEN p, GEN *py)1567{ return (typ(x) == t_INT)? Z_pvalrem(x, p, py): ZV_pvalrem(x, p, py); }1568/* x a QC or Q. Return a ZC or Z, whose content is coprime to Z. Set v, dx1569* such that x = p^v (newx / dx); dx = NULL if 1 */1570static GEN1571nf_remove_denom_p(GEN nf, GEN x, GEN p, GEN *pdx, long *pv)1572{1573long vcx;1574GEN dx;1575x = nf_to_scalar_or_basis(nf, x);1576x = Q_remove_denom(x, &dx);1577if (dx)1578{1579vcx = - Z_pvalrem(dx, p, &dx);1580if (!vcx) vcx = zk_pvalrem(x, p, &x);1581if (isint1(dx)) dx = NULL;1582}1583else1584{1585vcx = zk_pvalrem(x, p, &x);1586dx = NULL;1587}1588*pv = vcx;1589*pdx = dx; return x;1590}1591/* x = b^e/p^(e-1) in Z_K; x = 0 mod p/pr^e, (x,pr) = 1. Return NULL1592* if p inert (instead of 1) */1593static GEN1594p_makecoprime(GEN pr)1595{1596GEN B = pr_get_tau(pr), b;1597long i, e;15981599if (typ(B) == t_INT) return NULL;1600b = gel(B,1); /* B = multiplication table by b */1601e = pr_get_e(pr);1602if (e == 1) return b;1603/* one could also divide (exactly) by p in each iteration */1604for (i = 1; i < e; i++) b = ZM_ZC_mul(B, b);1605return ZC_Z_divexact(b, powiu(pr_get_p(pr), e-1));1606}16071608/* Compute A = prod g[i]^e[i] mod pr^k, assuming (A, pr) = 1.1609* Method: modify each g[i] so that it becomes coprime to pr,1610* g[i] *= (b/p)^v_pr(g[i]), where b/p = pr^(-1) times something integral1611* and prime to p; globally, we multiply by (b/p)^v_pr(A) = 1.1612* Optimizations:1613* 1) remove all powers of p from contents, and consider extra generator p^vp;1614* modified as p * (b/p)^e = b^e / p^(e-1)1615* 2) remove denominators, coprime to p, by multiplying by inverse mod prk\cap Z1616*1617* EX = multiple of exponent of (O_K / pr^k)^* used to reduce the product in1618* case the e[i] are large */1619GEN1620famat_makecoprime(GEN nf, GEN g, GEN e, GEN pr, GEN prk, GEN EX)1621{1622GEN G, E, t, vp = NULL, p = pr_get_p(pr), prkZ = gcoeff(prk, 1,1);1623long i, l = lg(g);16241625G = cgetg(l+1, t_VEC);1626E = cgetg(l+1, t_VEC); /* l+1: room for "modified p" */1627for (i=1; i < l; i++)1628{1629long vcx;1630GEN dx, x = nf_remove_denom_p(nf, gel(g,i), p, &dx, &vcx);1631if (vcx) /* = v_p(content(g[i])) */1632{1633GEN a = mulsi(vcx, gel(e,i));1634vp = vp? addii(vp, a): a;1635}1636/* x integral, content coprime to p; dx coprime to p */1637if (typ(x) == t_INT)1638{ /* x coprime to p, hence to pr */1639x = modii(x, prkZ);1640if (dx) x = Fp_div(x, dx, prkZ);1641}1642else1643{1644(void)ZC_nfvalrem(x, pr, &x); /* x *= (b/p)^v_pr(x) */1645x = ZC_hnfrem(FpC_red(x,prkZ), prk);1646if (dx) x = FpC_Fp_mul(x, Fp_inv(dx,prkZ), prkZ);1647}1648gel(G,i) = x;1649gel(E,i) = gel(e,i);1650}16511652t = vp? p_makecoprime(pr): NULL;1653if (!t)1654{ /* no need for extra generator */1655setlg(G,l);1656setlg(E,l);1657}1658else1659{1660gel(G,i) = FpC_red(t, prkZ);1661gel(E,i) = vp;1662}1663return famat_to_nf_modideal_coprime(nf, G, E, prk, EX);1664}16651666/* simplified version of famat_makecoprime for X = SUnits[1] */1667GEN1668sunits_makecoprime(GEN X, GEN pr, GEN prk)1669{1670GEN G, p = pr_get_p(pr), prkZ = gcoeff(prk,1,1);1671long i, l = lg(X);16721673G = cgetg(l, t_VEC);1674for (i = 1; i < l; i++)1675{1676GEN x = gel(X,i);1677if (typ(x) == t_INT) /* a prime */1678x = equalii(x,p)? p_makecoprime(pr): modii(x, prkZ);1679else1680{1681(void)ZC_nfvalrem(x, pr, &x); /* x *= (b/p)^v_pr(x) */1682x = ZC_hnfrem(FpC_red(x,prkZ), prk);1683}1684gel(G,i) = x;1685}1686return G;1687}16881689/* prod g[i]^e[i] mod bid, assume (g[i], id) = 1 and 1 < lg(g) <= lg(e) */1690GEN1691famat_to_nf_moddivisor(GEN nf, GEN g, GEN e, GEN bid)1692{1693GEN t, cyc = bid_get_cyc(bid);1694if (lg(cyc) == 1)1695t = gen_1;1696else1697t = famat_to_nf_modideal_coprime(nf, g, e, bid_get_ideal(bid),1698cyc_get_expo(cyc));1699return set_sign_mod_divisor(nf, mkmat2(g,e), t, bid_get_sarch(bid));1700}17011702GEN1703vecmul(GEN x, GEN y)1704{1705if (is_scalar_t(typ(x))) return gmul(x,y);1706pari_APPLY_same(vecmul(gel(x,i), gel(y,i)))1707}17081709GEN1710vecinv(GEN x)1711{1712if (is_scalar_t(typ(x))) return ginv(x);1713pari_APPLY_same(vecinv(gel(x,i)))1714}17151716GEN1717vecpow(GEN x, GEN n)1718{1719if (is_scalar_t(typ(x))) return powgi(x,n);1720pari_APPLY_same(vecpow(gel(x,i), n))1721}17221723GEN1724vecdiv(GEN x, GEN y)1725{1726if (is_scalar_t(typ(x))) return gdiv(x,y);1727pari_APPLY_same(vecdiv(gel(x,i), gel(y,i)))1728}17291730/* A ideal as a square t_MAT */1731static GEN1732idealmulelt(GEN nf, GEN x, GEN A)1733{1734long i, lx;1735GEN dx, dA, D;1736if (lg(A) == 1) return cgetg(1, t_MAT);1737x = nf_to_scalar_or_basis(nf,x);1738if (typ(x) != t_COL)1739return isintzero(x)? cgetg(1,t_MAT): RgM_Rg_mul(A, Q_abs_shallow(x));1740x = Q_remove_denom(x, &dx);1741A = Q_remove_denom(A, &dA);1742x = zk_multable(nf, x);1743D = mulii(zkmultable_capZ(x), gcoeff(A,1,1));1744x = zkC_multable_mul(A, x);1745settyp(x, t_MAT); lx = lg(x);1746/* x may contain scalars (at most 1 since the ideal is nonzero)*/1747for (i=1; i<lx; i++)1748if (typ(gel(x,i)) == t_INT)1749{1750if (i > 1) swap(gel(x,1), gel(x,i)); /* help HNF */1751gel(x,1) = scalarcol_shallow(gel(x,1), lx-1);1752break;1753}1754x = ZM_hnfmodid(x, D);1755dx = mul_denom(dx,dA);1756return dx? gdiv(x,dx): x;1757}17581759/* nf a true nf, tx <= ty */1760static GEN1761idealmul_aux(GEN nf, GEN x, GEN y, long tx, long ty)1762{1763GEN z, cx, cy;1764switch(tx)1765{1766case id_PRINCIPAL:1767switch(ty)1768{1769case id_PRINCIPAL:1770return idealhnf_principal(nf, nfmul(nf,x,y));1771case id_PRIME:1772{1773GEN p = pr_get_p(y), pi = pr_get_gen(y), cx;1774if (pr_is_inert(y)) return RgM_Rg_mul(idealhnf_principal(nf,x),p);17751776x = nf_to_scalar_or_basis(nf, x);1777switch(typ(x))1778{1779case t_INT:1780if (!signe(x)) return cgetg(1,t_MAT);1781return ZM_Z_mul(pr_hnf(nf,y), absi_shallow(x));1782case t_FRAC:1783return RgM_Rg_mul(pr_hnf(nf,y), Q_abs_shallow(x));1784}1785/* t_COL */1786x = Q_primitive_part(x, &cx);1787x = zk_multable(nf, x);1788z = shallowconcat(ZM_Z_mul(x,p), ZM_ZC_mul(x,pi));1789z = ZM_hnfmodid(z, mulii(p, zkmultable_capZ(x)));1790return cx? ZM_Q_mul(z, cx): z;1791}1792default: /* id_MAT */1793return idealmulelt(nf, x,y);1794}1795case id_PRIME:1796if (ty==id_PRIME)1797{ y = pr_hnf(nf,y); cy = NULL; }1798else1799y = Q_primitive_part(y, &cy);1800y = idealHNF_mul_two(nf,y,x);1801return cy? ZM_Q_mul(y,cy): y;18021803default: /* id_MAT */1804{1805long N = nf_get_degree(nf);1806if (lg(x)-1 != N || lg(y)-1 != N) pari_err_DIM("idealmul");1807x = Q_primitive_part(x, &cx);1808y = Q_primitive_part(y, &cy); cx = mul_content(cx,cy);1809y = idealHNF_mul(nf,x,y);1810return cx? ZM_Q_mul(y,cx): y;1811}1812}1813}18141815/* output the ideal product x.y */1816GEN1817idealmul(GEN nf, GEN x, GEN y)1818{1819pari_sp av;1820GEN res, ax, ay, z;1821long tx = idealtyp(&x,&ax);1822long ty = idealtyp(&y,&ay), f;1823if (tx>ty) { swap(ax,ay); swap(x,y); lswap(tx,ty); }1824f = (ax||ay); res = f? cgetg(3,t_VEC): NULL; /*product is an extended ideal*/1825av = avma;1826z = gerepileupto(av, idealmul_aux(checknf(nf), x,y, tx,ty));1827if (!f) return z;1828if (ax && ay)1829ax = ext_mul(nf, ax, ay);1830else1831ax = gcopy(ax? ax: ay);1832gel(res,1) = z; gel(res,2) = ax; return res;1833}18341835/* Return x, integral in 2-elt form, such that pr^2 = c * x. cf idealpowprime1836* nf = true nf */1837static GEN1838idealsqrprime(GEN nf, GEN pr, GEN *pc)1839{1840GEN p = pr_get_p(pr), q, gen;1841long e = pr_get_e(pr), f = pr_get_f(pr);18421843q = (e == 1)? sqri(p): p;1844if (e <= 2 && e * f == nf_get_degree(nf))1845{ /* pr^e = (p) */1846*pc = q;1847return mkvec2(gen_1,gen_0);1848}1849gen = nfsqr(nf, pr_get_gen(pr));1850gen = FpC_red(gen, q);1851*pc = NULL;1852return mkvec2(q, gen);1853}1854/* cf idealpow_aux */1855static GEN1856idealsqr_aux(GEN nf, GEN x, long tx)1857{1858GEN T = nf_get_pol(nf), m, cx, a, alpha;1859long N = degpol(T);1860switch(tx)1861{1862case id_PRINCIPAL:1863return idealhnf_principal(nf, nfsqr(nf,x));1864case id_PRIME:1865if (pr_is_inert(x)) return scalarmat(sqri(gel(x,1)), N);1866x = idealsqrprime(nf, x, &cx);1867x = idealhnf_two(nf,x);1868return cx? ZM_Z_mul(x, cx): x;1869default:1870x = Q_primitive_part(x, &cx);1871a = mat_ideal_two_elt(nf,x); alpha = gel(a,2); a = gel(a,1);1872alpha = nfsqr(nf,alpha);1873m = zk_scalar_or_multable(nf, alpha);1874if (typ(m) == t_INT) {1875x = gcdii(sqri(a), m);1876if (cx) x = gmul(x, gsqr(cx));1877x = scalarmat(x, N);1878}1879else1880{ /* could use gcdii(sqri(a), zkmultable_capZ(m)), but costly */1881x = ZM_hnfmodid(m, sqri(a));1882if (cx) cx = gsqr(cx);1883if (cx) x = ZM_Q_mul(x, cx);1884}1885return x;1886}1887}1888GEN1889idealsqr(GEN nf, GEN x)1890{1891pari_sp av;1892GEN res, ax, z;1893long tx = idealtyp(&x,&ax);1894res = ax? cgetg(3,t_VEC): NULL; /*product is an extended ideal*/1895av = avma;1896z = gerepileupto(av, idealsqr_aux(checknf(nf), x, tx));1897if (!ax) return z;1898gel(res,1) = z;1899gel(res,2) = ext_sqr(nf, ax); return res;1900}19011902/* norm of an ideal */1903GEN1904idealnorm(GEN nf, GEN x)1905{1906pari_sp av;1907GEN y;1908long tx;19091910switch(idealtyp(&x,&y))1911{1912case id_PRIME: return pr_norm(x);1913case id_MAT: return RgM_det_triangular(x);1914}1915/* id_PRINCIPAL */1916nf = checknf(nf); av = avma;1917x = nfnorm(nf, x);1918tx = typ(x);1919if (tx == t_INT) return gerepileuptoint(av, absi(x));1920if (tx != t_FRAC) pari_err_TYPE("idealnorm",x);1921return gerepileupto(av, Q_abs(x));1922}19231924/* x \cap Z */1925GEN1926idealdown(GEN nf, GEN x)1927{1928pari_sp av = avma;1929GEN y, c;1930switch(idealtyp(&x,&y))1931{1932case id_PRIME: return icopy(pr_get_p(x));1933case id_MAT: return gcopy(gcoeff(x,1,1));1934}1935/* id_PRINCIPAL */1936nf = checknf(nf); av = avma;1937x = nf_to_scalar_or_basis(nf, x);1938if (is_rational_t(typ(x))) return Q_abs(x);1939x = Q_primitive_part(x, &c);1940y = zkmultable_capZ(zk_multable(nf, x));1941return gerepilecopy(av, mul_content(c, y));1942}19431944/* true nf */1945static GEN1946idealismaximal_int(GEN nf, GEN p)1947{1948GEN L;1949if (!BPSW_psp(p)) return NULL;1950if (!dvdii(nf_get_index(nf), p) &&1951!FpX_is_irred(FpX_red(nf_get_pol(nf),p), p)) return NULL;1952L = idealprimedec(nf, p);1953return lg(L) == 2? gel(L,1): NULL;1954}1955/* true nf */1956static GEN1957idealismaximal_mat(GEN nf, GEN x)1958{1959GEN p, c, L;1960long i, l, f;1961x = Q_primitive_part(x, &c);1962p = gcoeff(x,1,1);1963if (c)1964{1965if (typ(c) == t_FRAC || !equali1(p)) return NULL;1966return idealismaximal_int(nf, p);1967}1968if (!BPSW_psp(p)) return NULL;1969l = lg(x); f = 1;1970for (i = 2; i < l; i++)1971{1972c = gcoeff(x,i,i);1973if (equalii(c, p)) f++; else if (!equali1(c)) return NULL;1974}1975L = idealprimedec_limit_f(nf, p, f);1976for (i = lg(L)-1; i; i--)1977{1978GEN pr = gel(L,i);1979if (pr_get_f(pr) != f) break;1980if (idealval(nf, x, pr) == 1) return pr;1981}1982return NULL;1983}1984/* true nf */1985static GEN1986idealismaximal_i(GEN nf, GEN x)1987{1988GEN L, p, pr, c;1989long i, l;1990switch(idealtyp(&x,&c))1991{1992case id_PRIME: return x;1993case id_MAT: return idealismaximal_mat(nf, x);1994}1995/* id_PRINCIPAL */1996nf = checknf(nf);1997x = nf_to_scalar_or_basis(nf, x);1998switch(typ(x))1999{2000case t_INT: return idealismaximal_int(nf, absi_shallow(x));2001case t_FRAC: return NULL;2002}2003x = Q_primitive_part(x, &c);2004if (c) return NULL;2005p = zkmultable_capZ(zk_multable(nf, x));2006L = idealprimedec(nf, p); l = lg(L); pr = NULL;2007for (i = 1; i < l; i++)2008{2009long v = ZC_nfval(x, gel(L,i));2010if (v > 1 || (v && pr)) return NULL;2011pr = gel(L,i);2012}2013return pr;2014}2015GEN2016idealismaximal(GEN nf, GEN x)2017{2018pari_sp av = avma;2019x = idealismaximal_i(checknf(nf), x);2020if (!x) { set_avma(av); return gen_0; }2021return gerepilecopy(av, x);2022}20232024/* I^(-1) = { x \in K, Tr(x D^(-1) I) \in Z }, D different of K/Q2025*2026* nf[5][6] = pp( D^(-1) ) = pp( HNF( T^(-1) ) ), T = (Tr(wi wj))2027* nf[5][7] = same in 2-elt form.2028* Assume I integral. Return the integral ideal (I\cap Z) I^(-1) */2029GEN2030idealHNF_inv_Z(GEN nf, GEN I)2031{2032GEN J, dual, IZ = gcoeff(I,1,1); /* I \cap Z */2033if (isint1(IZ)) return matid(lg(I)-1);2034J = idealHNF_mul(nf,I, gmael(nf,5,7));2035/* I in HNF, hence easily inverted; multiply by IZ to get integer coeffs2036* missing content cancels while solving the linear equation */2037dual = shallowtrans( hnf_divscale(J, gmael(nf,5,6), IZ) );2038return ZM_hnfmodid(dual, IZ);2039}2040/* I HNF with rational coefficients (denominator d). */2041GEN2042idealHNF_inv(GEN nf, GEN I)2043{2044GEN J, IQ = gcoeff(I,1,1); /* I \cap Q; d IQ = dI \cap Z */2045J = idealHNF_inv_Z(nf, Q_remove_denom(I, NULL)); /* = (dI)^(-1) * (d IQ) */2046return equali1(IQ)? J: RgM_Rg_div(J, IQ);2047}20482049/* return p * P^(-1) [integral] */2050GEN2051pr_inv_p(GEN pr)2052{2053if (pr_is_inert(pr)) return matid(pr_get_f(pr));2054return ZM_hnfmodid(pr_get_tau(pr), pr_get_p(pr));2055}2056GEN2057pr_inv(GEN pr)2058{2059GEN p = pr_get_p(pr);2060if (pr_is_inert(pr)) return scalarmat(ginv(p), pr_get_f(pr));2061return RgM_Rg_div(ZM_hnfmodid(pr_get_tau(pr),p), p);2062}20632064GEN2065idealinv(GEN nf, GEN x)2066{2067GEN res, ax;2068pari_sp av;2069long tx = idealtyp(&x,&ax), N;20702071res = ax? cgetg(3,t_VEC): NULL;2072nf = checknf(nf); av = avma;2073N = nf_get_degree(nf);2074switch (tx)2075{2076case id_MAT:2077if (lg(x)-1 != N) pari_err_DIM("idealinv");2078x = idealHNF_inv(nf,x); break;2079case id_PRINCIPAL:2080x = nf_to_scalar_or_basis(nf, x);2081if (typ(x) != t_COL)2082x = idealhnf_principal(nf,ginv(x));2083else2084{ /* nfinv + idealhnf where we already know (x) \cap Z */2085GEN c, d;2086x = Q_remove_denom(x, &c);2087x = zk_inv(nf, x);2088x = Q_remove_denom(x, &d); /* true inverse is c/d * x */2089if (!d) /* x and x^(-1) integral => x a unit */2090x = c? scalarmat(c, N): matid(N);2091else2092{2093c = c? gdiv(c,d): ginv(d);2094x = zk_multable(nf, x);2095x = ZM_Q_mul(ZM_hnfmodid(x,d), c);2096}2097}2098break;2099case id_PRIME:2100x = pr_inv(x); break;2101}2102x = gerepileupto(av,x); if (!ax) return x;2103gel(res,1) = x;2104gel(res,2) = ext_inv(nf, ax); return res;2105}21062107/* write x = A/B, A,B coprime integral ideals */2108GEN2109idealnumden(GEN nf, GEN x)2110{2111pari_sp av = avma;2112GEN x0, ax, c, d, A, B, J;2113long tx = idealtyp(&x,&ax);2114nf = checknf(nf);2115switch (tx)2116{2117case id_PRIME:2118retmkvec2(idealhnf(nf, x), gen_1);2119case id_PRINCIPAL:2120{2121GEN xZ, mx;2122x = nf_to_scalar_or_basis(nf, x);2123switch(typ(x))2124{2125case t_INT: return gerepilecopy(av, mkvec2(absi_shallow(x),gen_1));2126case t_FRAC:return gerepilecopy(av, mkvec2(absi_shallow(gel(x,1)), gel(x,2)));2127}2128/* t_COL */2129x = Q_remove_denom(x, &d);2130if (!d) return gerepilecopy(av, mkvec2(idealhnf(nf, x), gen_1));2131mx = zk_multable(nf, x);2132xZ = zkmultable_capZ(mx);2133x = ZM_hnfmodid(mx, xZ); /* principal ideal (x) */2134x0 = mkvec2(xZ, mx); /* same, for fast multiplication */2135break;2136}2137default: /* id_MAT */2138{2139long n = lg(x)-1;2140if (n == 0) return mkvec2(gen_0, gen_1);2141if (n != nf_get_degree(nf)) pari_err_DIM("idealnumden");2142x0 = x = Q_remove_denom(x, &d);2143if (!d) return gerepilecopy(av, mkvec2(x, gen_1));2144break;2145}2146}2147J = hnfmodid(x, d); /* = d/B */2148c = gcoeff(J,1,1); /* (d/B) \cap Z, divides d */2149B = idealHNF_inv_Z(nf, J); /* (d/B \cap Z) B/d */2150if (!equalii(c,d)) B = ZM_Z_mul(B, diviiexact(d,c)); /* = B ! */2151A = idealHNF_mul(nf, B, x0); /* d * (original x) * B = d A */2152A = ZM_Z_divexact(A, d); /* = A ! */2153return gerepilecopy(av, mkvec2(A, B));2154}21552156/* Return x, integral in 2-elt form, such that pr^n = c * x. Assume n != 0.2157* nf = true nf */2158static GEN2159idealpowprime(GEN nf, GEN pr, GEN n, GEN *pc)2160{2161GEN p = pr_get_p(pr), q, gen;21622163*pc = NULL;2164if (is_pm1(n)) /* n = 1 special cased for efficiency */2165{2166q = p;2167if (typ(pr_get_tau(pr)) == t_INT) /* inert */2168{2169*pc = (signe(n) >= 0)? p: ginv(p);2170return mkvec2(gen_1,gen_0);2171}2172if (signe(n) >= 0) gen = pr_get_gen(pr);2173else2174{2175gen = pr_get_tau(pr); /* possibly t_MAT */2176*pc = ginv(p);2177}2178}2179else if (equalis(n,2)) return idealsqrprime(nf, pr, pc);2180else2181{2182long e = pr_get_e(pr), f = pr_get_f(pr);2183GEN r, m = truedvmdis(n, e, &r);2184if (e * f == nf_get_degree(nf))2185{ /* pr^e = (p) */2186if (signe(m)) *pc = powii(p,m);2187if (!signe(r)) return mkvec2(gen_1,gen_0);2188q = p;2189gen = nfpow(nf, pr_get_gen(pr), r);2190}2191else2192{2193m = absi_shallow(m);2194if (signe(r)) m = addiu(m,1);2195q = powii(p,m); /* m = ceil(|n|/e) */2196if (signe(n) >= 0) gen = nfpow(nf, pr_get_gen(pr), n);2197else2198{2199gen = pr_get_tau(pr);2200if (typ(gen) == t_MAT) gen = gel(gen,1);2201n = negi(n);2202gen = ZC_Z_divexact(nfpow(nf, gen, n), powii(p, subii(n,m)));2203*pc = ginv(q);2204}2205}2206gen = FpC_red(gen, q);2207}2208return mkvec2(q, gen);2209}22102211/* x * pr^n. Assume x in HNF or scalar (possibly nonintegral) */2212GEN2213idealmulpowprime(GEN nf, GEN x, GEN pr, GEN n)2214{2215GEN c, cx, y;2216long N;22172218nf = checknf(nf);2219N = nf_get_degree(nf);2220if (!signe(n)) return typ(x) == t_MAT? x: scalarmat_shallow(x, N);22212222/* inert, special cased for efficiency */2223if (pr_is_inert(pr))2224{2225GEN q = powii(pr_get_p(pr), n);2226return typ(x) == t_MAT? RgM_Rg_mul(x,q)2227: scalarmat_shallow(gmul(Q_abs(x),q), N);2228}22292230y = idealpowprime(nf, pr, n, &c);2231if (typ(x) == t_MAT)2232{ x = Q_primitive_part(x, &cx); if (is_pm1(gcoeff(x,1,1))) x = NULL; }2233else2234{ cx = x; x = NULL; }2235cx = mul_content(c,cx);2236if (x)2237x = idealHNF_mul_two(nf,x,y);2238else2239x = idealhnf_two(nf,y);2240if (cx) x = ZM_Q_mul(x,cx);2241return x;2242}2243GEN2244idealdivpowprime(GEN nf, GEN x, GEN pr, GEN n)2245{2246return idealmulpowprime(nf,x,pr, negi(n));2247}22482249/* nf = true nf */2250static GEN2251idealpow_aux(GEN nf, GEN x, long tx, GEN n)2252{2253GEN T = nf_get_pol(nf), m, cx, n1, a, alpha;2254long N = degpol(T), s = signe(n);2255if (!s) return matid(N);2256switch(tx)2257{2258case id_PRINCIPAL:2259return idealhnf_principal(nf, nfpow(nf,x,n));2260case id_PRIME:2261if (pr_is_inert(x)) return scalarmat(powii(gel(x,1), n), N);2262x = idealpowprime(nf, x, n, &cx);2263x = idealhnf_two(nf,x);2264return cx? ZM_Q_mul(x, cx): x;2265default:2266if (is_pm1(n)) return (s < 0)? idealinv(nf, x): gcopy(x);2267n1 = (s < 0)? negi(n): n;22682269x = Q_primitive_part(x, &cx);2270a = mat_ideal_two_elt(nf,x); alpha = gel(a,2); a = gel(a,1);2271alpha = nfpow(nf,alpha,n1);2272m = zk_scalar_or_multable(nf, alpha);2273if (typ(m) == t_INT) {2274x = gcdii(powii(a,n1), m);2275if (s<0) x = ginv(x);2276if (cx) x = gmul(x, powgi(cx,n));2277x = scalarmat(x, N);2278}2279else2280{ /* could use gcdii(powii(a,n1), zkmultable_capZ(m)), but costly */2281x = ZM_hnfmodid(m, powii(a,n1));2282if (cx) cx = powgi(cx,n);2283if (s<0) {2284GEN xZ = gcoeff(x,1,1);2285cx = cx ? gdiv(cx, xZ): ginv(xZ);2286x = idealHNF_inv_Z(nf,x);2287}2288if (cx) x = ZM_Q_mul(x, cx);2289}2290return x;2291}2292}22932294/* raise the ideal x to the power n (in Z) */2295GEN2296idealpow(GEN nf, GEN x, GEN n)2297{2298pari_sp av;2299long tx;2300GEN res, ax;23012302if (typ(n) != t_INT) pari_err_TYPE("idealpow",n);2303tx = idealtyp(&x,&ax);2304res = ax? cgetg(3,t_VEC): NULL;2305av = avma;2306x = gerepileupto(av, idealpow_aux(checknf(nf), x, tx, n));2307if (!ax) return x;2308ax = ext_pow(nf, ax, n);2309gel(res,1) = x;2310gel(res,2) = ax;2311return res;2312}23132314/* Return ideal^e in number field nf. e is a C integer. */2315GEN2316idealpows(GEN nf, GEN ideal, long e)2317{2318long court[] = {evaltyp(t_INT) | _evallg(3),0,0};2319affsi(e,court); return idealpow(nf,ideal,court);2320}23212322static GEN2323_idealmulred(GEN nf, GEN x, GEN y)2324{ return idealred(nf,idealmul(nf,x,y)); }2325static GEN2326_idealsqrred(GEN nf, GEN x)2327{ return idealred(nf,idealsqr(nf,x)); }2328static GEN2329_mul(void *data, GEN x, GEN y) { return _idealmulred((GEN)data,x,y); }2330static GEN2331_sqr(void *data, GEN x) { return _idealsqrred((GEN)data, x); }23322333/* compute x^n (x ideal, n integer), reducing along the way */2334GEN2335idealpowred(GEN nf, GEN x, GEN n)2336{2337pari_sp av = avma, av2;2338long s;2339GEN y;23402341if (typ(n) != t_INT) pari_err_TYPE("idealpowred",n);2342s = signe(n); if (s == 0) return idealpow(nf,x,n);2343y = gen_pow_i(x, n, (void*)nf, &_sqr, &_mul);2344av2 = avma;2345if (s < 0) y = idealinv(nf,y);2346if (s < 0 || is_pm1(n)) y = idealred(nf,y);2347return avma == av2? gerepilecopy(av,y): gerepileupto(av,y);2348}23492350GEN2351idealmulred(GEN nf, GEN x, GEN y)2352{2353pari_sp av = avma;2354return gerepileupto(av, _idealmulred(nf,x,y));2355}23562357long2358isideal(GEN nf,GEN x)2359{2360long N, i, j, lx, tx = typ(x);2361pari_sp av;2362GEN T, xZ;23632364nf = checknf(nf); T = nf_get_pol(nf); lx = lg(x);2365if (tx==t_VEC && lx==3) { x = gel(x,1); tx = typ(x); lx = lg(x); }2366switch(tx)2367{2368case t_INT: case t_FRAC: return 1;2369case t_POL: return varn(x) == varn(T);2370case t_POLMOD: return RgX_equal_var(T, gel(x,1));2371case t_VEC: return get_prid(x)? 1 : 0;2372case t_MAT: break;2373default: return 0;2374}2375N = degpol(T);2376if (lx-1 != N) return (lx == 1);2377if (nbrows(x) != N) return 0;23782379av = avma; x = Q_primpart(x);2380if (!ZM_ishnf(x)) return 0;2381xZ = gcoeff(x,1,1);2382for (j=2; j<=N; j++)2383if (!dvdii(xZ, gcoeff(x,j,j))) return gc_long(av,0);2384for (i=2; i<=N; i++)2385for (j=2; j<=N; j++)2386if (! hnf_invimage(x, zk_ei_mul(nf,gel(x,i),j))) return gc_long(av,0);2387return gc_long(av,1);2388}23892390GEN2391idealdiv(GEN nf, GEN x, GEN y)2392{2393pari_sp av = avma, tetpil;2394GEN z = idealinv(nf,y);2395tetpil = avma; return gerepile(av,tetpil, idealmul(nf,x,z));2396}23972398/* This routine computes the quotient x/y of two ideals in the number field nf.2399* It assumes that the quotient is an integral ideal. The idea is to find an2400* ideal z dividing y such that gcd(Nx/Nz, Nz) = 1. Then2401*2402* x + (Nx/Nz) x2403* ----------- = ---2404* y + (Ny/Nz) y2405*2406* Proof: we can assume x and y are integral. Let p be any prime ideal2407*2408* If p | Nz, then it divides neither Nx/Nz nor Ny/Nz (since Nx/Nz is the2409* product of the integers N(x/y) and N(y/z)). Both the numerator and the2410* denominator on the left will be coprime to p. So will x/y, since x/y is2411* assumed integral and its norm N(x/y) is coprime to p.2412*2413* If instead p does not divide Nz, then v_p (Nx/Nz) = v_p (Nx) >= v_p(x).2414* Hence v_p (x + Nx/Nz) = v_p(x). Likewise for the denominators. QED.2415*2416* Peter Montgomery. July, 1994. */2417static void2418err_divexact(GEN x, GEN y)2419{ pari_err_DOMAIN("idealdivexact","denominator(x/y)", "!=",2420gen_1,mkvec2(x,y)); }2421GEN2422idealdivexact(GEN nf, GEN x0, GEN y0)2423{2424pari_sp av = avma;2425GEN x, y, xZ, yZ, Nx, Ny, Nz, cy, q, r;24262427nf = checknf(nf);2428x = idealhnf_shallow(nf, x0);2429y = idealhnf_shallow(nf, y0);2430if (lg(y) == 1) pari_err_INV("idealdivexact", y0);2431if (lg(x) == 1) { set_avma(av); return cgetg(1, t_MAT); } /* numerator is zero */2432y = Q_primitive_part(y, &cy);2433if (cy) x = RgM_Rg_div(x,cy);2434xZ = gcoeff(x,1,1); if (typ(xZ) != t_INT) err_divexact(x,y);2435yZ = gcoeff(y,1,1); if (isint1(yZ)) return gerepilecopy(av, x);2436Nx = idealnorm(nf,x);2437Ny = idealnorm(nf,y);2438if (typ(Nx) != t_INT) err_divexact(x,y);2439q = dvmdii(Nx,Ny, &r);2440if (signe(r)) err_divexact(x,y);2441if (is_pm1(q)) { set_avma(av); return matid(nf_get_degree(nf)); }2442/* Find a norm Nz | Ny such that gcd(Nx/Nz, Nz) = 1 */2443for (Nz = Ny;;) /* q = Nx/Nz */2444{2445GEN p1 = gcdii(Nz, q);2446if (is_pm1(p1)) break;2447Nz = diviiexact(Nz,p1);2448q = mulii(q,p1);2449}2450xZ = gcoeff(x,1,1); q = gcdii(q, xZ);2451if (!equalii(xZ,q))2452{ /* Replace x/y by x+(Nx/Nz) / y+(Ny/Nz) */2453x = ZM_hnfmodid(x, q);2454/* y reduced to unit ideal ? */2455if (Nz == Ny) return gerepileupto(av, x);24562457yZ = gcoeff(y,1,1); q = gcdii(diviiexact(Ny,Nz), yZ);2458y = ZM_hnfmodid(y, q);2459}2460yZ = gcoeff(y,1,1);2461y = idealHNF_mul(nf,x, idealHNF_inv_Z(nf,y));2462return gerepileupto(av, ZM_Z_divexact(y, yZ));2463}24642465GEN2466idealintersect(GEN nf, GEN x, GEN y)2467{2468pari_sp av = avma;2469long lz, lx, i;2470GEN z, dx, dy, xZ, yZ;;24712472nf = checknf(nf);2473x = idealhnf_shallow(nf,x);2474y = idealhnf_shallow(nf,y);2475if (lg(x) == 1 || lg(y) == 1) { set_avma(av); return cgetg(1,t_MAT); }2476x = Q_remove_denom(x, &dx);2477y = Q_remove_denom(y, &dy);2478if (dx) y = ZM_Z_mul(y, dx);2479if (dy) x = ZM_Z_mul(x, dy);2480xZ = gcoeff(x,1,1);2481yZ = gcoeff(y,1,1);2482dx = mul_denom(dx,dy);2483z = ZM_lll(shallowconcat(x,y), 0.99, LLL_KER); lz = lg(z);2484lx = lg(x);2485for (i=1; i<lz; i++) setlg(z[i], lx);2486z = ZM_hnfmodid(ZM_mul(x,z), lcmii(xZ, yZ));2487if (dx) z = RgM_Rg_div(z,dx);2488return gerepileupto(av,z);2489}24902491/*******************************************************************/2492/* */2493/* T2-IDEAL REDUCTION */2494/* */2495/*******************************************************************/24962497static GEN2498chk_vdir(GEN nf, GEN vdir)2499{2500long i, l = lg(vdir);2501GEN v;2502if (l != lg(nf_get_roots(nf))) pari_err_DIM("idealred");2503switch(typ(vdir))2504{2505case t_VECSMALL: return vdir;2506case t_VEC: break;2507default: pari_err_TYPE("idealred",vdir);2508}2509v = cgetg(l, t_VECSMALL);2510for (i = 1; i < l; i++) v[i] = itos(gceil(gel(vdir,i)));2511return v;2512}25132514static void2515twistG(GEN G, long r1, long i, long v)2516{2517long j, lG = lg(G);2518if (i <= r1) {2519for (j=1; j<lG; j++) gcoeff(G,i,j) = gmul2n(gcoeff(G,i,j), v);2520} else {2521long k = (i<<1) - r1;2522for (j=1; j<lG; j++)2523{2524gcoeff(G,k-1,j) = gmul2n(gcoeff(G,k-1,j), v);2525gcoeff(G,k ,j) = gmul2n(gcoeff(G,k ,j), v);2526}2527}2528}25292530GEN2531nf_get_Gtwist(GEN nf, GEN vdir)2532{2533long i, l, v, r1;2534GEN G;25352536if (!vdir) return nf_get_roundG(nf);2537if (typ(vdir) == t_MAT)2538{2539long N = nf_get_degree(nf);2540if (lg(vdir) != N+1 || lgcols(vdir) != N+1) pari_err_DIM("idealred");2541return vdir;2542}2543vdir = chk_vdir(nf, vdir);2544G = RgM_shallowcopy(nf_get_G(nf));2545r1 = nf_get_r1(nf);2546l = lg(vdir);2547for (i=1; i<l; i++)2548{2549v = vdir[i]; if (!v) continue;2550twistG(G, r1, i, v);2551}2552return RM_round_maxrank(G);2553}2554GEN2555nf_get_Gtwist1(GEN nf, long i)2556{2557GEN G = RgM_shallowcopy( nf_get_G(nf) );2558long r1 = nf_get_r1(nf);2559twistG(G, r1, i, 10);2560return RM_round_maxrank(G);2561}25622563GEN2564RM_round_maxrank(GEN G0)2565{2566long e, r = lg(G0)-1;2567pari_sp av = avma;2568for (e = 4; ; e <<= 1, set_avma(av))2569{2570GEN G = gmul2n(G0, e), H = ground(G);2571if (ZM_rank(H) == r) return H; /* maximal rank ? */2572}2573}25742575GEN2576idealred0(GEN nf, GEN I, GEN vdir)2577{2578pari_sp av = avma;2579GEN G, aI, IZ, J, y, yZ, my, c1 = NULL;2580long N;25812582nf = checknf(nf);2583N = nf_get_degree(nf);2584/* put first for sanity checks, unused when I obviously principal */2585G = nf_get_Gtwist(nf, vdir);2586switch (idealtyp(&I,&aI))2587{2588case id_PRIME:2589if (pr_is_inert(I)) {2590if (!aI) { set_avma(av); return matid(N); }2591c1 = gel(I,1); I = matid(N);2592goto END;2593}2594IZ = pr_get_p(I);2595J = pr_inv_p(I);2596I = idealhnf_two(nf,I);2597break;2598case id_MAT:2599I = Q_primitive_part(I, &c1);2600IZ = gcoeff(I,1,1);2601if (is_pm1(IZ))2602{2603if (!aI) { set_avma(av); return matid(N); }2604goto END;2605}2606J = idealHNF_inv_Z(nf, I);2607break;2608default: /* id_PRINCIPAL, silly case */2609if (gequal0(I)) I = cgetg(1,t_MAT); else { c1 = I; I = matid(N); }2610if (!aI) return I;2611goto END;2612}2613/* now I integral, HNF; and J = (I\cap Z) I^(-1), integral */2614y = idealpseudomin(J, G); /* small elt in (I\cap Z)I^(-1), integral */2615if (equalii(ZV_content(y), IZ))2616{ /* already reduced */2617if (!aI) return gerepilecopy(av, I);2618goto END;2619}26202621my = zk_multable(nf, y);2622I = ZM_Z_divexact(ZM_mul(my, I), IZ); /* y I / (I\cap Z), integral */2623c1 = mul_content(c1, IZ);2624my = ZM_gauss(my, col_ei(N,1)); /* y^-1 */2625yZ = Q_denom(my); /* (y) \cap Z */2626I = hnfmodid(I, yZ);2627if (!aI) return gerepileupto(av, I);2628c1 = RgC_Rg_mul(my, c1);2629END:2630if (c1) aI = ext_mul(nf, aI,c1);2631return gerepilecopy(av, mkvec2(I, aI));2632}26332634GEN2635idealmin(GEN nf, GEN x, GEN vdir)2636{2637pari_sp av = avma;2638GEN y, dx;2639nf = checknf(nf);2640switch( idealtyp(&x,&y) )2641{2642case id_PRINCIPAL: return gcopy(x);2643case id_PRIME: x = pr_hnf(nf,x); break;2644case id_MAT: if (lg(x) == 1) return gen_0;2645}2646x = Q_remove_denom(x, &dx);2647y = idealpseudomin(x, nf_get_Gtwist(nf,vdir));2648if (dx) y = RgC_Rg_div(y, dx);2649return gerepileupto(av, y);2650}26512652/*******************************************************************/2653/* */2654/* APPROXIMATION THEOREM */2655/* */2656/*******************************************************************/2657/* a = ppi(a,b) ppo(a,b), where ppi regroups primes common to a and b2658* and ppo(a,b) = Z_ppo(a,b) */2659/* return gcd(a,b),ppi(a,b),ppo(a,b) */2660GEN2661Z_ppio(GEN a, GEN b)2662{2663GEN x, y, d = gcdii(a,b);2664if (is_pm1(d)) return mkvec3(gen_1, gen_1, a);2665x = d; y = diviiexact(a,d);2666for(;;)2667{2668GEN g = gcdii(x,y);2669if (is_pm1(g)) return mkvec3(d, x, y);2670x = mulii(x,g); y = diviiexact(y,g);2671}2672}2673/* a = ppg(a,b)pple(a,b), where ppg regroups primes such that v(a) > v(b)2674* and pple all others */2675/* return gcd(a,b),ppg(a,b),pple(a,b) */2676GEN2677Z_ppgle(GEN a, GEN b)2678{2679GEN x, y, g, d = gcdii(a,b);2680if (equalii(a, d)) return mkvec3(a, gen_1, a);2681x = diviiexact(a,d); y = d;2682for(;;)2683{2684g = gcdii(x,y);2685if (is_pm1(g)) return mkvec3(d, x, y);2686x = mulii(x,g); y = diviiexact(y,g);2687}2688}2689static void2690Z_dcba_rec(GEN L, GEN a, GEN b)2691{2692GEN x, r, v, g, h, c, c0;2693long n;2694if (is_pm1(b)) {2695if (!is_pm1(a)) vectrunc_append(L, a);2696return;2697}2698v = Z_ppio(a,b);2699a = gel(v,2);2700r = gel(v,3);2701if (!is_pm1(r)) vectrunc_append(L, r);2702v = Z_ppgle(a,b);2703g = gel(v,1);2704h = gel(v,2);2705x = c0 = gel(v,3);2706for (n = 1; !is_pm1(h); n++)2707{2708GEN d, y;2709long i;2710v = Z_ppgle(h,sqri(g));2711g = gel(v,1);2712h = gel(v,2);2713c = gel(v,3); if (is_pm1(c)) continue;2714d = gcdii(c,b);2715x = mulii(x,d);2716y = d; for (i=1; i < n; i++) y = sqri(y);2717Z_dcba_rec(L, diviiexact(c,y), d);2718}2719Z_dcba_rec(L,diviiexact(b,x), c0);2720}2721static GEN2722Z_cba_rec(GEN L, GEN a, GEN b)2723{2724GEN g;2725if (lg(L) > 10)2726{ /* a few naive steps before switching to dcba */2727Z_dcba_rec(L, a, b);2728return gel(L, lg(L)-1);2729}2730if (is_pm1(a)) return b;2731g = gcdii(a,b);2732if (is_pm1(g)) { vectrunc_append(L, a); return b; }2733a = diviiexact(a,g);2734b = diviiexact(b,g);2735return Z_cba_rec(L, Z_cba_rec(L, a, g), b);2736}2737GEN2738Z_cba(GEN a, GEN b)2739{2740GEN L = vectrunc_init(expi(a) + expi(b) + 2);2741GEN t = Z_cba_rec(L, a, b);2742if (!is_pm1(t)) vectrunc_append(L, t);2743return L;2744}2745/* P = coprime base, extend it by b; TODO: quadratic for now */2746GEN2747ZV_cba_extend(GEN P, GEN b)2748{2749long i, l = lg(P);2750GEN w = cgetg(l+1, t_VEC);2751for (i = 1; i < l; i++)2752{2753GEN v = Z_cba(gel(P,i), b);2754long nv = lg(v)-1;2755gel(w,i) = vecslice(v, 1, nv-1); /* those divide P[i] but not b */2756b = gel(v,nv);2757}2758gel(w,l) = b; return shallowconcat1(w);2759}2760GEN2761ZV_cba(GEN v)2762{2763long i, l = lg(v);2764GEN P;2765if (l <= 2) return v;2766P = Z_cba(gel(v,1), gel(v,2));2767for (i = 3; i < l; i++) P = ZV_cba_extend(P, gel(v,i));2768return P;2769}27702771/* write x = x1 x2, x2 maximal s.t. (x2,f) = 1, return x2 */2772GEN2773Z_ppo(GEN x, GEN f)2774{2775for (;;)2776{2777f = gcdii(x, f); if (is_pm1(f)) break;2778x = diviiexact(x, f);2779}2780return x;2781}2782/* write x = x1 x2, x2 maximal s.t. (x2,f) = 1, return x2 */2783ulong2784u_ppo(ulong x, ulong f)2785{2786for (;;)2787{2788f = ugcd(x, f); if (f == 1) break;2789x /= f;2790}2791return x;2792}27932794/* result known to be representable as an ulong */2795static ulong2796lcmuu(ulong a, ulong b) { ulong d = ugcd(a,b); return (a/d) * b; }27972798/* assume 0 < x < N; return u in (Z/NZ)^* such that u x = gcd(x,N) (mod N);2799* set *pd = gcd(x,N) */2800ulong2801Fl_invgen(ulong x, ulong N, ulong *pd)2802{2803ulong d, d0, e, v, v1;2804long s;2805*pd = d = xgcduu(N, x, 0, &v, &v1, &s);2806if (s > 0) v = N - v;2807if (d == 1) return v;2808/* vx = gcd(x,N) (mod N), v coprime to N/d but need not be coprime to N */2809e = N / d;2810d0 = u_ppo(d, e); /* d = d0 d1, d0 coprime to N/d, rad(d1) | N/d */2811if (d0 == 1) return v;2812e = lcmuu(e, d / d0);2813return u_chinese_coprime(v, 1, e, d0, e*d0);2814}28152816/* x t_INT, f ideal. Write x = x1 x2, sqf(x1) | f, (x2,f) = 1. Return x2 */2817static GEN2818nf_coprime_part(GEN nf, GEN x, GEN listpr)2819{2820long v, j, lp = lg(listpr), N = nf_get_degree(nf);2821GEN x1, x2, ex;28222823#if 0 /*1) via many gcds. Expensive ! */2824GEN f = idealprodprime(nf, listpr);2825f = ZM_hnfmodid(f, x); /* first gcd is less expensive since x in Z */2826x = scalarmat(x, N);2827for (;;)2828{2829if (gequal1(gcoeff(f,1,1))) break;2830x = idealdivexact(nf, x, f);2831f = ZM_hnfmodid(shallowconcat(f,x), gcoeff(x,1,1)); /* gcd(f,x) */2832}2833x2 = x;2834#else /*2) from prime decomposition */2835x1 = NULL;2836for (j=1; j<lp; j++)2837{2838GEN pr = gel(listpr,j);2839v = Z_pval(x, pr_get_p(pr)); if (!v) continue;28402841ex = muluu(v, pr_get_e(pr)); /* = v_pr(x) > 0 */2842x1 = x1? idealmulpowprime(nf, x1, pr, ex)2843: idealpow(nf, pr, ex);2844}2845x = scalarmat(x, N);2846x2 = x1? idealdivexact(nf, x, x1): x;2847#endif2848return x2;2849}28502851/* L0 in K^*, assume (L0,f) = 1. Return L integral, L0 = L mod f */2852GEN2853make_integral(GEN nf, GEN L0, GEN f, GEN listpr)2854{2855GEN fZ, t, L, D2, d1, d2, d;28562857L = Q_remove_denom(L0, &d);2858if (!d) return L0;28592860/* L0 = L / d, L integral */2861fZ = gcoeff(f,1,1);2862if (typ(L) == t_INT) return Fp_mul(L, Fp_inv(d, fZ), fZ);2863/* Kill denom part coprime to fZ */2864d2 = Z_ppo(d, fZ);2865t = Fp_inv(d2, fZ); if (!is_pm1(t)) L = ZC_Z_mul(L,t);2866if (equalii(d, d2)) return L;28672868d1 = diviiexact(d, d2);2869/* L0 = (L / d1) mod f. d1 not coprime to f2870* write (d1) = D1 D2, D2 minimal, (D2,f) = 1. */2871D2 = nf_coprime_part(nf, d1, listpr);2872t = idealaddtoone_i(nf, D2, f); /* in D2, 1 mod f */2873L = nfmuli(nf,t,L);28742875/* if (L0, f) = 1, then L in D1 ==> in D1 D2 = (d1) */2876return Q_div_to_int(L, d1); /* exact division */2877}28782879/* assume L is a list of prime ideals. Return the product */2880GEN2881idealprodprime(GEN nf, GEN L)2882{2883long l = lg(L), i;2884GEN z;2885if (l == 1) return matid(nf_get_degree(nf));2886z = pr_hnf(nf, gel(L,1));2887for (i=2; i<l; i++) z = idealHNF_mul_two(nf,z, gel(L,i));2888return z;2889}28902891/* optimize for the frequent case I = nfhnf()[2]: lots of them are 1 */2892GEN2893idealprod(GEN nf, GEN I)2894{2895long i, l = lg(I);2896GEN z;2897for (i = 1; i < l; i++)2898if (!equali1(gel(I,i))) break;2899if (i == l) return gen_1;2900z = gel(I,i);2901for (i++; i<l; i++) z = idealmul(nf, z, gel(I,i));2902return z;2903}29042905/* v_pr(idealprod(nf,I)) */2906long2907idealprodval(GEN nf, GEN I, GEN pr)2908{2909long i, l = lg(I), v = 0;2910for (i = 1; i < l; i++)2911if (!equali1(gel(I,i))) v += idealval(nf, gel(I,i), pr);2912return v;2913}29142915/* assume L is a list of prime ideals. Return prod L[i]^e[i] */2916GEN2917factorbackprime(GEN nf, GEN L, GEN e)2918{2919long l = lg(L), i;2920GEN z;29212922if (l == 1) return matid(nf_get_degree(nf));2923z = idealpow(nf, gel(L,1), gel(e,1));2924for (i=2; i<l; i++)2925if (signe(gel(e,i))) z = idealmulpowprime(nf,z, gel(L,i),gel(e,i));2926return z;2927}29282929/* F in Z, divisible exactly by pr.p. Return F-uniformizer for pr, i.e.2930* a t in Z_K such that v_pr(t) = 1 and (t, F/pr) = 1 */2931GEN2932pr_uniformizer(GEN pr, GEN F)2933{2934GEN p = pr_get_p(pr), t = pr_get_gen(pr);2935if (!equalii(F, p))2936{2937long e = pr_get_e(pr);2938GEN u, v, q = (e == 1)? sqri(p): p;2939u = mulii(q, Fp_inv(q, diviiexact(F,p))); /* 1 mod F/p, 0 mod q */2940v = subui(1UL, u); /* 0 mod F/p, 1 mod q */2941if (pr_is_inert(pr))2942t = addii(mulii(p, v), u);2943else2944{2945t = ZC_Z_mul(t, v);2946gel(t,1) = addii(gel(t,1), u); /* return u + vt */2947}2948}2949return t;2950}2951/* L = list of prime ideals, return lcm_i (L[i] \cap \ZM) */2952GEN2953prV_lcm_capZ(GEN L)2954{2955long i, r = lg(L);2956GEN F;2957if (r == 1) return gen_1;2958F = pr_get_p(gel(L,1));2959for (i = 2; i < r; i++)2960{2961GEN pr = gel(L,i), p = pr_get_p(pr);2962if (!dvdii(F, p)) F = mulii(F,p);2963}2964return F;2965}29662967/* Given a prime ideal factorization with possibly zero or negative2968* exponents, gives b such that v_p(b) = v_p(x) for all prime ideals pr | x2969* and v_pr(b) >= 0 for all other pr.2970* For optimal performance, all [anti-]uniformizers should be precomputed,2971* but no support for this yet.2972*2973* If nored, do not reduce result.2974* No garbage collecting */2975static GEN2976idealapprfact_i(GEN nf, GEN x, int nored)2977{2978GEN z, d, L, e, e2, F;2979long i, r;2980int flagden;29812982nf = checknf(nf);2983L = gel(x,1);2984e = gel(x,2);2985F = prV_lcm_capZ(L);2986flagden = 0;2987z = NULL; r = lg(e);2988for (i = 1; i < r; i++)2989{2990long s = signe(gel(e,i));2991GEN pi, q;2992if (!s) continue;2993if (s < 0) flagden = 1;2994pi = pr_uniformizer(gel(L,i), F);2995q = nfpow(nf, pi, gel(e,i));2996z = z? nfmul(nf, z, q): q;2997}2998if (!z) return gen_1;2999if (nored || typ(z) != t_COL) return z;3000e2 = cgetg(r, t_VEC);3001for (i=1; i<r; i++) gel(e2,i) = addiu(gel(e,i), 1);3002x = factorbackprime(nf, L,e2);3003if (flagden) /* denominator */3004{3005z = Q_remove_denom(z, &d);3006d = diviiexact(d, Z_ppo(d, F));3007x = RgM_Rg_mul(x, d);3008}3009else3010d = NULL;3011z = ZC_reducemodlll(z, x);3012return d? RgC_Rg_div(z,d): z;3013}30143015GEN3016idealapprfact(GEN nf, GEN x) {3017pari_sp av = avma;3018return gerepileupto(av, idealapprfact_i(nf, x, 0));3019}3020GEN3021idealappr(GEN nf, GEN x) {3022pari_sp av = avma;3023if (!is_nf_extfactor(x)) x = idealfactor(nf, x);3024return gerepileupto(av, idealapprfact_i(nf, x, 0));3025}30263027/* OBSOLETE */3028GEN3029idealappr0(GEN nf, GEN x, long fl) { (void)fl; return idealappr(nf, x); }30303031static GEN3032mat_ideal_two_elt2(GEN nf, GEN x, GEN a)3033{3034GEN F = idealfactor(nf,a), P = gel(F,1), E = gel(F,2);3035long i, r = lg(E);3036for (i=1; i<r; i++) gel(E,i) = stoi( idealval(nf,x,gel(P,i)) );3037return idealapprfact_i(nf,F,1);3038}30393040static void3041not_in_ideal(GEN a) {3042pari_err_DOMAIN("idealtwoelt2","element mod ideal", "!=", gen_0, a);3043}3044/* x integral in HNF, a an 'nf' */3045static int3046in_ideal(GEN x, GEN a)3047{3048switch(typ(a))3049{3050case t_INT: return dvdii(a, gcoeff(x,1,1));3051case t_COL: return RgV_is_ZV(a) && !!hnf_invimage(x, a);3052default: return 0;3053}3054}30553056/* Given an integral ideal x and a in x, gives a b such that3057* x = aZ_K + bZ_K using the approximation theorem */3058GEN3059idealtwoelt2(GEN nf, GEN x, GEN a)3060{3061pari_sp av = avma;3062GEN cx, b;30633064nf = checknf(nf);3065a = nf_to_scalar_or_basis(nf, a);3066x = idealhnf_shallow(nf,x);3067if (lg(x) == 1)3068{3069if (!isintzero(a)) not_in_ideal(a);3070set_avma(av); return gen_0;3071}3072x = Q_primitive_part(x, &cx);3073if (cx) a = gdiv(a, cx);3074if (!in_ideal(x, a)) not_in_ideal(a);3075b = mat_ideal_two_elt2(nf, x, a);3076if (typ(b) == t_COL)3077{3078GEN mod = idealhnf_principal(nf,a);3079b = ZC_hnfrem(b,mod);3080if (ZV_isscalar(b)) b = gel(b,1);3081}3082else3083{3084GEN aZ = typ(a) == t_COL? Q_denom(zk_inv(nf,a)): a; /* (a) \cap Z */3085b = centermodii(b, aZ, shifti(aZ,-1));3086}3087b = cx? gmul(b,cx): gcopy(b);3088return gerepileupto(av, b);3089}30903091/* Given 2 integral ideals x and y in nf, returns a beta in nf such that3092* beta * x is an integral ideal coprime to y */3093GEN3094idealcoprimefact(GEN nf, GEN x, GEN fy)3095{3096GEN L = gel(fy,1), e;3097long i, r = lg(L);30983099e = cgetg(r, t_COL);3100for (i=1; i<r; i++) gel(e,i) = stoi( -idealval(nf,x,gel(L,i)) );3101return idealapprfact_i(nf, mkmat2(L,e), 0);3102}3103GEN3104idealcoprime(GEN nf, GEN x, GEN y)3105{3106pari_sp av = avma;3107return gerepileupto(av, idealcoprimefact(nf, x, idealfactor(nf,y)));3108}31093110GEN3111nfmulmodpr(GEN nf, GEN x, GEN y, GEN modpr)3112{3113pari_sp av = avma;3114GEN z, p, pr = modpr, T;31153116nf = checknf(nf); modpr = nf_to_Fq_init(nf,&pr,&T,&p);3117x = nf_to_Fq(nf,x,modpr);3118y = nf_to_Fq(nf,y,modpr);3119z = Fq_mul(x,y,T,p);3120return gerepileupto(av, algtobasis(nf, Fq_to_nf(z,modpr)));3121}31223123GEN3124nfdivmodpr(GEN nf, GEN x, GEN y, GEN modpr)3125{3126pari_sp av = avma;3127nf = checknf(nf);3128return gerepileupto(av, nfreducemodpr(nf, nfdiv(nf,x,y), modpr));3129}31303131GEN3132nfpowmodpr(GEN nf, GEN x, GEN k, GEN modpr)3133{3134pari_sp av=avma;3135GEN z, T, p, pr = modpr;31363137nf = checknf(nf); modpr = nf_to_Fq_init(nf,&pr,&T,&p);3138z = nf_to_Fq(nf,x,modpr);3139z = Fq_pow(z,k,T,p);3140return gerepileupto(av, algtobasis(nf, Fq_to_nf(z,modpr)));3141}31423143GEN3144nfkermodpr(GEN nf, GEN x, GEN modpr)3145{3146pari_sp av = avma;3147GEN T, p, pr = modpr;31483149nf = checknf(nf); modpr = nf_to_Fq_init(nf, &pr,&T,&p);3150if (typ(x)!=t_MAT) pari_err_TYPE("nfkermodpr",x);3151x = nfM_to_FqM(x, nf, modpr);3152return gerepilecopy(av, FqM_to_nfM(FqM_ker(x,T,p), modpr));3153}31543155GEN3156nfsolvemodpr(GEN nf, GEN a, GEN b, GEN pr)3157{3158const char *f = "nfsolvemodpr";3159pari_sp av = avma;3160GEN T, p, modpr;31613162nf = checknf(nf);3163modpr = nf_to_Fq_init(nf, &pr,&T,&p);3164if (typ(a)!=t_MAT) pari_err_TYPE(f,a);3165a = nfM_to_FqM(a, nf, modpr);3166switch(typ(b))3167{3168case t_MAT:3169b = nfM_to_FqM(b, nf, modpr);3170b = FqM_gauss(a,b,T,p);3171if (!b) pari_err_INV(f,a);3172a = FqM_to_nfM(b, modpr);3173break;3174case t_COL:3175b = nfV_to_FqV(b, nf, modpr);3176b = FqM_FqC_gauss(a,b,T,p);3177if (!b) pari_err_INV(f,a);3178a = FqV_to_nfV(b, modpr);3179break;3180default: pari_err_TYPE(f,b);3181}3182return gerepilecopy(av, a);3183}318431853186