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/* RNF STRUCTURE AND OPERATIONS */17/* */18/*******************************************************************/19#include "pari.h"20#include "paripriv.h"2122#define DEBUGLEVEL DEBUGLEVEL_rnf2324/* eq is an rnfeq; must return a t_POL */25GEN26eltreltoabs(GEN eq, GEN x)27{28GEN Pabs = gel(eq,1), a = gel(eq,2), k = gel(eq,3), T = gel(eq,4), b, s;29long i, v = varn(Pabs);30pari_sp av = avma;3132if (varncmp(gvar(x), v) > 0) x = scalarpol(x,v);33x = RgX_nffix("eltreltoabs", T, x, 1);34/* Mod(X - k a, Pabs(X)) is a root of the relative polynomial */35if (signe(k))36x = RgXQX_translate(x, deg1pol_shallow(negi(k), gen_0, varn(T)), T);37b = pol_x(v);38s = gen_0;39for (i=lg(x)-1; i>1; i--)40{41GEN c = gel(x,i);42if (typ(c) == t_POL) c = RgX_RgXQ_eval(c, a, Pabs);43s = RgX_rem(gadd(c, gmul(b,s)), Pabs);44}45return gerepileupto(av, s);46}47GEN48rnfeltreltoabs(GEN rnf,GEN x)49{50const char *f = "rnfeltreltoabs";51GEN pol;52checkrnf(rnf);53pol = rnf_get_polabs(rnf);54switch(typ(x))55{56case t_INT: return icopy(x);57case t_FRAC: return gcopy(x);58case t_POLMOD:59if (RgX_equal_var(gel(x,1), pol))60{ /* already in 'abs' form, unless possibly if nf = Q */61if (rnf_get_nfdegree(rnf) == 1)62{63GEN y = gel(x,2);64pari_sp av = avma;65y = simplify_shallow(liftpol_shallow(y));66return gerepilecopy(av, mkpolmod(y, pol));67}68return gcopy(x);69}70x = polmod_nffix(f,rnf,x,0);71if (typ(x) == t_POLMOD) return rnfeltup(rnf,x);72retmkpolmod(eltreltoabs(rnf_get_map(rnf), x), ZX_copy(pol));73case t_POL:74if (varn(x) == rnf_get_nfvarn(rnf)) return rnfeltup(rnf,x);75retmkpolmod(eltreltoabs(rnf_get_map(rnf), x), ZX_copy(pol));76}77pari_err_TYPE(f,x);78return NULL;/*LCOV_EXCL_LINE*/79}8081GEN82eltabstorel_lift(GEN rnfeq, GEN P)83{84GEN k, T = gel(rnfeq,4), R = gel(rnfeq,5);85if (is_scalar_t(typ(P))) return P;86k = gel(rnfeq,3);87P = lift_shallow(P);88if (signe(k))89P = RgXQX_translate(P, deg1pol_shallow(k, gen_0, varn(T)), T);90P = RgXQX_rem(P, R, T);91return QXQX_to_mod_shallow(P, T);92}93/* rnfeq = [pol,a,k,T,R], P a t_POL or scalar94* Return Mod(P(x + k Mod(y, T(y))), pol(x)) */95GEN96eltabstorel(GEN rnfeq, GEN P)97{98GEN T = gel(rnfeq,4), R = gel(rnfeq,5);99return mkpolmod(eltabstorel_lift(rnfeq,P), QXQX_to_mod_shallow(R,T));100}101GEN102rnfeltabstorel(GEN rnf,GEN x)103{104const char *f = "rnfeltabstorel";105pari_sp av = avma;106GEN pol, T, P, NF;107checkrnf(rnf);108T = rnf_get_nfpol(rnf);109P = rnf_get_pol(rnf);110pol = rnf_get_polabs(rnf);111switch(typ(x))112{113case t_INT: return icopy(x);114case t_FRAC: return gcopy(x);115case t_POLMOD:116if (RgX_equal_var(P, gel(x,1)))117{118x = polmod_nffix(f, rnf, x, 0);119P = QXQX_to_mod_shallow(P,T);120return gerepilecopy(av, mkpolmod(x,P));121}122if (RgX_equal_var(T, gel(x,1))) { x = Rg_nffix(f, T, x, 0); goto END; }123if (!RgX_equal_var(pol, gel(x,1))) pari_err_MODULUS(f, gel(x,1),pol);124x = gel(x,2); break;125case t_POL: break;126case t_COL:127NF = obj_check(rnf, rnf_NFABS);128if (!NF) pari_err_TYPE("rnfeltabstorel, apply nfinit(rnf)",x);129x = nf_to_scalar_or_alg(NF,x); break;130default:131pari_err_TYPE(f,x);132return NULL;/*LCOV_EXCL_LINE*/133}134switch(typ(x))135{136case t_INT: return icopy(x);137case t_FRAC: return gcopy(x);138case t_POL: break;139default: pari_err_TYPE(f, x);140}141RgX_check_QX(x,f);142if (varn(x) != varn(pol))143{144if (varn(x) == varn(T)) { x = Rg_nffix(f,T,x,0); goto END; }145pari_err_VAR(f, x,pol);146}147switch(lg(x))148{149case 2: set_avma(av); return gen_0;150case 3: return gerepilecopy(av, gel(x,2));151}152END:153return gerepilecopy(av, eltabstorel(rnf_get_map(rnf), x));154}155156/* x a t_VEC of rnf elements in 'alg' form (t_POL). Assume maximal rank or 0 */157static GEN158modulereltoabs(GEN rnf, GEN x)159{160GEN W=gel(x,1), I=gel(x,2), rnfeq = rnf_get_map(rnf), polabs = gel(rnfeq,1);161long i, j, k, m, N = lg(W)-1;162GEN zknf, dzknf, M;163164if (!N) return cgetg(1, t_VEC);165zknf = rnf_get_nfzk(rnf);166dzknf = gel(zknf,1);167m = rnf_get_nfdegree(rnf);168M = cgetg(N*m+1, t_VEC);169for (k=i=1; i<=N; i++)170{171GEN c0, cid, w = gel(W,i), id = gel(I,i);172173if (lg(id) == 1) continue; /* must be a t_MAT */174id = Q_primitive_part(id, &cid);175w = Q_primitive_part(eltreltoabs(rnfeq,w), &c0);176c0 = div_content(mul_content(c0,cid), dzknf);177if (typ(id) == t_INT)178for (j=1; j<=m; j++)179{180GEN z = RgX_rem(gmul(w, gel(zknf,j)), polabs);181if (c0) z = RgX_Rg_mul(z, c0);182gel(M,k++) = z;183}184else185for (j=1; j<=m; j++)186{187GEN c, z = Q_primitive_part(RgV_RgC_mul(zknf,gel(id,j)), &c);188z = RgX_rem(gmul(w, z), polabs);189c = mul_content(c, c0); if (c) z = RgX_Rg_mul(z, c);190gel(M,k++) = z;191}192}193setlg(M, k); return M;194}195196/* Z-basis for absolute maximal order: [NF.pol, NF.zk] */197GEN198rnf_zkabs(GEN rnf)199{200GEN d, v, M = modulereltoabs(rnf, rnf_get_zk(rnf));201GEN T = rnf_get_polabs(rnf);202long n = degpol(T);203M = Q_remove_denom(M, &d); /* t_VEC of t_POL */204if (d)205{206M = RgXV_to_RgM(M,n);207M = ZM_hnfmodall(M, d, hnf_MODID|hnf_CENTER);208M = RgM_Rg_div(M, d);209}210else211M = matid(n);212v = rnf_get_ramified_primes(rnf);213if (lg(v) == 1)214{215GEN D = gel(rnf_get_disc(rnf),1);216if (!isint1(D)) pari_err_TYPE("rnf_zkabs (old style rnf)", rnf);217}218v = shallowconcat(nf_get_ramified_primes(rnf_get_nf(rnf)), v);219return mkvec3(T, RgM_to_RgXV(M, varn(T)), ZV_sort_uniq(v));220}221222static GEN223mknfabs(GEN rnf, long prec)224{225GEN NF;226if ((NF = obj_check(rnf,rnf_NFABS)))227{ if (nf_get_prec(NF) < prec) NF = nfnewprec_shallow(NF,prec); }228else229NF = nfinit(rnf_zkabs(rnf), prec);230return NF;231}232233static GEN234mkupdown(GEN rnf)235{236GEN NF = obj_check(rnf, rnf_NFABS), M, zknf, dzknf;237long i, l;238zknf = rnf_get_nfzk(rnf);239dzknf = gel(zknf,1); if (gequal1(dzknf)) dzknf = NULL;240l = lg(zknf); M = cgetg(l, t_MAT);241gel(M,1) = vec_ei(nf_get_degree(NF), 1);242for (i = 2; i < l; i++)243{244GEN c = poltobasis(NF, gel(zknf,i));245if (dzknf) c = gdiv(c, dzknf);246gel(M,i) = c;247}248return Qevproj_init(M);249}250GEN251rnf_build_nfabs(GEN rnf, long prec)252{253GEN NF = obj_checkbuild_prec(rnf, rnf_NFABS, &mknfabs, &nf_get_prec, prec);254(void)obj_checkbuild(rnf, rnf_MAPS, &mkupdown);255return NF;256}257258void259rnfcomplete(GEN rnf)260{ (void)rnf_build_nfabs(rnf, nf_get_prec(rnf_get_nf(rnf))); }261262GEN263nf_nfzk(GEN nf, GEN rnfeq)264{265GEN pol = gel(rnfeq,1), a = gel(rnfeq,2);266return Q_primpart(QXV_QXQ_eval(nf_get_zkprimpart(nf), a, pol));267}268269static GEN270rnfdisc_get_T_i(GEN P, GEN *lim)271{272*lim = NULL;273if (typ(P) == t_VEC && lg(P) == 3)274{275GEN L = gel(P,2);276long i, l;277*lim = L;278switch(typ(L))279{280case t_INT:281if (signe(L) <= 0) return NULL;282break;283case t_VEC: case t_COL:284l = lg(L);285for (i = 1; i < l; i++)286{287GEN p = gel(L,i);288if (typ(p) == t_INT)289{ if (signe(p) <= 0) return NULL; }290else checkprid(p);291}292break;293default: return NULL;294}295P = gel(P,1);296}297return (typ(P) == t_POL)? P: NULL;298}299/* true nf */300GEN301rnfdisc_get_T(GEN nf, GEN P, GEN *lim)302{303GEN T = rnfdisc_get_T_i(P, lim);304if (!T) pari_err_TYPE("rnfdisc",P);305return RgX_nffix("rnfdisc", nf_get_pol(nf), T, 1);306}307308GEN309rnfpseudobasis(GEN nf, GEN pol)310{311pari_sp av = avma;312GEN D, z, lim;313nf = checknf(nf);314pol = rnfdisc_get_T(nf, pol, &lim);315z = rnfallbase(nf, pol, lim, NULL, &D, NULL, NULL);316return gerepilecopy(av, shallowconcat(z,D));317}318319GEN320rnfinit0(GEN nf, GEN T, long flag)321{322pari_sp av = avma;323GEN lim, bas, D, f, B, DKP, rnfeq, rnf = obj_init(11, 2);324nf = checknf(nf);325T = rnfdisc_get_T(nf, T, &lim);326gel(rnf,11) = rnfeq = nf_rnfeq(nf,T);327gel(rnf,2) = nf_nfzk(nf, rnfeq);328bas = rnfallbase(nf, T, lim, rnf, &D, &f, &DKP);329B = matbasistoalg(nf,gel(bas,1));330gel(bas,1) = lift_if_rational( RgM_to_RgXV(B,varn(T)) );331gel(rnf,1) = T;332gel(rnf,3) = D;333gel(rnf,4) = f;334gel(rnf,5) = DKP;335gel(rnf,6) = cgetg(1, t_VEC); /* dummy */336gel(rnf,7) = bas;337gel(rnf,8) = lift_if_rational( RgM_inv_upper(B) );338gel(rnf,9) = typ(f) == t_INT? powiu(f, nf_get_degree(nf))339: RgM_det_triangular(f);340gel(rnf,10)= nf;341rnf = gerepilecopy(av, rnf);342if (flag) rnfcomplete(rnf);343return rnf;344}345GEN346rnfinit(GEN nf, GEN T) { return rnfinit0(nf,T,0); }347348GEN349rnfeltup0(GEN rnf, GEN x, long flag)350{351pari_sp av = avma;352GEN zknf, nf, NF, POL;353long tx = typ(x);354checkrnf(rnf);355if (flag) rnfcomplete(rnf);356NF = obj_check(rnf,rnf_NFABS);357POL = rnf_get_polabs(rnf);358if (tx == t_POLMOD && RgX_equal_var(gel(x,1), POL))359{360if (flag) x = nf_to_scalar_or_basis(NF,x);361return gerepilecopy(av, x);362}363nf = rnf_get_nf(rnf);364if (NF && tx == t_COL && lg(x)-1 == degpol(POL) && nf_get_degree(rnf) > 1)365{366x = flag? nf_to_scalar_or_basis(NF,x)367: mkpolmod(nf_to_scalar_or_alg(NF,x), POL);368return gerepilecopy(av, x);369}370if (NF)371{372GEN d, proj;373x = nf_to_scalar_or_basis(nf, x);374if (typ(x) != t_COL) return gerepilecopy(av, x);375proj = obj_check(rnf,rnf_MAPS);376x = Q_remove_denom(x,&d);377x = ZM_ZC_mul(gel(proj,1), x);378if (d) x = gdiv(x,d);379if (!flag) x = basistoalg(NF,x);380}381else382{383zknf = rnf_get_nfzk(rnf);384x = nfeltup(nf, x, zknf);385if (typ(x) == t_POL) x = mkpolmod(x, POL);386}387return gerepilecopy(av, x);388}389GEN390rnfeltup(GEN rnf, GEN x) { return rnfeltup0(rnf,x,0); }391392GEN393nfeltup(GEN nf, GEN x, GEN zknf)394{395GEN c, dzknf = gel(zknf,1);396x = nf_to_scalar_or_basis(nf, x);397if (typ(x) != t_COL) return x;398x = Q_primitive_part(x, &c);399if (!RgV_is_ZV(x)) pari_err_TYPE("rnfeltup", x);400if (gequal1(dzknf)) dzknf = NULL;401c = div_content(c, dzknf);402x = RgV_RgC_mul(zknf, x); if (c) x = RgX_Rg_mul(x, c);403return x;404}405406static void407fail(const char *f, GEN x)408{ pari_err_DOMAIN(f,"element","not in", strtoGENstr("the base field"),x); }409/* x t_COL of length degabs */410static GEN411eltdown(GEN rnf, GEN x, long flag)412{413GEN z,y, d, proj = obj_check(rnf,rnf_MAPS);414GEN M= gel(proj,1), iM=gel(proj,2), diM=gel(proj,3), perm=gel(proj,4);415x = Q_remove_denom(x,&d);416if (!RgV_is_ZV(x)) pari_err_TYPE("rnfeltdown", x);417y = ZM_ZC_mul(iM, vecpermute(x, perm));418z = ZM_ZC_mul(M,y);419if (!isint1(diM)) z = ZC_Z_mul(z,diM);420if (!ZV_equal(z,x)) fail("rnfeltdown",x);421422d = mul_denom(d, diM);423if (d) y = gdiv(y,d);424if (!flag) y = basistoalg(rnf_get_nf(rnf), y);425return y;426}427GEN428rnfeltdown0(GEN rnf, GEN x, long flag)429{430const char *f = "rnfeltdown";431pari_sp av = avma;432GEN z, T, NF, nf;433long v;434435checkrnf(rnf);436NF = obj_check(rnf,rnf_NFABS);437nf = rnf_get_nf(rnf);438T = nf_get_pol(nf);439v = varn(T);440switch(typ(x))441{ /* directly belonging to base field ? */442case t_INT: return icopy(x);443case t_FRAC:return gcopy(x);444case t_POLMOD:445if (RgX_equal_var(gel(x,1), rnf_get_polabs(rnf)))446{447if (degpol(T) == 1)448{449x = simplify_shallow(liftpol_shallow(gel(x,2)));450if (typ(x) != t_POL) return gerepilecopy(av,x);451}452break;453}454x = polmod_nffix(f,rnf,x,0);455/* x was defined mod the relative polynomial & non constant => fail */456if (typ(x) == t_POL) fail(f,x);457if (flag) x = nf_to_scalar_or_basis(nf,x);458return gerepilecopy(av, x);459460case t_POL:461if (varn(x) != v) break;462x = Rg_nffix(f,T,x,0);463if (flag) x = nf_to_scalar_or_basis(nf,x);464return gerepilecopy(av, x);465case t_COL:466{467long n = lg(x)-1;468if (n == degpol(T) && RgV_is_QV(x))469{470if (RgV_isscalar(x)) return gcopy(gel(x,1));471if (!flag) return gcopy(x);472return basistoalg(nf,x);473}474if (NF) break;475}476default: pari_err_TYPE(f, x);477}478/* x defined mod the absolute equation */479if (NF)480{481x = nf_to_scalar_or_basis(NF, x);482if (typ(x) == t_COL) x = eltdown(rnf,x,flag);483return gerepilecopy(av, x);484}485z = rnfeltabstorel(rnf,x);486switch(typ(z))487{488case t_INT:489case t_FRAC: return z;490}491/* typ(z) = t_POLMOD, varn of both components is rnf_get_varn(rnf) */492z = gel(z,2);493if (typ(z) == t_POL)494{495if (lg(z) != 3) fail(f,x);496z = gel(z,2);497}498return gerepilecopy(av, z);499}500GEN501rnfeltdown(GEN rnf, GEN x) { return rnfeltdown0(rnf,x,0); }502503/* vector of rnf elt -> matrix of nf elts */504static GEN505rnfV_to_nfM(GEN rnf, GEN x)506{507long i, l = lg(x);508GEN y = cgetg(l, t_MAT);509for (i = 1; i < l; i++) gel(y,i) = rnfalgtobasis(rnf,gel(x,i));510return y;511}512513static GEN514rnfprincipaltohnf(GEN rnf,GEN x)515{516pari_sp av = avma;517GEN bas = rnf_get_zk(rnf), nf = rnf_get_nf(rnf);518x = rnfbasistoalg(rnf,x);519x = gmul(x, gmodulo(gel(bas,1), rnf_get_pol(rnf)));520return gerepileupto(av, nfhnf(nf, mkvec2(rnfV_to_nfM(rnf,x), gel(bas,2))));521}522523/* pseudo-basis for the 0 ideal */524static GEN525rnfideal0(void) { retmkvec2(cgetg(1,t_MAT),cgetg(1,t_VEC)); }526527GEN528rnfidealhnf(GEN rnf, GEN x)529{530GEN z, nf, bas;531532checkrnf(rnf); nf = rnf_get_nf(rnf);533switch(typ(x))534{535case t_INT: case t_FRAC:536if (isintzero(x)) return rnfideal0();537bas = rnf_get_zk(rnf); z = cgetg(3,t_VEC);538gel(z,1) = matid(rnf_get_degree(rnf));539gel(z,2) = gmul(x, gel(bas,2)); return z;540541case t_VEC:542if (lg(x) == 3 && typ(gel(x,1)) == t_MAT) return nfhnf(nf, x);543case t_MAT:544return rnfidealabstorel(rnf, x);545546case t_POLMOD: case t_POL: case t_COL:547return rnfprincipaltohnf(rnf,x);548}549pari_err_TYPE("rnfidealhnf",x);550return NULL; /* LCOV_EXCL_LINE */551}552553static GEN554prodidnorm(GEN nf, GEN I)555{556long i, l = lg(I);557GEN z;558if (l == 1) return gen_1;559z = idealnorm(nf, gel(I,1));560for (i=2; i<l; i++) z = gmul(z, idealnorm(nf, gel(I,i)));561return z;562}563564GEN565rnfidealnormrel(GEN rnf, GEN id)566{567pari_sp av = avma;568GEN nf, z = gel(rnfidealhnf(rnf,id), 2);569if (lg(z) == 1) return cgetg(1, t_MAT);570nf = rnf_get_nf(rnf); z = idealprod(nf, z);571return gerepileupto(av, idealmul(nf,z, rnf_get_index(rnf)));572}573574GEN575rnfidealnormabs(GEN rnf, GEN id)576{577pari_sp av = avma;578GEN nf, z = gel(rnfidealhnf(rnf,id), 2);579if (lg(z) == 1) return gen_0;580nf = rnf_get_nf(rnf); z = prodidnorm(nf, z);581return gerepileupto(av, gmul(z, gel(rnf,9)));582}583584static GEN585rnfidealreltoabs_i(GEN rnf, GEN x)586{587long i, l;588GEN w;589x = rnfidealhnf(rnf,x);590w = gel(x,1); l = lg(w); settyp(w, t_VEC);591for (i=1; i<l; i++) gel(w,i) = lift_shallow( rnfbasistoalg(rnf, gel(w,i)) );592return modulereltoabs(rnf, x);593}594GEN595rnfidealreltoabs(GEN rnf, GEN x)596{597pari_sp av = avma;598return gerepilecopy(av, rnfidealreltoabs_i(rnf,x));599}600GEN601rnfidealreltoabs0(GEN rnf, GEN x, long flag)602{603pari_sp av = avma;604long i, l;605GEN NF;606607x = rnfidealreltoabs_i(rnf, x);608if (!flag) return gerepilecopy(av,x);609rnfcomplete(rnf);610NF = obj_check(rnf,rnf_NFABS);611l = lg(x); settyp(x, t_MAT);612for (i=1; i<l; i++) gel(x,i) = algtobasis(NF, gel(x,i));613return gerepileupto(av, idealhnf(NF,x));614}615616GEN617rnfidealabstorel(GEN rnf, GEN x)618{619long n, N, j, tx = typ(x);620pari_sp av = avma;621GEN A, I, invbas;622623checkrnf(rnf);624invbas = rnf_get_invzk(rnf);625if (tx != t_VEC && tx != t_MAT) pari_err_TYPE("rnfidealabstorel",x);626N = lg(x)-1;627if (N != rnf_get_absdegree(rnf))628{629if (!N) return rnfideal0();630pari_err_DIM("rnfidealabstorel");631}632n = rnf_get_degree(rnf);633A = cgetg(N+1,t_MAT);634I = cgetg(N+1,t_VEC);635for (j=1; j<=N; j++)636{637GEN t = lift_shallow( rnfeltabstorel(rnf, gel(x,j)) );638if (typ(t) == t_POL)639t = RgM_RgX_mul(invbas, t);640else641t = scalarcol_shallow(t, n);642gel(A,j) = t;643gel(I,j) = gen_1;644}645return gerepileupto(av, nfhnf(rnf_get_nf(rnf), mkvec2(A,I)));646}647648GEN649rnfidealdown(GEN rnf,GEN x)650{651pari_sp av = avma;652GEN I;653if (typ(x) == t_MAT)654{655GEN d;656x = Q_remove_denom(x,&d);657if (RgM_is_ZM(x))658{659GEN NF = obj_check(rnf,rnf_NFABS);660if (NF)661{662GEN z, proj = obj_check(rnf,rnf_MAPS), ZK = gel(proj,1);663long i, lz, l;664x = idealhnf(NF,x);665if (lg(x) == 1) { set_avma(av); return cgetg(1,t_MAT); }666z = ZM_lll(shallowconcat(ZK,x), 0.99, LLL_KER);667lz = lg(z); l = lg(ZK);668for (i = 1; i < lz; i++) setlg(gel(z,i), l);669z = ZM_hnfmodid(z, gcoeff(x,1,1));670if (d) z = gdiv(z,d);671return gerepileupto(av, z);672}673}674}675x = rnfidealhnf(rnf,x); I = gel(x,2);676if (lg(I) == 1) { set_avma(av); return cgetg(1,t_MAT); }677return gerepilecopy(av, gel(I,1));678}679680/* lift ideal x to the relative extension, returns a Z-basis */681GEN682rnfidealup(GEN rnf,GEN x)683{684pari_sp av = avma;685long i, n;686GEN nf, bas, bas2, I, x2, dx;687688checkrnf(rnf); nf = rnf_get_nf(rnf);689n = rnf_get_degree(rnf);690bas = rnf_get_zk(rnf); bas2 = gel(bas,2);691692(void)idealtyp(&x, &I); /* I is junk */693x = Q_remove_denom(x, &dx);694x2 = idealtwoelt(nf,x);695I = cgetg(n+1,t_VEC);696for (i=1; i<=n; i++)697{698GEN c = gel(bas2,i), d;699if (typ(c) == t_MAT)700{701c = Q_remove_denom(c,&d);702d = mul_denom(d, dx);703c = idealHNF_mul(nf,c,x2);704}705else706{707c = idealmul(nf,c,x);708d = dx;709}710if (d) c = gdiv(c,d);711gel(I,i) = c;712}713return gerepilecopy(av, modulereltoabs(rnf, mkvec2(gel(bas,1), I)));714}715GEN716rnfidealup0(GEN rnf,GEN x, long flag)717{718pari_sp av = avma;719GEN NF, nf, proj, d, x2;720721if (!flag) return rnfidealup(rnf,x);722checkrnf(rnf); nf = rnf_get_nf(rnf);723rnfcomplete(rnf);724proj = obj_check(rnf,rnf_MAPS);725NF = obj_check(rnf,rnf_NFABS);726727(void)idealtyp(&x, &d); /* d is junk */728x2 = idealtwoelt(nf,x);729x2 = Q_remove_denom(x2,&d);730if (typ(gel(x2,2)) == t_COL) gel(x2,2) = ZM_ZC_mul(gel(proj,1),gel(x2,2));731x2 = idealhnf_two(NF, x2);732if (d) x2 = gdiv(x2,d);733return gerepileupto(av, x2);734}735736/* x a relative HNF => vector of 2 generators (relative polmods) */737GEN738rnfidealtwoelement(GEN rnf, GEN x)739{740pari_sp av = avma;741GEN y, cy, z, NF;742743y = rnfidealreltoabs_i(rnf,x);744rnfcomplete(rnf);745NF = obj_check(rnf,rnf_NFABS);746y = matalgtobasis(NF, y); settyp(y, t_MAT);747y = Q_primitive_part(y, &cy);748y = ZM_hnf(y);749if (lg(y) == 1) { set_avma(av); return mkvec2(gen_0, gen_0); }750y = idealtwoelt(NF, y);751if (cy) y = RgV_Rg_mul(y, cy);752z = gel(y,2);753if (typ(z) == t_COL) z = rnfeltabstorel(rnf, nf_to_scalar_or_alg(NF, z));754return gerepilecopy(av, mkvec2(gel(y,1), z));755}756757GEN758rnfidealmul(GEN rnf,GEN x,GEN y)759{760pari_sp av = avma;761GEN nf, z, x1, x2, p1, p2, bas;762763y = rnfidealtwoelement(rnf,y);764if (isintzero(gel(y,1))) { set_avma(av); return rnfideal0(); }765nf = rnf_get_nf(rnf);766bas = rnf_get_zk(rnf);767x = rnfidealhnf(rnf,x);768x1 = gmodulo(gmul(gel(bas,1), matbasistoalg(nf,gel(x,1))), rnf_get_pol(rnf));769x2 = gel(x,2);770p1 = gmul(gel(y,1), gel(x,1));771p2 = rnfV_to_nfM(rnf, gmul(gel(y,2), x1));772z = mkvec2(shallowconcat(p1, p2), shallowconcat(x2, x2));773return gerepileupto(av, nfhnf(nf,z));774}775776/* prK wrt NF ~ Q[x]/(polabs) */777static GEN778rnfidealprimedec_1(GEN rnf, GEN SL, GEN prK)779{780GEN v, piL, piK = pr_get_gen(prK);781long i, c, l;782if (pr_is_inert(prK)) return SL;783piL = rnfeltup0(rnf, piK, 1);784v = cgetg_copy(SL, &l);785for (i = c = 1; i < l; i++)786{787GEN P = gel(SL,i);788if (ZC_prdvd(piL, P)) gel(v,c++) = P;789}790setlg(v, c); return v;791}792GEN793rnfidealprimedec(GEN rnf, GEN pr)794{795pari_sp av = avma;796GEN p, z, NF, nf, SL;797checkrnf(rnf);798rnfcomplete(rnf);799NF = obj_check(rnf,rnf_NFABS);800nf = rnf_get_nf(rnf);801if (typ(pr) == t_INT) { p = pr; pr = NULL; }802else { checkprid(pr); p = pr_get_p(pr); }803SL = idealprimedec(NF, p);804if (pr) z = rnfidealprimedec_1(rnf, SL, pr);805else806{807GEN vK = idealprimedec(nf, p), vL;808long l = lg(vK), i;809vL = cgetg(l, t_VEC);810for (i = 1; i < l; i++) gel(vL,i) = rnfidealprimedec_1(rnf, SL, gel(vK,i));811z = mkvec2(vK, vL);812}813return gerepilecopy(av, z);814}815816GEN817rnfidealfactor(GEN rnf, GEN x)818{819pari_sp av = avma;820GEN NF;821checkrnf(rnf);822rnfcomplete(rnf);823NF = obj_check(rnf,rnf_NFABS);824return gerepileupto(av, idealfactor(NF, rnfidealreltoabs0(rnf, x, 1)));825}826827GEN828rnfequationall(GEN A, GEN B, long *pk, GEN *pLPRS)829{830long lA, lB;831GEN nf, C;832833A = get_nfpol(A, &nf); lA = lg(A);834if (!nf) {835if (lA<=3) pari_err_CONSTPOL("rnfequation");836RgX_check_ZX(A,"rnfequation");837}838B = RgX_nffix("rnfequation", A,B,1); lB = lg(B);839if (lB<=3) pari_err_CONSTPOL("rnfequation");840B = Q_primpart(B);841842if (!nfissquarefree(A,B))843pari_err_DOMAIN("rnfequation","issquarefree(B)","=",gen_0,B);844845*pk = 0; C = ZX_ZXY_resultant_all(A, B, pk, pLPRS);846if (signe(leading_coeff(C)) < 0) C = ZX_neg(C);847*pk = -*pk; return Q_primpart(C);848}849850GEN851rnfequation0(GEN A, GEN B, long flall)852{853pari_sp av = avma;854GEN LPRS, C;855long k;856857C = rnfequationall(A, B, &k, flall? &LPRS: NULL);858if (flall)859{ /* a,b,c root of A,B,C = compositum, c = b + k a */860GEN a, mH0 = RgX_neg(gel(LPRS,1)), H1 = gel(LPRS,2);861a = QXQ_div(mH0, H1, C);862C = mkvec3(C, mkpolmod(a, C), stoi(k));863}864return gerepilecopy(av, C);865}866GEN867rnfequation(GEN nf, GEN pol) { return rnfequation0(nf,pol,0); }868GEN869rnfequation2(GEN nf, GEN pol) { return rnfequation0(nf,pol,1); }870GEN871nf_rnfeq(GEN nf, GEN R)872{873GEN pol, a, k, junk, eq;874R = liftpol_shallow(R);875eq = rnfequation2(nf, R);876pol = gel(eq,1);877a = gel(eq,2); if (typ(a) == t_POLMOD) a = gel(a,2);878k = gel(eq,3);879return mkvec5(pol,a,k,get_nfpol(nf, &junk),R);880}881/* only allow abstorel */882GEN883nf_rnfeqsimple(GEN nf, GEN R)884{885long sa;886GEN junk, pol;887R = liftpol_shallow(R);888pol = rnfequationall(nf, R, &sa, NULL);889return mkvec5(pol,gen_0/*dummy*/,stoi(sa),get_nfpol(nf, &junk),R);890}891892/*******************************************************************/893/* */894/* RELATIVE LLL */895/* */896/*******************************************************************/897static GEN898nftau(long r1, GEN x)899{900long i, l = lg(x);901GEN s = r1? gel(x,1): gmul2n(real_i(gel(x,1)),1);902for (i=2; i<=r1; i++) s = gadd(s, gel(x,i));903for ( ; i < l; i++) s = gadd(s, gmul2n(real_i(gel(x,i)),1));904return s;905}906907static GEN908initmat(long l)909{910GEN x = cgetg(l, t_MAT);911long i;912for (i = 1; i < l; i++) gel(x,i) = cgetg(l, t_COL);913return x;914}915916static GEN917nftocomplex(GEN nf, GEN x)918{919GEN M = nf_get_M(nf);920x = nf_to_scalar_or_basis(nf,x);921if (typ(x) != t_COL) return const_col(nbrows(M), x);922return RgM_RgC_mul(M, x);923}924/* assume x a square t_MAT, return a t_VEC of embeddings of its columns */925static GEN926mattocomplex(GEN nf, GEN x)927{928long i,j, l = lg(x);929GEN v = cgetg(l, t_VEC);930for (j=1; j<l; j++)931{932GEN c = gel(x,j), b = cgetg(l, t_MAT);933for (i=1; i<l; i++) gel(b,i) = nftocomplex(nf, gel(c,i));934b = shallowtrans(b); settyp(b, t_COL);935gel(v,j) = b;936}937return v;938}939940static GEN941nf_all_roots(GEN nf, GEN x, long prec)942{943long i, j, l = lg(x), ru = lg(nf_get_roots(nf));944GEN y = cgetg(l, t_POL), v, z;945946x = RgX_to_nfX(nf, x);947y[1] = x[1];948for (i=2; i<l; i++) gel(y,i) = nftocomplex(nf, gel(x,i));949i = gprecision(y); if (i && i <= 3) return NULL;950951v = cgetg(ru, t_VEC);952z = cgetg(l, t_POL); z[1] = x[1];953for (i=1; i<ru; i++)954{955for (j = 2; j < l; j++) gel(z,j) = gmael(y,j,i);956gel(v,i) = cleanroots(z, prec);957}958return v;959}960961static GEN962rnfscal(GEN m, GEN x, GEN y)963{964long i, l = lg(m);965GEN z = cgetg(l, t_COL);966for (i = 1; i < l; i++)967gel(z,i) = gmul(conj_i(shallowtrans(gel(x,i))), gmul(gel(m,i), gel(y,i)));968return z;969}970971/* x ideal in HNF */972static GEN973findmin(GEN nf, GEN x, GEN muf)974{975pari_sp av = avma;976long e;977GEN cx, y, m, M = nf_get_M(nf);978979x = Q_primitive_part(x, &cx);980if (gequal1(gcoeff(x,1,1))) y = M;981else982{983GEN G = nf_get_G(nf);984m = lllfp(RgM_mul(G,x), 0.75, 0);985if (typ(m) != t_MAT)986{987x = ZM_lll(x, 0.75, LLL_INPLACE);988m = lllfp(RgM_mul(G,x), 0.75, 0);989if (typ(m) != t_MAT) pari_err_PREC("rnflllgram");990}991x = ZM_mul(x, m);992y = RgM_mul(M, x);993}994m = RgM_solve_realimag(y, muf);995if (!m) return NULL; /* precision problem */996if (cx) m = RgC_Rg_div(m, cx);997m = grndtoi(m, &e);998if (e >= 0) return NULL; /* precision problem */999m = ZM_ZC_mul(x, m);1000if (cx) m = ZC_Q_mul(m, cx);1001return gerepileupto(av, m);1002}10031004static int1005RED(long k, long l, GEN U, GEN mu, GEN MC, GEN nf, GEN I, GEN *Ik_inv)1006{1007GEN x, xc, ideal;1008long i;10091010if (!*Ik_inv) *Ik_inv = idealinv(nf, gel(I,k));1011ideal = idealmul(nf,gel(I,l), *Ik_inv);1012x = findmin(nf, ideal, gcoeff(mu,k,l));1013if (!x) return 0;1014if (gequal0(x)) return 1;10151016xc = nftocomplex(nf,x);1017gel(MC,k) = gsub(gel(MC,k), vecmul(xc,gel(MC,l)));1018gel(U,k) = gsub(gel(U,k), gmul(coltoalg(nf,x), gel(U,l)));1019gcoeff(mu,k,l) = gsub(gcoeff(mu,k,l), xc);1020for (i=1; i<l; i++)1021gcoeff(mu,k,i) = gsub(gcoeff(mu,k,i), vecmul(xc,gcoeff(mu,l,i)));1022return 1;1023}10241025static int1026check_0(GEN B)1027{1028long i, l = lg(B);1029for (i = 1; i < l; i++)1030if (gsigne(gel(B,i)) <= 0) return 1;1031return 0;1032}10331034static int1035do_SWAP(GEN I, GEN MC, GEN MCS, GEN h, GEN mu, GEN B, long kmax, long k,1036const long alpha, long r1)1037{1038GEN p1, p2, muf, mufc, Bf, temp;1039long i, j;10401041p1 = nftau(r1, gadd(gel(B,k),1042gmul(gnorml2(gcoeff(mu,k,k-1)), gel(B,k-1))));1043p2 = nftau(r1, gel(B,k-1));1044if (gcmp(gmulsg(alpha,p1), gmulsg(alpha-1,p2)) > 0) return 0;10451046swap(gel(MC,k-1),gel(MC,k));1047swap(gel(h,k-1), gel(h,k));1048swap(gel(I,k-1), gel(I,k));1049for (j=1; j<=k-2; j++) swap(gcoeff(mu,k-1,j),gcoeff(mu,k,j));1050muf = gcoeff(mu,k,k-1);1051mufc = conj_i(muf);1052Bf = gadd(gel(B,k), vecmul(real_i(vecmul(muf,mufc)), gel(B,k-1)));1053if (check_0(Bf)) return 1; /* precision problem */10541055p1 = vecdiv(gel(B,k-1),Bf);1056gcoeff(mu,k,k-1) = vecmul(mufc,p1);1057temp = gel(MCS,k-1);1058gel(MCS,k-1) = gadd(gel(MCS,k), vecmul(muf,gel(MCS,k-1)));1059gel(MCS,k) = gsub(vecmul(vecdiv(gel(B,k),Bf), temp),1060vecmul(gcoeff(mu,k,k-1), gel(MCS,k)));1061gel(B,k) = vecmul(gel(B,k),p1);1062gel(B,k-1) = Bf;1063for (i=k+1; i<=kmax; i++)1064{1065temp = gcoeff(mu,i,k);1066gcoeff(mu,i,k) = gsub(gcoeff(mu,i,k-1), vecmul(muf, gcoeff(mu,i,k)));1067gcoeff(mu,i,k-1) = gadd(temp, vecmul(gcoeff(mu,k,k-1),gcoeff(mu,i,k)));1068}1069return 1;1070}10711072static GEN1073rel_T2(GEN nf, GEN pol, long lx, long prec)1074{1075long ru, i, j, k, l;1076GEN T2, s, unro, roorder, powreorder;10771078roorder = nf_all_roots(nf, pol, prec);1079if (!roorder) return NULL;1080ru = lg(roorder);1081unro = cgetg(lx,t_COL); for (i=1; i<lx; i++) gel(unro,i) = gen_1;1082powreorder = cgetg(lx,t_MAT); gel(powreorder,1) = unro;1083T2 = cgetg(ru, t_VEC);1084for (i = 1; i < ru; i++)1085{1086GEN ro = gel(roorder,i);1087GEN m = initmat(lx);1088for (k=2; k<lx; k++)1089{1090GEN c = cgetg(lx, t_COL); gel(powreorder,k) = c;1091for (j=1; j < lx; j++)1092gel(c,j) = gmul(gel(ro,j), gmael(powreorder,k-1,j));1093}1094for (l = 1; l < lx; l++)1095for (k = 1; k <= l; k++)1096{1097s = gen_0;1098for (j = 1; j < lx; j++)1099s = gadd(s, gmul(conj_i(gmael(powreorder,k,j)),1100gmael(powreorder,l,j)));1101if (l == k)1102gcoeff(m, l, l) = real_i(s);1103else1104{1105gcoeff(m, k, l) = s;1106gcoeff(m, l, k) = conj_i(s);1107}1108}1109gel(T2,i) = m;1110}1111return T2;1112}11131114/* given a base field nf (e.g main variable y), a polynomial pol with1115* coefficients in nf (e.g main variable x), and an order as output1116* by rnfpseudobasis, outputs a reduced order. */1117GEN1118rnflllgram(GEN nf, GEN pol, GEN order,long prec)1119{1120pari_sp av = avma;1121long j, k, l, kmax, r1, lx, count = 0;1122GEN M, I, h, H, mth, MC, MPOL, MCS, B, mu;1123const long alpha = 10, MAX_COUNT = 4;11241125nf = checknf(nf); r1 = nf_get_r1(nf);1126check_ZKmodule(order, "rnflllgram");1127M = gel(order,1);1128I = gel(order,2); lx = lg(I);1129if (lx < 3) return gcopy(order);1130if (lx-1 != degpol(pol)) pari_err_DIM("rnflllgram");1131I = leafcopy(I);1132H = NULL;1133MPOL = matbasistoalg(nf, M);1134MCS = matid(lx-1); /* dummy for gerepile */1135PRECNF:1136if (count == MAX_COUNT)1137{1138prec = precdbl(prec); count = 0;1139if (DEBUGLEVEL) pari_warn(warnprec,"rnflllgram",prec);1140nf = nfnewprec_shallow(nf,prec);1141}1142mth = rel_T2(nf, pol, lx, prec);1143if (!mth) { count = MAX_COUNT; goto PRECNF; }1144h = NULL;1145PRECPB:1146if (h)1147{ /* precision problem, recompute. If no progress, increase nf precision */1148if (++count == MAX_COUNT || RgM_isidentity(h)) {count = MAX_COUNT; goto PRECNF;}1149H = H? gmul(H, h): h;1150MPOL = gmul(MPOL, h);1151}1152h = matid(lx-1);1153MC = mattocomplex(nf, MPOL);1154mu = cgetg(lx,t_MAT);1155B = cgetg(lx,t_COL);1156for (j=1; j<lx; j++)1157{1158gel(mu,j) = zerocol(lx - 1);1159gel(B,j) = gen_0;1160}1161if (DEBUGLEVEL) err_printf("k = ");1162gel(B,1) = real_i(rnfscal(mth,gel(MC,1),gel(MC,1)));1163gel(MCS,1) = gel(MC,1);1164kmax = 1; k = 2;1165do1166{1167GEN Ik_inv = NULL;1168if (DEBUGLEVEL) err_printf("%ld ",k);1169if (k > kmax)1170{ /* Incremental Gram-Schmidt */1171kmax = k; gel(MCS,k) = gel(MC,k);1172for (j=1; j<k; j++)1173{1174gcoeff(mu,k,j) = vecdiv(rnfscal(mth,gel(MCS,j),gel(MC,k)),1175gel(B,j));1176gel(MCS,k) = gsub(gel(MCS,k), vecmul(gcoeff(mu,k,j),gel(MCS,j)));1177}1178gel(B,k) = real_i(rnfscal(mth,gel(MCS,k),gel(MCS,k)));1179if (check_0(gel(B,k))) goto PRECPB;1180}1181if (!RED(k, k-1, h, mu, MC, nf, I, &Ik_inv)) goto PRECPB;1182if (do_SWAP(I,MC,MCS,h,mu,B,kmax,k,alpha, r1))1183{1184if (!B[k]) goto PRECPB;1185if (k > 2) k--;1186}1187else1188{1189for (l=k-2; l; l--)1190if (!RED(k, l, h, mu, MC, nf, I, &Ik_inv)) goto PRECPB;1191k++;1192}1193if (gc_needed(av,2))1194{1195if(DEBUGMEM>1) pari_warn(warnmem,"rnflllgram");1196gerepileall(av, H?10:9, &nf,&mth,&h,&MPOL,&B,&MC,&MCS,&mu,&I,&H);1197}1198}1199while (k < lx);1200MPOL = gmul(MPOL,h);1201if (H) h = gmul(H, h);1202if (DEBUGLEVEL) err_printf("\n");1203MPOL = RgM_to_nfM(nf,MPOL);1204h = RgM_to_nfM(nf,h);1205return gerepilecopy(av, mkvec2(mkvec2(MPOL,I), h));1206}12071208GEN1209rnfpolred(GEN nf, GEN pol, long prec)1210{1211pari_sp av = avma;1212long i, j, n, v = varn(pol);1213GEN id, w, I, O, bnf, nfpol;12141215if (typ(pol)!=t_POL) pari_err_TYPE("rnfpolred",pol);1216bnf = nf; nf = checknf(bnf);1217bnf = (nf == bnf)? NULL: checkbnf(bnf);1218if (degpol(pol) <= 1) { w = cgetg(2, t_VEC); gel(w,1) = pol_x(v); return w; }1219nfpol = nf_get_pol(nf);12201221id = rnfpseudobasis(nf,pol);1222if (bnf && is_pm1( bnf_get_no(bnf) )) /* if bnf is principal */1223{1224GEN newI, newO;1225O = gel(id,1);1226I = gel(id,2); n = lg(I)-1;1227newI = cgetg(n+1,t_VEC);1228newO = cgetg(n+1,t_MAT);1229for (j=1; j<=n; j++)1230{1231GEN al = gen_if_principal(bnf,gel(I,j));1232gel(newI,j) = gen_1;1233gel(newO,j) = nfC_nf_mul(nf, gel(O,j), al);1234}1235id = mkvec2(newO, newI);1236}12371238id = gel(rnflllgram(nf,pol,id,prec),1);1239O = gel(id,1);1240I = gel(id,2); n = lg(I)-1;1241w = cgetg(n+1,t_VEC);1242pol = lift_shallow(pol);1243for (j=1; j<=n; j++)1244{1245GEN newpol, L, a, Ij = gel(I,j);1246a = RgC_Rg_mul(gel(O,j), (typ(Ij) == t_MAT)? gcoeff(Ij,1,1): Ij);1247for (i=n; i; i--) gel(a,i) = nf_to_scalar_or_alg(nf, gel(a,i));1248a = RgV_to_RgX(a, v);1249newpol = RgXQX_red(RgXQ_charpoly(a, pol, v), nfpol);1250newpol = Q_primpart(newpol);12511252(void)nfgcd_all(newpol, RgX_deriv(newpol), nfpol, nf_get_index(nf), &newpol);1253L = leading_coeff(newpol);1254gel(w,j) = (typ(L) == t_POL)? RgXQX_div(newpol, L, nfpol)1255: RgX_Rg_div(newpol, L);1256}1257return gerepilecopy(av,w);1258}12591260/*******************************************************************/1261/* */1262/* LINEAR ALGEBRA OVER Z_K (HNF,SNF) */1263/* */1264/*******************************************************************/1265/* A torsion-free module M over Z_K is given by [A,I].1266* I=[a_1,...,a_k] is a row vector of k fractional ideals given in HNF.1267* A is an n x k matrix (same k) such that if A_j is the j-th column of A then1268* M=a_1 A_1+...+a_k A_k. We say that [A,I] is a pseudo-basis if k=n */12691270/* Given an element x and an ideal I in HNF, gives an r such that x-r is in H1271* and r is small */1272GEN1273nfreduce(GEN nf, GEN x, GEN I)1274{1275pari_sp av = avma;1276GEN aI;1277x = nf_to_scalar_or_basis(checknf(nf), x);1278if (idealtyp(&I,&aI) != id_MAT || lg(I)==1) pari_err_TYPE("nfreduce",I);1279if (typ(x) != t_COL) x = scalarcol( gmod(x, gcoeff(I,1,1)), lg(I)-1 );1280else x = reducemodinvertible(x, I);1281return gerepileupto(av, x);1282}1283/* Given an element x and an ideal in HNF, gives an a in ideal such that1284* x-a is small. No checks */1285static GEN1286element_close(GEN nf, GEN x, GEN ideal)1287{1288pari_sp av = avma;1289GEN y = gcoeff(ideal,1,1);1290x = nf_to_scalar_or_basis(nf, x);1291if (typ(y) == t_INT && is_pm1(y)) return ground(x);1292if (typ(x) == t_COL)1293x = closemodinvertible(x, ideal);1294else1295x = gmul(y, gdivround(x,y));1296return gerepileupto(av, x);1297}12981299/* A + v B */1300static GEN1301colcomb1(GEN nf, GEN v, GEN A, GEN B)1302{1303if (isintzero(v)) return A;1304return RgC_to_nfC(nf, RgC_add(A, nfC_nf_mul(nf,B,v)));1305}1306/* u A + v B */1307static GEN1308colcomb(GEN nf, GEN u, GEN v, GEN A, GEN B)1309{1310if (isintzero(u)) return nfC_nf_mul(nf,B,v);1311if (u != gen_1) A = nfC_nf_mul(nf,A,u);1312return colcomb1(nf, v, A, B);1313}13141315/* return m[i,1..lim] * x */1316static GEN1317element_mulvecrow(GEN nf, GEN x, GEN m, long i, long lim)1318{1319long j, l = minss(lg(m), lim+1);1320GEN dx, y = cgetg(l, t_VEC);1321x = nf_to_scalar_or_basis(nf, x);1322if (typ(x) == t_COL)1323{1324x = zk_multable(nf, Q_remove_denom(x, &dx));1325for (j=1; j<l; j++)1326{1327GEN t = gcoeff(m,i,j);1328if (!isintzero(t))1329{1330if (typ(t) == t_COL)1331t = RgM_RgC_mul(x, t);1332else1333t = ZC_Q_mul(gel(x,1), t);1334if (dx) t = gdiv(t, dx);1335t = nf_to_scalar_or_basis(nf,t);1336}1337gel(y,j) = t;1338}1339}1340else1341{1342for (j=1; j<l; j++) gel(y,j) = gmul(x, gcoeff(m,i,j));1343}1344return y;1345}13461347/* u Z[s,] + v Z[t,], limitied to the first lim entries */1348static GEN1349rowcomb(GEN nf, GEN u, GEN v, long s, long t, GEN Z, long lim)1350{1351GEN z;1352if (gequal0(u))1353z = element_mulvecrow(nf,v,Z,t, lim);1354else1355{1356z = element_mulvecrow(nf,u,Z,s, lim);1357if (!gequal0(v)) z = gadd(z, element_mulvecrow(nf,v,Z,t, lim));1358}1359return z;1360}13611362/* nfbezout(0,b,A,B). Either bB = NULL or b*B */1363static GEN1364zero_nfbezout(GEN nf,GEN bB, GEN b, GEN A,GEN B,GEN *u,GEN *v,GEN *w,GEN *di)1365{1366GEN d;1367if (isint1(b))1368{1369*v = gen_1;1370*w = A;1371d = B;1372*di = idealinv(nf,d);1373}1374else1375{1376*v = nfinv(nf,b);1377*w = idealmul(nf,A,*v);1378d = bB? bB: idealmul(nf,b,B);1379*di = idealHNF_inv(nf,d);1380}1381*u = gen_0; return d;1382}13831384/* Given elements a,b and ideals A, B, outputs d = a.A+b.B and gives1385* di=d^-1, w=A.B.di, u, v such that au+bv=1 and u in A.di, v in B.di.1386* Assume A, B nonzero, but a or b can be zero (not both) */1387static GEN1388nfbezout(GEN nf,GEN a,GEN b, GEN A,GEN B, GEN *pu,GEN *pv,GEN *pw,GEN *pdi,1389int red)1390{1391GEN w, u, v, d, di, aA, bB;13921393if (isintzero(a)) return zero_nfbezout(nf,NULL,b,A,B,pu,pv,pw,pdi);1394if (isintzero(b)) return zero_nfbezout(nf,NULL,a,B,A,pv,pu,pw,pdi);13951396if (a != gen_1) /* frequently called with a = gen_1 */1397{1398a = nf_to_scalar_or_basis(nf,a);1399if (isint1(a)) a = gen_1;1400}1401aA = (a == gen_1)? idealhnf_shallow(nf,A): idealmul(nf,a,A);1402bB = idealmul(nf,b,B);1403d = idealadd(nf,aA,bB);1404if (gequal(aA, d)) return zero_nfbezout(nf,d, a,B,A,pv,pu,pw,pdi);1405if (gequal(bB, d)) return zero_nfbezout(nf,d, b,A,B,pu,pv,pw,pdi);1406/* general case is slow */1407di = idealHNF_inv(nf,d);1408aA = idealmul(nf,aA,di); /* integral */1409bB = idealmul(nf,bB,di); /* integral */14101411u = red? idealaddtoone_i(nf, aA, bB): idealaddtoone_raw(nf, aA, bB);1412w = idealmul(nf,aA,B);1413v = nfdiv(nf, nfsub(nf, gen_1, u), b);1414if (a != gen_1)1415{1416GEN inva = nfinv(nf, a);1417u = nfmul(nf,u,inva);1418w = idealmul(nf, inva, w); /* AB/d */1419}1420*pu = u; *pv = v; *pw = w; *pdi = di; return d;1421}1422/* v a vector of ideals, simplify in place the ones generated by elts of Q */1423static void1424idV_simplify(GEN v)1425{1426long i, l = lg(v);1427for (i = 1; i < l; i++)1428{1429GEN M = gel(v,i);1430if (typ(M)==t_MAT && RgM_isscalar(M,NULL))1431gel(v,i) = Q_abs_shallow(gcoeff(M,1,1));1432}1433}1434/* Given a torsion-free module x outputs a pseudo-basis for x in HNF */1435GEN1436nfhnf0(GEN nf, GEN x, long flag)1437{1438long i, j, def, idef, m, n;1439pari_sp av0 = avma, av;1440GEN y, A, I, J, U;14411442nf = checknf(nf);1443check_ZKmodule(x, "nfhnf");1444A = gel(x,1); RgM_dimensions(A, &m, &n);1445I = gel(x,2);1446if (!n) {1447if (!flag) return gcopy(x);1448retmkvec2(gcopy(x), cgetg(1,t_MAT));1449}1450U = flag? matid(n): NULL;1451idef = (n < m)? m-n : 0;1452av = avma;1453A = RgM_to_nfM(nf,A);1454I = leafcopy(I);1455J = zerovec(n); def = n;1456for (i=m; i>idef; i--)1457{1458GEN d, di = NULL;14591460j=def; while (j>=1 && isintzero(gcoeff(A,i,j))) j--;1461if (!j)1462{ /* no pivot on line i */1463if (idef) idef--;1464continue;1465}1466if (j==def) j--;1467else {1468swap(gel(A,j), gel(A,def));1469swap(gel(I,j), gel(I,def));1470if (U) swap(gel(U,j), gel(U,def));1471}1472for ( ; j; j--)1473{1474GEN a,b, u,v,w, S, T, S0, T0 = gel(A,j);1475b = gel(T0,i); if (isintzero(b)) continue;14761477S0 = gel(A,def); a = gel(S0,i);1478d = nfbezout(nf, a,b, gel(I,def),gel(I,j), &u,&v,&w,&di,1);1479S = colcomb(nf, u,v, S0,T0);1480T = colcomb(nf, a,gneg(b), T0,S0);1481gel(A,def) = S; gel(A,j) = T;1482gel(I,def) = d; gel(I,j) = w;1483if (U)1484{1485S0 = gel(U,def);1486T0 = gel(U,j);1487gel(U,def) = colcomb(nf, u,v, S0,T0);1488gel(U,j) = colcomb(nf, a,gneg(b), T0,S0);1489}1490}1491y = gcoeff(A,i,def);1492if (!isint1(y))1493{1494GEN yi = nfinv(nf,y);1495gel(A,def) = nfC_nf_mul(nf, gel(A,def), yi);1496gel(I,def) = idealmul(nf, y, gel(I,def));1497if (U) gel(U,def) = nfC_nf_mul(nf, gel(U,def), yi);1498di = NULL;1499}1500if (!di) di = idealinv(nf,gel(I,def));1501d = gel(I,def);1502gel(J,def) = di;1503for (j=def+1; j<=n; j++)1504{1505GEN mc, c = gcoeff(A,i,j); if (isintzero(c)) continue;1506c = element_close(nf, c, idealmul(nf,d,gel(J,j)));1507mc = gneg(c);1508gel(A,j) = colcomb1(nf, mc, gel(A,j),gel(A,def));1509if (U) gel(U,j) = colcomb1(nf, mc, gel(U,j),gel(U,def));1510}1511def--;1512if (gc_needed(av,2))1513{1514if(DEBUGMEM>1) pari_warn(warnmem,"nfhnf, i = %ld", i);1515gerepileall(av,U?4:3, &A,&I,&J,&U);1516}1517}1518n -= def;1519A += def; A[0] = evaltyp(t_MAT)|evallg(n+1);1520I += def; I[0] = evaltyp(t_VEC)|evallg(n+1);1521idV_simplify(I);1522x = mkvec2(A,I);1523if (U) x = mkvec2(x,U);1524return gerepilecopy(av0, x);1525}15261527GEN1528nfhnf(GEN nf, GEN x) { return nfhnf0(nf, x, 0); }15291530static GEN1531RgV_find_denom(GEN x)1532{1533long i, l = lg(x);1534for (i = 1; i < l; i++)1535if (Q_denom(gel(x,i)) != gen_1) return gel(x,i);1536return NULL;1537}1538/* A torsion module M over Z_K will be given by a row vector [A,I,J] with1539* three components. I=[b_1,...,b_n] is a row vector of n fractional ideals1540* given in HNF, J=[a_1,...,a_n] is a row vector of n fractional ideals in1541* HNF. A is an nxn matrix (same n) such that if A_j is the j-th column of A1542* and e_n is the canonical basis of K^n, then1543* M=(b_1e_1+...+b_ne_n)/(a_1A_1+...a_nA_n) */15441545/* x=[A,I,J] a torsion module as above. Output the1546* smith normal form as K=[c_1,...,c_n] such that x = Z_K/c_1+...+Z_K/c_n */1547GEN1548nfsnf0(GEN nf, GEN x, long flag)1549{1550long i, j, k, l, n, m;1551pari_sp av;1552GEN z,u,v,w,d,dinv,A,I,J, U,V;15531554nf = checknf(nf);1555if (typ(x)!=t_VEC || lg(x)!=4) pari_err_TYPE("nfsnf",x);1556A = gel(x,1);1557I = gel(x,2);1558J = gel(x,3);1559if (typ(A)!=t_MAT) pari_err_TYPE("nfsnf",A);1560n = lg(A)-1;1561if (typ(I)!=t_VEC) pari_err_TYPE("nfsnf",I);1562if (typ(J)!=t_VEC) pari_err_TYPE("nfsnf",J);1563if (lg(I)!=n+1 || lg(J)!=n+1) pari_err_DIM("nfsnf");1564RgM_dimensions(A, &m, &n);1565if (!n || n != m) pari_err_IMPL("nfsnf for empty or non square matrices");15661567av = avma;1568if (!flag) U = V = NULL;1569else1570{1571U = matid(m);1572V = matid(n);1573}1574A = RgM_to_nfM(nf, A);1575I = leafcopy(I);1576J = leafcopy(J);1577for (i = 1; i <= n; i++) gel(J,i) = idealinv(nf, gel(J,i));1578z = zerovec(n);1579for (i=n; i>=1; i--)1580{1581GEN Aii, a, b, db;1582long c = 0;1583for (j=i-1; j>=1; j--)1584{1585GEN S, T, S0, T0 = gel(A,j);1586b = gel(T0,i); if (gequal0(b)) continue;15871588S0 = gel(A,i); a = gel(S0,i);1589d = nfbezout(nf, a,b, gel(J,i),gel(J,j), &u,&v,&w,&dinv,1);1590S = colcomb(nf, u,v, S0,T0);1591T = colcomb(nf, a,gneg(b), T0,S0);1592gel(A,i) = S; gel(A,j) = T;1593gel(J,i) = d; gel(J,j) = w;1594if (V)1595{1596T0 = gel(V,j);1597S0 = gel(V,i);1598gel(V,i) = colcomb(nf, u,v, S0,T0);1599gel(V,j) = colcomb(nf, a,gneg(b), T0,S0);1600}1601}1602for (j=i-1; j>=1; j--)1603{1604GEN ri, rj;1605b = gcoeff(A,j,i); if (gequal0(b)) continue;16061607a = gcoeff(A,i,i);1608d = nfbezout(nf, a,b, gel(I,i),gel(I,j), &u,&v,&w,&dinv,1);1609ri = rowcomb(nf, u,v, i,j, A, i);1610rj = rowcomb(nf, a,gneg(b), j,i, A, i);1611for (k=1; k<=i; k++) {1612gcoeff(A,j,k) = gel(rj,k);1613gcoeff(A,i,k) = gel(ri,k);1614}1615if (U)1616{1617ri = rowcomb(nf, u,v, i,j, U, m);1618rj = rowcomb(nf, a,gneg(b), j,i, U, m);1619for (k=1; k<=m; k++) {1620gcoeff(U,j,k) = gel(rj,k);1621gcoeff(U,i,k) = gel(ri,k);1622}1623}1624gel(I,i) = d; gel(I,j) = w; c = 1;1625}1626if (c) { i++; continue; }16271628Aii = gcoeff(A,i,i); if (gequal0(Aii)) continue;1629gel(J,i) = idealmul(nf, gel(J,i), Aii);1630gcoeff(A,i,i) = gen_1;1631if (V) gel(V,i) = nfC_nf_mul(nf, gel(V,i), nfinv(nf,Aii));1632gel(z,i) = idealmul(nf,gel(J,i),gel(I,i));1633b = Q_remove_denom(gel(z,i), &db);1634for (k=1; k<i; k++)1635for (l=1; l<i; l++)1636{1637GEN d, D, p1, p2, p3, Akl = gcoeff(A,k,l);1638long t;1639if (gequal0(Akl)) continue;16401641p1 = idealmul(nf,Akl,gel(J,l));1642p3 = idealmul(nf, p1, gel(I,k));1643if (db) p3 = RgM_Rg_mul(p3, db);1644if (RgM_is_ZM(p3) && hnfdivide(b, p3)) continue;16451646/* find d in D = I[k]/I[i] not in J[i]/(A[k,l] J[l]) */1647D = idealdiv(nf,gel(I,k),gel(I,i));1648p2 = idealdiv(nf,gel(J,i), p1);1649d = RgV_find_denom(QM_gauss(p2, D));1650if (!d) pari_err_BUG("nfsnf");1651p1 = element_mulvecrow(nf,d,A,k,i);1652for (t=1; t<=i; t++) gcoeff(A,i,t) = gadd(gcoeff(A,i,t),gel(p1,t));1653if (U)1654{1655p1 = element_mulvecrow(nf,d,U,k,i);1656for (t=1; t<=i; t++) gcoeff(U,i,t) = gadd(gcoeff(U,i,t),gel(p1,t));1657}16581659k = i; c = 1; break;1660}1661if (gc_needed(av,1))1662{1663if(DEBUGMEM>1) pari_warn(warnmem,"nfsnf");1664gerepileall(av,U?6:4, &A,&I,&J,&z,&U,&V);1665}1666if (c) i++; /* iterate on row/column i */1667}1668if (U) z = mkvec3(z,U,V);1669return gerepilecopy(av, z);1670}1671GEN1672nfsnf(GEN nf, GEN x) { return nfsnf0(nf,x,0); }16731674/* Given a pseudo-basis x, outputs a multiple of its ideal determinant */1675GEN1676nfdetint(GEN nf, GEN x)1677{1678GEN pass,c,v,det1,piv,pivprec,vi,p1,A,I,id,idprod;1679long i, j, k, rg, n, m, m1, cm=0, N;1680pari_sp av = avma, av1;16811682nf = checknf(nf); N = nf_get_degree(nf);1683check_ZKmodule(x, "nfdetint");1684A = gel(x,1);1685I = gel(x,2);1686n = lg(A)-1; if (!n) return gen_1;16871688m1 = lgcols(A); m = m1-1;1689id = matid(N);1690c = new_chunk(m1); for (k=1; k<=m; k++) c[k] = 0;1691piv = pivprec = gen_1;16921693av1 = avma;1694det1 = idprod = gen_0; /* dummy for gerepileall */1695pass = cgetg(m1,t_MAT);1696v = cgetg(m1,t_COL);1697for (j=1; j<=m; j++)1698{1699gel(pass,j) = zerocol(m);1700gel(v,j) = gen_0; /* dummy */1701}1702for (rg=0,k=1; k<=n; k++)1703{1704long t = 0;1705for (i=1; i<=m; i++)1706if (!c[i])1707{1708vi=nfmul(nf,piv,gcoeff(A,i,k));1709for (j=1; j<=m; j++)1710if (c[j]) vi=gadd(vi,nfmul(nf,gcoeff(pass,i,j),gcoeff(A,j,k)));1711gel(v,i) = vi; if (!t && !gequal0(vi)) t=i;1712}1713if (t)1714{1715pivprec = piv;1716if (rg == m-1)1717{1718if (!cm)1719{1720cm=1; idprod = id;1721for (i=1; i<=m; i++)1722if (i!=t)1723idprod = (idprod==id)? gel(I,c[i])1724: idealmul(nf,idprod,gel(I,c[i]));1725}1726p1 = idealmul(nf,gel(v,t),gel(I,k)); c[t]=0;1727det1 = (typ(det1)==t_INT)? p1: idealadd(nf,p1,det1);1728}1729else1730{1731rg++; piv=gel(v,t); c[t]=k;1732for (i=1; i<=m; i++)1733if (!c[i])1734{1735for (j=1; j<=m; j++)1736if (c[j] && j!=t)1737{1738p1 = gsub(nfmul(nf,piv,gcoeff(pass,i,j)),1739nfmul(nf,gel(v,i),gcoeff(pass,t,j)));1740gcoeff(pass,i,j) = rg>1? nfdiv(nf,p1,pivprec)1741: p1;1742}1743gcoeff(pass,i,t) = gneg(gel(v,i));1744}1745}1746}1747if (gc_needed(av1,1))1748{1749if(DEBUGMEM>1) pari_warn(warnmem,"nfdetint");1750gerepileall(av1,6, &det1,&piv,&pivprec,&pass,&v,&idprod);1751}1752}1753if (!cm) { set_avma(av); return cgetg(1,t_MAT); }1754return gerepileupto(av, idealmul(nf,idprod,det1));1755}17561757/* reduce in place components of x[1..lim] mod D (destroy x). D in HNF */1758static void1759nfcleanmod(GEN nf, GEN x, long lim, GEN D)1760{1761GEN DZ, DZ2, dD;1762long i;1763D = Q_remove_denom(D, &dD);1764DZ = gcoeff(D,1,1); DZ2 = shifti(DZ, -1);1765for (i = 1; i <= lim; i++)1766{1767GEN c = nf_to_scalar_or_basis(nf, gel(x,i));1768switch(typ(c)) /* c = centermod(c, D) */1769{1770case t_INT:1771if (!signe(c)) break;1772if (dD) c = mulii(c, dD);1773c = centermodii(c, DZ, DZ2);1774if (dD) c = Qdivii(c,dD);1775break;1776case t_FRAC: {1777GEN dc = gel(c,2), nc = gel(c,1), N = mulii(DZ, dc);1778if (dD) nc = mulii(nc, dD);1779c = centermodii(nc, N, shifti(N,-1));1780c = Qdivii(c, dD ? mulii(dc,dD): dc);1781break;1782}1783case t_COL: {1784GEN dc;1785c = Q_remove_denom(c, &dc);1786if (dD) c = ZC_Z_mul(c, dD);1787c = ZC_hnfrem(c, dc? ZM_Z_mul(D,dc): D);1788dc = mul_content(dc, dD);1789if (ZV_isscalar(c))1790{1791c = gel(c,1);1792if (dc) c = Qdivii(c,dc);1793}1794else1795if (dc) c = RgC_Rg_div(c, dc);1796break;1797}1798}1799gel(x,i) = c;1800}1801}18021803GEN1804nfhnfmod(GEN nf, GEN x, GEN D)1805{1806long li, co, i, j, def, ldef;1807pari_sp av0=avma, av;1808GEN dA, dI, d0, w, p1, d, u, v, A, I, J, di;18091810nf = checknf(nf);1811check_ZKmodule(x, "nfhnfmod");1812A = gel(x,1);1813I = gel(x,2);1814co = lg(A); if (co==1) return cgetg(1,t_MAT);18151816li = lgcols(A);1817if (typ(D)!=t_MAT) D = idealhnf_shallow(nf, D);1818D = Q_remove_denom(D, NULL);1819RgM_check_ZM(D, "nfhnfmod");18201821av = avma;1822A = RgM_to_nfM(nf, A);1823A = Q_remove_denom(A, &dA);1824I = Q_remove_denom(leafcopy(I), &dI);1825dA = mul_denom(dA,dI);1826if (dA) D = ZM_Z_mul(D, powiu(dA, minss(li,co)));18271828def = co; ldef = (li>co)? li-co+1: 1;1829for (i=li-1; i>=ldef; i--)1830{1831def--; j=def; while (j>=1 && isintzero(gcoeff(A,i,j))) j--;1832if (!j) continue;1833if (j==def) j--;1834else {1835swap(gel(A,j), gel(A,def));1836swap(gel(I,j), gel(I,def));1837}1838for ( ; j; j--)1839{1840GEN a, b, S, T, S0, T0 = gel(A,j);1841b = gel(T0,i); if (isintzero(b)) continue;18421843S0 = gel(A,def); a = gel(S0,i);1844d = nfbezout(nf, a,b, gel(I,def),gel(I,j), &u,&v,&w,&di,0);1845S = colcomb(nf, u,v, S0,T0);1846T = colcomb(nf, a,gneg(b), T0,S0);1847if (u != gen_0 && v != gen_0) /* already reduced otherwise */1848nfcleanmod(nf, S, i, idealmul(nf,D,di));1849nfcleanmod(nf, T, i, idealdiv(nf,D,w));1850gel(A,def) = S; gel(A,j) = T;1851gel(I,def) = d; gel(I,j) = w;1852}1853if (gc_needed(av,2))1854{1855if(DEBUGMEM>1) pari_warn(warnmem,"[1]: nfhnfmod, i = %ld", i);1856gerepileall(av,dA? 4: 3, &A,&I,&D,&dA);1857}1858}1859def--; d0 = D;1860A += def; A[0] = evaltyp(t_MAT)|evallg(li);1861I += def; I[0] = evaltyp(t_VEC)|evallg(li);1862J = cgetg(li,t_VEC);1863for (i=li-1; i>=1; i--)1864{1865GEN b = gcoeff(A,i,i);1866d = nfbezout(nf, gen_1,b, d0,gel(I,i), &u,&v,&w,&di,0);1867p1 = nfC_nf_mul(nf,gel(A,i),v);1868if (i > 1)1869{1870d0 = idealmul(nf,d0,di);1871nfcleanmod(nf, p1, i, d0);1872}1873gel(A,i) = p1; gel(p1,i) = gen_1;1874gel(I,i) = d;1875gel(J,i) = di;1876}1877for (i=li-2; i>=1; i--)1878{1879d = gel(I,i);1880for (j=i+1; j<li; j++)1881{1882GEN c = gcoeff(A,i,j); if (isintzero(c)) continue;1883c = element_close(nf, c, idealmul(nf,d,gel(J,j)));1884gel(A,j) = colcomb1(nf, gneg(c), gel(A,j),gel(A,i));1885}1886if (gc_needed(av,2))1887{1888if(DEBUGMEM>1) pari_warn(warnmem,"[2]: nfhnfmod, i = %ld", i);1889gerepileall(av,dA? 4: 3, &A,&I,&J,&dA);1890}1891}1892idV_simplify(I);1893if (dA) I = gdiv(I,dA);1894return gerepilecopy(av0, mkvec2(A, I));1895}189618971898