Testing latest pari + WASM + node.js... and it works?! Wow.
License: GPL3
ubuntu2004
/* Copyright (C) 2002 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/* Original code contributed by: Ralf Stephan ([email protected]).15* Updated by Bill Allombert (2014) to use Selberg formula for L16* following http://dx.doi.org/10.1112/S146115701200108817*18* This program is basically the implementation of the script19*20* Psi(n, q) = my(a=sqrt(2/3)*Pi/q, b=n-1/24, c=sqrt(b));21* (sqrt(q)/(2*sqrt(2)*b*Pi))*(a*cosh(a*c)-(sinh(a*c)/c))22* L(n,q)=sqrt(k/3)*sum(l=0,2*k-1,23if(((3*l^2+l)/2+n)%k==0,(-1)^l*cos((6*l+1)/(6*k)*Pi)))24* part(n) = round(sum(q=1,5 + 0.24*sqrt(n),L(n,q)*Psi(n,q)))25*26* only faster.27*28* ------------------------------------------------------------------29* The first restriction depends on Pari's maximum precision of floating30* point reals, which is 268435454 bits in 2.2.4, since the algorithm needs31* high precision exponentials. For that engine, the maximum possible argument32* would be in [5*10^15,10^16], the computation of which would need days on33* a ~1-GHz computer. */3435#include "pari.h"36#include "paripriv.h"3738/****************************************************************/3940/* Given c = sqrt(2/3)*Pi*sqrt(N-1/24)41* Psi(N, q) = my(a = c/q); sqrt(q) * (a*cosh(a) - sinh(a)) */42static GEN43psi(GEN c, ulong q, long prec)44{45GEN a = divru(c, q), ea = mpexp(a), invea = invr(ea);46GEN cha = shiftr(addrr(ea, invea), -1); /* ch(a) */47GEN sha = shiftr(subrr(ea, invea), -1); /* sh(a) */48return mulrr(sqrtr(utor(q,prec)), subrr(mulrr(a,cha), sha));49}5051/* L(n,q)=sqrt(k/3)*sum(l=0,2*k-1,52if(((3*l^2+l)/2+n)%k==0,(-1)^l*cos((6*l+1)/(6*k)*Pi)))53* Never called with q < 3, so ignore this case */54static GEN55L(GEN n, ulong k, long bitprec)56{57ulong r, l, m;58long pr = nbits2prec(bitprec / k + k);59GEN s = utor(0,pr), pi = mppi(pr);60pari_sp av = avma;6162r = 2; m = umodiu(n,k);63for (l = 0; l < 2*k; l++)64{65if (m == 0)66{67GEN c = mpcos(divru(mulru(pi, 6*l+1), 6*k));68if (odd(l)) subrrz(s, c, s); else addrrz(s, c, s);69set_avma(av);70}71m += r; if (m >= k) m -= k;72r += 3; if (r >= k) r -= k;73}74/* multiply by sqrt(k/3) */75return mulrr(s, sqrtr((k % 3)? rdivss(k,3,pr): utor(k/3,pr)));76}7778/* Return a low precision estimate of log p(n). */79static GEN80estim(GEN n)81{82pari_sp av = avma;83GEN p1, pi = mppi (DEFAULTPREC);8485p1 = divru( itor(shifti(n,1), DEFAULTPREC), 3 );86p1 = mpexp( mulrr(pi, sqrtr(p1)) ); /* exp(Pi * sqrt(2N/3)) */87p1 = divri (shiftr(p1,-2), n);88p1 = divrr(p1, sqrtr( utor(3,DEFAULTPREC) ));89return gerepileupto(av, mplog(p1));90}9192/* c = sqrt(2/3)*Pi*sqrt(n-1/24); d = 1 / ((2*b)^(3/2) * Pi); */93static void94pinit(GEN n, GEN *c, GEN *d, ulong prec)95{96GEN b = divru( itor( subiu(muliu(n,24), 1), prec ), 24 ); /* n - 1/24 */97GEN sqrtb = sqrtr(b), Pi = mppi(prec), pi2sqrt2, pisqrt2d3;9899pisqrt2d3 = mulrr(Pi, sqrtr( divru(utor(2, prec), 3) ));100pi2sqrt2 = mulrr(Pi, sqrtr( utor(8, prec) ));101*c = mulrr(pisqrt2d3, sqrtb);102*d = invr( mulrr(pi2sqrt2, mulrr(b,sqrtb)) );103}104105/* part(n) = round(sum(q=1,5 + 0.24*sqrt(n), L(n,q)*Psi(n,q))) */106GEN107numbpart(GEN n)108{109pari_sp ltop = avma, av;110GEN sum, est, C, D, p1, p2;111long prec, bitprec;112ulong q;113114if (typ(n) != t_INT) pari_err_TYPE("partition function",n);115if (signe(n) < 0) return gen_0;116if (abscmpiu(n, 2) < 0) return gen_1;117if (cmpii(n, uu32toi(0x38d7e, 0xa4c68000)) >= 0)118pari_err_OVERFLOW("numbpart [n < 10^15]");119est = estim(n);120bitprec = (long)(rtodbl(est)/M_LN2) + 32;121prec = nbits2prec(bitprec);122pinit(n, &C, &D, prec);123sum = cgetr (prec); affsr(0, sum);124/* Because N < 10^16 and q < sqrt(N), q fits into a long125* In fact q < 2 LONG_MAX / 3 */126av = avma; togglesign(est);127for (q = (ulong)(sqrt(gtodouble(n))*0.24 + 5); q >= 3; q--, set_avma(av))128{129GEN t = L(n, q, bitprec);130if (abscmprr(t, mpexp(divru(est,q))) < 0) continue;131132t = mulrr(t, psi(gprec_w(C, nbits2prec(bitprec / q + 32)), q, prec));133affrr(addrr(sum, t), sum);134}135p1 = addrr(sum, psi(C, 1, prec));136p2 = psi(C, 2, prec);137affrr(mod2(n)? subrr(p1,p2): addrr(p1,p2), sum);138return gerepileuptoint (ltop, roundr(mulrr(D,sum)));139}140141/* for loop over partitions of integer k.142* nbounds can restrict partitions to have length between nmin and nmax143* (the length is the number of non zero entries) and144* abounds restrict to integers between amin and amax.145*146* Start from central partition.147* By default, remove zero entries on the left.148*149* Algorithm:150*151* A partition of k is an increasing sequence v1,... vn with sum(vi)=k152* The starting point is the minimal n-partition of k: a,...a,a+1,.. a+1153* (a+1 is repeated r times with k = a * n + r).154*155* The procedure to obtain the next partition:156* - find the last index i<n such that v{i-1} != v{i} (that is vi is the start157* of the last constant range excluding vn).158* - decrease vi by one, and set v{i+1},... v{n} to be a minimal partition (of159* the right sum).160*161* Examples: we highlight the index i162* 1 1 2 2 3163* ^164* 1 1 1 3 3165* ^166* 1 1 1 2 4167* ^168* 1 1 1 1 5169* ^170* 0 2 2 2 3171* ^172* This is recursive in nature. Restrictions on upper bounds of the vi or on173* the length of the partitions are straightforward to take into account. */174175static void176parse_interval(GEN a, long *amin, long *amax)177{178switch (typ(a))179{180case t_INT:181*amax = itos(a);182break;183case t_VEC:184if (lg(a) != 3)185pari_err_TYPE("forpart [expect vector of type [amin,amax]]",a);186*amin = gtos(gel(a,1));187*amax = gtos(gel(a,2));188if (*amin>*amax || *amin<0 || *amax<=0)189pari_err_TYPE("forpart [expect 0<=min<=max, 0<max]",a);190break;191default:192pari_err_TYPE("forpart",a);193}194}195196void197forpart_init(forpart_t *T, long k, GEN abound, GEN nbound)198{199200/* bound on coefficients */201T->amin=1;202if (abound) parse_interval(abound,&T->amin,&T->amax);203else T->amax = k;204/* strip leading zeros ? */205T->strip = (T->amin > 0) ? 1 : 0;206/* bound on number of nonzero coefficients */207T->nmin=0;208if (nbound) parse_interval(nbound,&T->nmin,&T->nmax);209else T->nmax = k;210211/* non empty if nmin*amin <= k <= amax*nmax */212if ( T->amin*T->nmin > k || k > T->amax * T->nmax )213{214T->nmin = T->nmax = 0;215}216else217{218/* to reach nmin one must have k <= nmin*amax, otherwise increase nmin */219if ( T->nmin * T->amax < k )220T->nmin = 1 + (k - 1) / T->amax; /* ceil( k/tmax ) */221/* decrease nmax (if strip): k <= amin*nmax */222if (T->strip && T->nmax > k/T->amin)223T->nmax = k / T->amin; /* strip implies amin>0 */ /* fixme: take ceil( ) */224/* no need to change amin */225/* decrease amax if amax + (nmin-1)*amin > k */226if ( T->amax + (T->nmin-1)* T->amin > k )227T->amax = k - (T->nmin-1)* T->amin;228}229230if ( T->amax < T->amin )231T->nmin = T->nmax = 0;232233T->v = zero_zv(T->nmax); /* partitions will be of length <= nmax */234T->k = k;235}236237GEN238forpart_next(forpart_t *T)239{240GEN v = T->v;241long n = lg(v)-1;242long i, s, a, k, vi, vn;243244if (n>0 && v[n])245{246/* find index to increase: i s.t. v[i+1],...v[n] is central a,..a,a+1,..a+1247keep s = v[i] + v[i+1] + ... + v[n] */248s = a = v[n];249for(i = n-1; i>0 && v[i]+1 >= a; s += v[i--]);250if (i == 0) {251/* v is central [ a, a, .. a, a+1, .. a+1 ] */252if ((n+1) * T->amin > s || n == T->nmax) return NULL;253i = 1; n++;254setlg(v, n+1);255vi = T->amin;256} else {257s += v[i];258vi = v[i]+1;259}260} else {261/* init v */262s = T->k;263if (T->amin == 0) T->amin = 1;264if (T->strip) { n = T->nmin; setlg(T->v, n+1); }265if (s==0)266{267if (n==0 && T->nmin==0) {T->nmin++; return v;}268return NULL;269}270if (n==0) return NULL;271vi = T->amin;272i = T->strip ? 1 : n + 1 - T->nmin; /* first nonzero index */273if (s <= (n-i)*vi) return NULL;274}275/* now fill [ v[i],... v[n] ] with s, start at vi */276vn = s - (n-i)*vi; /* expected value for v[n] */277if (T->amax && vn > T->amax)278{279/* do not exceed amax */280long ai, q, r;281vn -= vi;282ai = T->amax - vi;283q = vn / ai; /* number of nmax */284r = vn % ai; /* value before nmax */285/* fill [ v[i],... v[n] ] as [ vi,... vi, vi+r, amax,... amax ] */286while ( q-- ) v[n--] = T->amax;287if ( n >= i ) v[n--] = vi + r;288while ( n >= i ) v[n--] = vi;289} else {290/* fill as [ v[i], ... v[i], vn ] */291for ( k=i; k<n; v[k++] = vi );292v[n] = vn;293}294return v;295}296297GEN298forpart_prev(forpart_t *T)299{300GEN v = T->v;301long n = lg(v)-1;302long j, ni, q, r;303long i, s;304if (n>0 && v[n])305{306/* find index to decrease: start of last constant sequence, excluding v[n] */307i = n-1; s = v[n];308while (i>1 && (v[i-1]==v[i] || v[i+1]==T->amax))309s+= v[i--];310if (!i) return NULL;311/* amax condition: cannot decrease i if maximal on the right */312if ( v[i+1] == T->amax ) return NULL;313/* amin condition: stop if below except if strip & try to remove */314if (v[i] == T->amin) {315if (!T->strip) return NULL;316s += v[i]; v[i] = 0;317} else {318v[i]--; s++;319}320/* zero case... */321if (v[i] == 0)322{323if (T->nmin > n-i) return NULL; /* need too many non zero coeffs */324/* reduce size of v ? */325if (T->strip) {326i = 0; n--;327setlg(v, n+1);328}329}330} else331{332s = T->k;333i = 0;334if (s==0)335{336if (n==0 && T->nmin==0) {T->nmin++; return v;}337return NULL;338}339if (n*T->amax < s || s < T->nmin*T->amin) return NULL;340}341/* set minimal partition of sum s starting from index i+1 */342ni = n-i;343q = s / ni;344r = s % ni;345for(j=i+1; j<=n-r; j++) v[j]=q;346for(j=n-r+1; j<=n; j++) v[j]=q + 1;347return v;348}349350static long351countpart(long k, GEN abound, GEN nbound)352{353pari_sp av = avma;354long n;355forpart_t T;356if (k<0) return 0;357forpart_init(&T, k, abound, nbound);358for (n=0; forpart_next(&T); n++)359set_avma(av);360return n;361}362363GEN364partitions(long k, GEN abound, GEN nbound)365{366GEN v;367forpart_t T;368long i, n = countpart(k,abound,nbound);369if (n==0) return cgetg(1, t_VEC);370forpart_init(&T, k, abound, nbound);371v = cgetg(n+1, t_VEC);372for (i=1; i<=n; i++)373gel(v,i)=zv_copy(forpart_next(&T));374return v;375}376377void378forpart(void *E, long call(void*, GEN), long k, GEN abound, GEN nbound)379{380pari_sp av = avma;381GEN v;382forpart_t T;383forpart_init(&T, k, abound, nbound);384while ((v=forpart_next(&T)))385if (call(E, v)) break;386set_avma(av);387}388389void390forpart0(GEN k, GEN code, GEN abound, GEN nbound)391{392pari_sp av = avma;393if (typ(k) != t_INT) pari_err_TYPE("forpart",k);394if (signe(k)<0) return;395push_lex(gen_0, code);396forpart((void*)code, &gp_evalvoid, itos(k), abound, nbound);397pop_lex(1);398set_avma(av);399}400401402