Testing latest pari + WASM + node.js... and it works?! Wow.
License: GPL3
ubuntu2004
#line 2 "../src/kernel/none/halfgcd.c"1/* Copyright (C) 2019 The PARI group.23This file is part of the PARI/GP package.45PARI/GP is free software; you can redistribute it and/or modify it under the6terms of the GNU General Public License as published by the Free Software7Foundation; either version 2 of the License, or (at your option) any later8version. It is distributed in the hope that it will be useful, but WITHOUT9ANY WARRANTY WHATSOEVER.1011Check the License for details. You should have received a copy of it, along12with the package; see the file 'COPYING'. If not, write to the Free Software13Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */1415GEN16ZM2_mul(GEN A, GEN B)17{18const long t = 52;19GEN A11=gcoeff(A,1,1),A12=gcoeff(A,1,2), B11=gcoeff(B,1,1),B12=gcoeff(B,1,2);20GEN A21=gcoeff(A,2,1),A22=gcoeff(A,2,2), B21=gcoeff(B,2,1),B22=gcoeff(B,2,2);21if (lgefint(A11) < t || lgefint(B11) < t || lgefint(A22) < t || lgefint(B22) < t22|| lgefint(A12) < t || lgefint(B12) < t || lgefint(A21) < t || lgefint(B21) < t)23{24GEN a = mulii(A11, B11), b = mulii(A12, B21);25GEN c = mulii(A11, B12), d = mulii(A12, B22);26GEN e = mulii(A21, B11), f = mulii(A22, B21);27GEN g = mulii(A21, B12), h = mulii(A22, B22);28retmkmat2(mkcol2(addii(a,b), addii(e,f)), mkcol2(addii(c,d), addii(g,h)));29} else30{31GEN M1 = mulii(addii(A11,A22), addii(B11,B22));32GEN M2 = mulii(addii(A21,A22), B11);33GEN M3 = mulii(A11, subii(B12,B22));34GEN M4 = mulii(A22, subii(B21,B11));35GEN M5 = mulii(addii(A11,A12), B22);36GEN M6 = mulii(subii(A21,A11), addii(B11,B12));37GEN M7 = mulii(subii(A12,A22), addii(B21,B22));38GEN T1 = addii(M1,M4), T2 = subii(M7,M5);39GEN T3 = subii(M1,M2), T4 = addii(M3,M6);40retmkmat2(mkcol2(addii(T1,T2), addii(M2,M4)),41mkcol2(addii(M3,M5), addii(T3,T4)));42}43}4445static GEN46matid2(void)47{48retmkmat2(mkcol2(gen_1,gen_0),49mkcol2(gen_0,gen_1));50}5152/* Return M*[q,1;1,0] */53static GEN54mulq(GEN M, GEN q)55{56GEN u, v, res = cgetg(3, t_MAT);57u = addii(mulii(gcoeff(M,1,1), q), gcoeff(M,1,2));58v = addii(mulii(gcoeff(M,2,1), q), gcoeff(M,2,2));59gel(res,1) = mkcol2(u, v);60gel(res,2) = gel(M,1);61return res;62}63static GEN64mulqab(GEN M, GEN q, GEN *ap, GEN *bp)65{66GEN b = subii(*ap, mulii(*bp, q));67*ap = *bp; *bp = b;68return mulq(M,q);69}7071/* Return M*[q,1;1,0]^-1 */7273static GEN74mulqi(GEN M, GEN q, GEN *ap, GEN *bp)75{76GEN u, v, res, a;77a = addii(mulii(*ap, q), *bp);78*bp = *ap; *ap = a;79res = cgetg(3, t_MAT);80u = subii(gcoeff(M,1,1),mulii(gcoeff(M,1,2), q));81v = subii(gcoeff(M,2,1),mulii(gcoeff(M,2,2), q));82gel(res,1) = gel(M,2);83gel(res,2) = mkcol2(u,v);84return res;85}8687static long88uexpi(GEN a)89{ return expi(subiu(shifti(a,1),1)); }9091static GEN92FIXUP0(GEN M, GEN *a, GEN *b, long m)93{94long cnt=0;95while (expi(*b) >= m)96{97GEN r, q = dvmdii(*a, *b, &r);98*a = *b; *b = r;99M = mulq(M, q);100cnt++;101};102if (cnt>6) pari_err_BUG("FIXUP0");103return M;104}105106static long107signdet(GEN Q)108{109long a = Mod4(gcoeff(Q,1,1)), b = Mod4(gcoeff(Q,1,2));110long c = Mod4(gcoeff(Q,2,1)), d = Mod4(gcoeff(Q,2,2));111return ((a*d-b*c)&3)==1 ? 1 : -1;112}113114static GEN115ZM_inv2(GEN M)116{117long e = signdet(M);118if (e==1) return mkmat22(gcoeff(M,2,2),negi(gcoeff(M,1,2)),119negi(gcoeff(M,2,1)),gcoeff(M,1,1));120else return mkmat22(negi(gcoeff(M,2,2)),gcoeff(M,1,2),121gcoeff(M,2,1),negi(gcoeff(M,1,1)));122}123124static GEN125lastq(GEN Q)126{127GEN p = gcoeff(Q,1,1), q = gcoeff(Q,1,2), s = gcoeff(Q,2,2);128if (signe(q)==0) pari_err_BUG("halfgcd");129if (signe(s)==0) return p;130if (equali1(q)) return subiu(p,1);131return divii(p, q);132}133134static GEN135mulT(GEN Q, GEN *ap, GEN *bp)136{137*ap = addii(*ap, *bp);138*bp = negi(*bp);139return mkmat2(gel(Q,1),140mkcol2(subii(gcoeff(Q,1,1), gcoeff(Q,1,2))141, subii(gcoeff(Q,2,1), gcoeff(Q,2,2))));142}143144static GEN145FIXUP1(GEN M, GEN a, GEN b, long m, long t, GEN *ap, GEN *bp)146{147GEN Q = gel(M,1), a0 = gel(M,2), b0 = gel(M,3);148GEN q, am = remi2n(a, m), bm = remi2n(b, m);149if (signdet(Q)==-1)150{151*ap = subii(mulii(bm, gcoeff(Q,1,2)),mulii(am, gcoeff(Q,2,2)));152*bp = subii(mulii(am, gcoeff(Q,2,1)),mulii(bm, gcoeff(Q,1,1)));153*ap = addii(*ap, shifti(addii(a0, gcoeff(Q,2,2)), m));154*bp = addii(*bp, shifti(subii(b0, gcoeff(Q,2,1)), m));155if (signe(*bp) >= 0)156return Q;157if (expi(addii(*ap,*bp)) >= m+t)158return mulT(Q, ap ,bp);159q = lastq(Q);160Q = mulqi(Q, q, ap, bp);161if (cmpiu(q, 2)>=0)162return mulqab(Q, subiu(q,1), ap, bp);163else164return mulqi(Q, lastq(Q), ap, bp);165}166else167{168*ap = subii(mulii(am, gcoeff(Q,2,2)),mulii(bm, gcoeff(Q,1,2)));169*bp = subii(mulii(bm, gcoeff(Q,1,1)),mulii(am, gcoeff(Q,2,1)));170*ap = addii(*ap, shifti(subii(a0, gcoeff(Q,2,2)), m));171*bp = addii(*bp, shifti(addii(b0, gcoeff(Q,2,1)), m));172if (expi(*ap) >= m+t)173return FIXUP0(Q, ap, bp, m+t);174else175return signe(gcoeff(Q,1,2))==0? Q: mulqi(Q, lastq(Q), ap, bp);176}177}178179static long180magic_threshold(GEN a)181{ return (3+uexpi(a))>>1; }182183static GEN184HGCD_basecase(GEN a, GEN b)185{186pari_sp av=avma;187long m = magic_threshold(a);188GEN u,u1,v,v1;189u1 = v = gen_0;190u = v1 = gen_1;191while (expi(b) >= m)192{193GEN r, q = dvmdii(a,b, &r);194a = b; b = r; swap(u,u1); swap(v,v1);195u = addii(mulii(u1, q), u);196v = addii(mulii(v1, q), v);197if (gc_needed(av,2))198{199if (DEBUGMEM>1) pari_warn(warnmem,"halfgcd (d = %ld)",lgefint(b));200gerepileall(av,6, &a,&b,&u1,&v1,&u,&v);201}202}203return gerepilecopy(av, mkvec3(mkmat22(u,u1,v,v1), a, b));204}205206static GEN HGCD(GEN x, GEN y);207208/*209Based on210Klaus Thull and Chee K. Yap,211A unified approach to HGCD algorithms for polynomials andintegers,2121990, Manuscript.213URL: http://cs.nyu.edu/cs/faculty/yap/papers.214*/215216static GEN217HGCD_split(GEN a, GEN b)218{219pari_sp av = avma;220long m = magic_threshold(a), t, l, k, tp;221GEN a0, b0, ap, bp, c, d, c0, d0, cp, dp, R, S, T, q, r;222if (signe(b) < 0 || cmpii(a,b)<0) pari_err_BUG("HGCD_split");223if (expi(b) < m)224return gerepilecopy(av, mkvec3(matid2(), a, b));225a0 = addiu(shifti(a, -m), 1);226if (cmpiu(a0,7) <= 0)227{228R = FIXUP0(matid2(), &a, &b, m);229return gerepilecopy(av, mkvec3(R, a, b));230}231b0 = shifti(b,-m);232t = magic_threshold(a0);233R = FIXUP1(HGCD(a0,b0),a, b, m, t, &ap, &bp);234if (expi(bp) < m)235return gerepilecopy(av, mkvec3(R, ap, bp));236q = dvmdii(ap, bp, &r);237c = bp; d = r;238if (cmpiu(shifti(c,-m),6) <= 0)239{240R = FIXUP0(mulq(R, q), &c, &d, m);241return gerepilecopy(av, mkvec3(R, c, d));242}243l = uexpi(c);244k = 2*m-l-1; if (k<0) pari_err_BUG("halfgcd");245c0 = addiu(shifti(c, -k), 1); if (cmpiu(c0,8)<0) pari_err_BUG("halfgcd");246d0 = shifti(d, -k);247tp = magic_threshold(c0);248S = FIXUP1(HGCD(c0,d0), c, d, k, tp, &cp, &dp);249if (!(expi(cp)>=m+1 && m+1 > expi(dp))) pari_err_BUG("halfgcd");250T = FIXUP0(ZM2_mul(mulq(R, q), S), &cp, &dp, m);251return gerepilecopy(av, mkvec3(T, cp, dp));252}253254static GEN255HGCD(GEN x, GEN y)256{257if (lgefint(y)-2 < HALFGCD_LIMIT)258return HGCD_basecase(x, y);259else260return HGCD_split(x, y);261}262263static GEN264HGCD0(GEN x, GEN y)265{266if (signe(y) >= 0 && cmpii(x, y) >= 0)267return HGCD(x, y);268if (cmpii(x, y) < 0)269{270GEN M = HGCD0(y, x), Q = gel(M,1);271return mkvec3(mkmat22(gcoeff(Q,2,1),gcoeff(Q,2,2),gcoeff(Q,1,1),gcoeff(Q,1,2)),272gel(M,2),gel(M,3));273} /* Now y <= x*/274if (signe(x) <= 0)275{ /* y <= x <=0 */276GEN M = HGCD(negi(y), negi(x)), Q = gel(M,1);277return mkvec3(mkmat22(negi(gcoeff(Q,2,1)),negi(gcoeff(Q,2,2)),278negi(gcoeff(Q,1,1)),negi(gcoeff(Q,1,2))),279gel(M,2),gel(M,3));280}281else /* y <= 0 <=x */282{283GEN M = HGCD0(x, negi(y)), Q = gel(M,1);284return mkvec3(mkmat22(gcoeff(Q,1,1),gcoeff(Q,1,2),negi(gcoeff(Q,2,1)),negi(gcoeff(Q,2,2))),285gel(M,2),gel(M,3));286}287}288289GEN290halfgcdii(GEN A, GEN B)291{292pari_sp av = avma;293GEN M, Q, a, b, m = absi_shallow(abscmpii(A, B)>0 ? A: B);294M = HGCD0(A,B); Q = gel(M,1); a = gel(M,2); b = gel(M,3);295while (signe(b) && cmpii(sqri(b), m) >= 0)296{297GEN r, q = dvmdii(a, b, &r);298a = b; b = r;299Q = mulq(Q, q);300}301return gerepilecopy(av, mkvec2(ZM_inv2(Q),mkcol2(a,b)));302}303304305