Testing latest pari + WASM + node.js... and it works?! Wow.
License: GPL3
ubuntu2004
/* Copyright (C) 2020 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. */13#include "pari.h"14#include "paripriv.h"1516#define DEBUGLEVEL DEBUGLEVEL_bnf1718/* if x a famat, assume it is a true unit (very costly to check even that19* it's an algebraic integer) */20GEN21bnfisunit(GEN bnf, GEN x)22{23long tx = typ(x), i, r1, RU, e, n, prec;24pari_sp av = avma;25GEN t, logunit, ex, nf, pi2_sur_w, rx, emb, arg;2627bnf = checkbnf(bnf); nf = bnf_get_nf(bnf);28RU = lg(bnf_get_logfu(bnf));29n = bnf_get_tuN(bnf); /* # { roots of 1 } */30if (tx == t_MAT)31{ /* famat, assumed OK */32if (lg(x) != 3) pari_err_TYPE("bnfisunit [not a factorization]", x);33} else {34x = nf_to_scalar_or_basis(nf,x);35if (typ(x) != t_COL)36{ /* rational unit ? */37GEN v;38long s;39if (typ(x) != t_INT || !is_pm1(x)) return cgetg(1,t_COL);40s = signe(x); set_avma(av); v = zerocol(RU);41gel(v,RU) = utoi((s > 0)? 0: n>>1);42return v;43}44if (!isint1(Q_denom(x))) { set_avma(av); return cgetg(1,t_COL); }45}4647r1 = nf_get_r1(nf);48prec = nf_get_prec(nf);49for (i = 1;; i++)50{51GEN rlog;52nf = bnf_get_nf(bnf);53logunit = bnf_get_logfu(bnf);54rlog = real_i(logunit);55rx = nflogembed(nf,x,&emb, prec);56if (rx)57{58GEN logN = RgV_sum(rx); /* log(Nx), should be ~ 0 */59if (gexpo(logN) > -20)60{ /* precision problem ? */61if (typ(logN) != t_REAL) { set_avma(av); return cgetg(1,t_COL); } /*no*/62if (i == 1 && typ(x) != t_MAT &&63!is_pm1(nfnorm(nf, x))) { set_avma(av); return cgetg(1, t_COL); }64}65else66{67ex = RU == 1? cgetg(1,t_COL)68: RgM_solve(rlog, rx); /* ~ fundamental units exponents */69if (ex) { ex = grndtoi(ex, &e); if (e < -4) break; }70}71}72if (i == 1)73prec = nbits2prec(gexpo(x) + 128);74else75{76if (i > 4) pari_err_PREC("bnfisunit");77prec = precdbl(prec);78}79if (DEBUGLEVEL) pari_warn(warnprec,"bnfisunit",prec);80bnf = bnfnewprec_shallow(bnf, prec);81}82/* choose a large embedding => small relative error */83for (i = 1; i < RU; i++)84if (signe(gel(rx,i)) > -1) break;85if (RU == 1) t = gen_0;86else87{88t = imag_i( row_i(logunit,i, 1,RU-1) );89t = RgV_dotproduct(t, ex);90if (i > r1) t = gmul2n(t, -1);91}92if (typ(emb) != t_MAT) arg = garg(gel(emb,i), prec);93else94{95GEN p = gel(emb,1), e = gel(emb,2);96long j, l = lg(p);97arg = NULL;98for (j = 1; j < l; j++)99{100GEN a = gmul(gel(e,j), garg(gel(gel(p,j),i), prec));101arg = arg? gadd(arg, a): a;102}103}104t = gsub(arg, t); /* = arg(the missing root of 1) */105pi2_sur_w = divru(mppi(prec), n>>1); /* 2pi / n */106e = umodiu(roundr(divrr(t, pi2_sur_w)), n);107if (n > 2)108{109GEN z = algtobasis(nf, bnf_get_tuU(bnf)); /* primitive root of 1 */110GEN ro = RgV_dotproduct(row(nf_get_M(nf), i), z);111GEN p2 = roundr(divrr(garg(ro, prec), pi2_sur_w));112e *= Fl_inv(umodiu(p2,n), n);113e %= n;114}115gel(ex,RU) = utoi(e); setlg(ex, RU+1); return gerepilecopy(av, ex);116}117118/* split M a square ZM in HNF as [H, B; 0, Id], H in HNF without 1-eigenvalue */119static GEN120hnfsplit(GEN M, GEN *pB)121{122long i, l = lg(M);123for (i = l-1; i; i--)124if (!equali1(gcoeff(M,i,i))) break;125if (!i) { *pB = zeromat(0, l-1); return cgetg(1, t_MAT); }126*pB = matslice(M, 1, i, i+1, l-1); return matslice(M, 1, i, 1, i);127}128129/* S a list of prime ideal in idealprimedec format. If pH != NULL, set it to130* the HNF of the S-class group and return bnfsunit, else return bnfunits */131static GEN132bnfsunit_i(GEN bnf, GEN S, GEN *pH, GEN *pA, GEN *pden)133{134long FLAG, i, lS = lg(S);135GEN M, U1, U2, U, V, H, Sunit, B, g;136137if (!is_vec_t(typ(S))) pari_err_TYPE("bnfsunit",S);138bnf = checkbnf(bnf);139if (lS == 1)140{141*pA = cgetg(1,t_MAT);142*pden = gen_1; return cgetg(1,t_VEC);143}144M = cgetg(lS,t_MAT); /* relation matrix for the S class group */145g = cgetg(lS,t_MAT); /* principal part */146FLAG = pH ? 0: nf_GENMAT;147for (i = 1; i < lS; i++)148{149GEN pr = gel(S,i);150checkprid(pr);151if (pH)152gel(M,i) = isprincipal(bnf, pr);153else154{155GEN v = bnfisprincipal0(bnf, pr, FLAG);156gel(M,i) = gel(v,1);157gel(g,i) = gel(v,2);158}159}160/* S class group and S units, use ZM_hnflll to get small 'U' */161M = shallowconcat(M, diagonal_shallow(bnf_get_cyc(bnf)));162H = ZM_hnflll(M, &U, 1); setlg(U, lS); if (pH) *pH = H;163U1 = rowslice(U,1, lS-1);164U2 = rowslice(U,lS, lg(M)-1); /* (M | cyc) [U1; U2] = 0 */165H = ZM_hnflll(U1, pH? NULL: &V, 0);166/* U1 = upper left corner of U, invertible. S * U1 = principal ideals167* whose generators generate the S-units */168H = hnfsplit(H, &B);169/* [ H B ] [ H^-1 - H^-1 B ]170* U1 * V = HNF(U1) = [ 0 Id ], inverse = [ 0 Id ]171* S * HNF(U1) = integral generators for S-units = Sunit */172Sunit = cgetg(lS, t_VEC);173if (pH)174{175long nH = lg(H) - 1;176FLAG = nf_FORCE | nf_GEN;177for (i = 1; i < lS; i++)178{179GEN C = NULL, E;180if (i <= nH) E = gel(H,i); else { C = gel(S,i), E = gel(B,i-nH); }181gel(Sunit,i) = gel(isprincipalfact(bnf, C, S, E, FLAG), 2);182}183}184else185{186GEN cycgen = bnf_build_cycgen(bnf);187U1 = ZM_mul(U1, V);188U2 = ZM_mul(U2, V);189FLAG = nf_FORCE | nf_GENMAT;190for (i = 1; i < lS; i++)191{192GEN a = famatV_factorback(g, gel(U1,i));193GEN b = famatV_factorback(cycgen, ZC_neg(gel(U2,i)));194gel(Sunit,i) = famat_reduce(famat_mul(a, b));195}196}197H = ZM_inv(H, pden);198*pA = shallowconcat(H, ZM_neg(ZM_mul(H,B))); /* top inverse * den */199return Sunit;200}201GEN202bnfsunit(GEN bnf,GEN S,long prec)203{204pari_sp av = avma;205long i, l = lg(S);206GEN v, R, nf, A, den, U, cl, H = NULL;207bnf = checkbnf(bnf); nf = bnf_get_nf(bnf);208v = cgetg(7, t_VEC);209gel(v,1) = U = bnfsunit_i(bnf, S, &H, &A, &den);210gel(v,2) = mkvec2(A, den);211gel(v,3) = cgetg(1,t_VEC); /* dummy */212R = bnf_get_reg(bnf);213cl = bnf_get_clgp(bnf);214if (l != 1)215{216GEN u,A, G = bnf_get_gen(bnf), D = ZM_snf_group(H,NULL,&u), h = ZV_prod(D);217long lD = lg(D);218A = cgetg(lD, t_VEC);219for(i = 1; i < lD; i++) gel(A,i) = idealfactorback(nf, G, gel(u,i), 1);220cl = mkvec3(h, D, A);221R = mpmul(R, h);222for (i = 1; i < l; i++)223{224GEN pr = gel(S,i), p = pr_get_p(pr);225long f = pr_get_f(pr);226R = mpmul(R, logr_abs(itor(p,prec)));227if (f != 1) R = mulru(R, f);228gel(U,i) = nf_to_scalar_or_alg(nf, gel(U,i));229}230}231gel(v,4) = R;232gel(v,5) = cl;233gel(v,6) = S; return gerepilecopy(av, v);234}235GEN236bnfunits(GEN bnf, GEN S)237{238pari_sp av = avma;239GEN A, den, U, fu, tu;240bnf = checkbnf(bnf);241U = bnfsunit_i(bnf, S? S: cgetg(1,t_VEC), NULL, &A, &den);242if (!S) S = cgetg(1,t_VEC);243fu = bnf_compactfu(bnf);244if (!fu)245{246long i, l;247fu = bnf_has_fu(bnf); if (!fu) bnf_build_units(bnf);248fu = shallowcopy(fu); l = lg(fu);249for (i = 1; i < l; i++) gel(fu,i) = to_famat_shallow(gel(fu,i),gen_1);250}251tu = nf_to_scalar_or_basis(bnf_get_nf(bnf), bnf_get_tuU(bnf));252U = shallowconcat(U, vec_append(fu, to_famat_shallow(tu,gen_1)));253return gerepilecopy(av, mkvec4(U, S, A, den));254}255GEN256sunits_mod_units(GEN bnf, GEN S)257{258pari_sp av = avma;259GEN A, den;260bnf = checkbnf(bnf);261return gerepilecopy(av, bnfsunit_i(bnf, S, NULL, &A, &den));262}263264/* v_S(x), x in famat form */265static GEN266sunit_famat_val(GEN nf, GEN S, GEN x)267{268long i, l = lg(S);269GEN v = cgetg(l, t_VEC);270for (i = 1; i < l; i++) gel(v,i) = famat_nfvalrem(nf, x, gel(S,i), NULL);271return v;272}273/* v_S(x), x algebraic number */274static GEN275sunit_val(GEN nf, GEN S, GEN x, GEN N)276{277long i, l = lg(S);278GEN v = zero_zv(l-1), N0 = N;279for (i = 1; i < l; i++)280{281GEN P = gel(S,i), p = pr_get_p(P);282if (dvdii(N, p)) { v[i] = nfval(nf,x,P); (void)Z_pvalrem(N0, p, &N0); }283}284return is_pm1(N0)? v: NULL;285}286287/* if *px a famat, assume it's an S-unit */288static GEN289make_unit(GEN nf, GEN U, GEN *px)290{291GEN den, v, w, A, gen = gel(U,1), S = gel(U,2), x = *px;292long cH, i, l = lg(S);293294if (l == 1) return cgetg(1, t_COL);295A = gel(U,3); den = gel(U,4);296cH = nbrows(A);297if (typ(x) == t_MAT && lg(x) == 3)298{299w = sunit_famat_val(nf, S, x); /* x = S v */300v = ZM_ZC_mul(A, w);301w += cH; w[0] = evaltyp(t_COL) | evallg(lg(A) - cH);302}303else304{305GEN N;306x = nf_to_scalar_or_basis(nf,x);307switch(typ(x))308{309case t_INT: N = x; if (!signe(N)) return NULL; break;310case t_FRAC: N = mulii(gel(x,1),gel(x,2)); break;311default: { GEN d = Q_denom(x); N = mulii(idealnorm(nf,gmul(x,d)), d); }312}313/* relevant primes divide N */314if (is_pm1(N)) return zerocol(l-1);315w = sunit_val(nf, S, x, N);316if (!w) return NULL;317v = ZM_zc_mul(A, w);318w += cH; w[0] = evaltyp(t_VECSMALL) | evallg(lg(A) - cH);319w = zc_to_ZC(w);320}321if (!is_pm1(den)) for (i = 1; i <= cH; i++)322{323GEN r;324gel(v,i) = dvmdii(gel(v,i), den, &r);325if (r != gen_0) return NULL;326}327v = shallowconcat(v, w); /* append bottom of w (= [0 Id] part) */328for (i = 1; i < l; i++)329{330GEN e = gel(v,i);331if (signe(e)) x = famat_mulpow_shallow(x, gel(gen,i), negi(e));332}333*px = x; return v;334}335336static GEN337bnfissunit_i(GEN bnf, GEN x, GEN U)338{339GEN w, nf, v = NULL;340bnf = checkbnf(bnf);341nf = bnf_get_nf(bnf);342if ( (w = make_unit(nf, U, &x)) ) v = bnfisunit(bnf, x);343if (!v || lg(v) == 1) return NULL;344return mkvec2(v, w);345}346static int347checkU(GEN U)348{349if (typ(U) != t_VEC || lg(U) != 5) return 0;350return typ(gel(U,1)) == t_VEC && is_vec_t(typ(gel(U,2)))351&& typ(gel(U,4))==t_INT;352}353GEN354bnfisunit0(GEN bnf, GEN x, GEN U)355{356pari_sp av = avma;357GEN z;358if (!U) return bnfisunit(bnf, x);359if (!checkU(U)) pari_err_TYPE("bnfisunit",U);360z = bnfissunit_i(bnf, x, U);361if (!z) { set_avma(av); return cgetg(1,t_COL); }362return gerepilecopy(av, shallowconcat(gel(z,2), gel(z,1)));363}364365/* OBSOLETE */366static int367checkbnfS_i(GEN v)368{369GEN S, g, w;370if (typ(v) != t_VEC || lg(v) != 7) return 0;371g = gel(v,1); w = gel(v,2); S = gel(v,6);372if (typ(g) != t_VEC || !is_vec_t(typ(S)) || lg(S) != lg(g)) return 0;373return typ(w) == t_VEC && lg(w) == 3;374}375/* OBSOLETE */376GEN377bnfissunit(GEN bnf, GEN bnfS, GEN x)378{379pari_sp av = avma;380GEN z, U;381if (!checkbnfS_i(bnfS)) pari_err_TYPE("bnfissunit",bnfS);382U = mkvec4(gel(bnfS,1), gel(bnfS,6), gmael(bnfS,2,1), gmael(bnfS,2,2));383z = bnfissunit_i(bnf, x, U);384if (!z) { set_avma(av); return cgetg(1,t_COL); }385return gerepilecopy(av, shallowconcat(gel(z,1), gel(z,2)));386}387388389