Code coverage tests

This page documents the degree to which the PARI/GP source code is tested by our public test suite, distributed with the source distribution in directory src/test/. This is measured by the gcov utility; we then process gcov output using the lcov frond-end.

We test a few variants depending on Configure flags on the pari.math.u-bordeaux.fr machine (x86_64 architecture), and agregate them in the final report:

The target is to exceed 90% coverage for all mathematical modules (given that branches depending on DEBUGLEVEL or DEBUGMEM are not covered). This script is run to produce the results below.

LCOV - code coverage report
Current view: top level - modules - part.c (source / functions) Hit Total Coverage
Test: PARI/GP v2.16.2 lcov report (development 29115-f22e516b23) Lines: 154 189 81.5 %
Date: 2024-04-19 08:07:09 Functions: 12 13 92.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Copyright (C) 2002  The PARI group.
       2             : 
       3             : This file is part of the PARI/GP package.
       4             : 
       5             : PARI/GP is free software; you can redistribute it and/or modify it under the
       6             : terms of the GNU General Public License as published by the Free Software
       7             : Foundation; either version 2 of the License, or (at your option) any later
       8             : version. It is distributed in the hope that it will be useful, but WITHOUT
       9             : ANY WARRANTY WHATSOEVER.
      10             : 
      11             : Check the License for details. You should have received a copy of it, along
      12             : with the package; see the file 'COPYING'. If not, write to the Free Software
      13             : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
      14             : 
      15             : /* Original code contributed by: Ralf Stephan (ralf@ark.in-berlin.de).
      16             :  * Updated by Bill Allombert (2014) to use Selberg formula for L
      17             :  * following http://dx.doi.org/10.1112/S1461157012001088
      18             :  *
      19             :  * This program is basically the implementation of the script
      20             :  *
      21             :  * Psi(n, q) = my(a=sqrt(2/3)*Pi/q, b=n-1/24, c=sqrt(b));
      22             :  *             (sqrt(q)/(2*sqrt(2)*b*Pi))*(a*cosh(a*c)-(sinh(a*c)/c))
      23             :  * L(n,q)=sqrt(k/3)*sum(l=0,2*k-1,
      24             :           if(((3*l^2+l)/2+n)%k==0,(-1)^l*cos((6*l+1)/(6*k)*Pi)))
      25             :  * part(n) = round(sum(q=1,5 + 0.24*sqrt(n),L(n,q)*Psi(n,q)))
      26             :  *
      27             :  * only faster.
      28             :  *
      29             :  * ------------------------------------------------------------------
      30             :  *   The first restriction depends on Pari's maximum precision of floating
      31             :  * point reals, which is 268435454 bits in 2.2.4, since the algorithm needs
      32             :  * high precision exponentials. For that engine, the maximum possible argument
      33             :  * would be in [5*10^15,10^16], the computation of which would need days on
      34             :  * a ~1-GHz computer. */
      35             : 
      36             : #include "pari.h"
      37             : #include "paripriv.h"
      38             : 
      39             : /****************************************************************/
      40             : 
      41             : /* Given c = sqrt(2/3)*Pi*sqrt(N-1/24)
      42             :  * Psi(N, q) = my(a = c/q); sqrt(q) * (a*cosh(a) - sinh(a)) */
      43             : static GEN
      44     1109212 : psi(GEN c, ulong q, long prec)
      45             : {
      46     1109212 :   GEN a = divru(c, q), ea = mpexp(a), invea = invr(ea);
      47     1109212 :   GEN cha = shiftr(addrr(ea, invea), -1);  /* ch(a) */
      48     1109212 :   GEN sha = shiftr(subrr(ea, invea), -1);  /* sh(a) */
      49     1109212 :   return mulrr(sqrtr(utor(q,prec)), subrr(mulrr(a,cha), sha));
      50             : }
      51             : 
      52             : /* L(n,q)=sqrt(k/3)*sum(l=0,2*k-1,
      53             :           if(((3*l^2+l)/2+n)%k==0,(-1)^l*cos((6*l+1)/(6*k)*Pi)))
      54             :  * Never called with q < 3, so ignore this case */
      55             : static GEN
      56     1295452 : L(GEN n, ulong k, long bitprec)
      57             : {
      58             :   ulong r, l, m;
      59     1295452 :   long pr = nbits2prec(bitprec / k + k);
      60     1295452 :   GEN s = utor(0,pr), pi = mppi(pr);
      61     1295452 :   pari_sp av = avma;
      62             : 
      63     1295452 :   r = 2; m = umodiu(n,k);
      64    34034238 :   for (l = 0; l < 2*k; l++)
      65             :   {
      66    32738786 :     if (m == 0)
      67             :     {
      68     2590332 :       GEN c = mpcos(divru(mulru(pi, 6*l+1), 6*k));
      69     2590332 :       if (odd(l)) subrrz(s, c, s); else addrrz(s, c, s);
      70     2590332 :       set_avma(av);
      71             :     }
      72    32738786 :     m += r; if (m >= k) m -= k;
      73    32738786 :     r += 3; if (r >= k) r -= k;
      74             :   }
      75             :   /* multiply by sqrt(k/3) */
      76     1295452 :   return mulrr(s, sqrtr((k % 3)? rdivss(k,3,pr): utor(k/3,pr)));
      77             : }
      78             : 
      79             : /* Return a low precision estimate of log p(n). */
      80             : static GEN
      81       70000 : estim(GEN n)
      82             : {
      83       70000 :   pari_sp av = avma;
      84       70000 :   GEN p1, pi = mppi (DEFAULTPREC);
      85             : 
      86       70000 :   p1 = divru( itor(shifti(n,1), DEFAULTPREC), 3 );
      87       70000 :   p1 = mpexp( mulrr(pi, sqrtr(p1)) ); /* exp(Pi * sqrt(2N/3)) */
      88       70000 :   p1 = divri (shiftr(p1,-2), n);
      89       70000 :   p1 = divrr(p1, sqrtr( utor(3,DEFAULTPREC) ));
      90       70000 :   return gerepileupto(av, mplog(p1));
      91             : }
      92             : 
      93             : /* c = sqrt(2/3)*Pi*sqrt(n-1/24);  d = 1 / ((2*b)^(3/2) * Pi); */
      94             : static void
      95       70000 : pinit(GEN n, GEN *c, GEN *d, ulong prec)
      96             : {
      97       70000 :   GEN b = divru( itor( subiu(muliu(n,24), 1), prec ), 24 ); /* n - 1/24 */
      98       70000 :   GEN sqrtb = sqrtr(b), Pi = mppi(prec), pi2sqrt2, pisqrt2d3;
      99             : 
     100       70000 :   pisqrt2d3 = mulrr(Pi, sqrtr( divru(utor(2, prec), 3) ));
     101       70000 :   pi2sqrt2  = mulrr(Pi, sqrtr( utor(8, prec) ));
     102       70000 :   *c = mulrr(pisqrt2d3, sqrtb);
     103       70000 :   *d = invr( mulrr(pi2sqrt2, mulrr(b,sqrtb)) );
     104       70000 : }
     105             : 
     106             : /* part(n) = round(sum(q=1,5 + 0.24*sqrt(n), L(n,q)*Psi(n,q))) */
     107             : GEN
     108       70021 : numbpart(GEN n)
     109             : {
     110       70021 :   pari_sp ltop = avma, av;
     111             :   GEN sum, est, C, D, p1, p2;
     112             :   long prec, bitprec;
     113             :   ulong q;
     114             : 
     115       70021 :   if (typ(n) != t_INT) pari_err_TYPE("partition function",n);
     116       70021 :   if (signe(n) < 0) return gen_0;
     117       70021 :   if (abscmpiu(n, 2) < 0) return gen_1;
     118       70007 :   if (cmpii(n, uu32toi(0x38d7e, 0xa4c68000)) >= 0)
     119           7 :     pari_err_OVERFLOW("numbpart [n < 10^15]");
     120       70000 :   est = estim(n);
     121       70000 :   bitprec = (long)(rtodbl(est)/M_LN2) + 32;
     122       70000 :   prec = nbits2prec(bitprec);
     123       70000 :   pinit(n, &C, &D, prec);
     124       70000 :   sum = utor(0, prec);
     125             :   /* Because N < 10^16 and q < sqrt(N), q fits into a long
     126             :    * In fact q < 2 LONG_MAX / 3 */
     127       70000 :   av = avma; togglesign(est);
     128     1365452 :   for (q = (ulong)(sqrt(gtodouble(n))*0.24 + 5); q >= 3; q--, set_avma(av))
     129             :   {
     130     1295452 :     GEN t = L(n, q, bitprec);
     131     1295452 :     if (abscmprr(t, mpexp(divru(est,q))) < 0) continue;
     132             : 
     133      969212 :     t = mulrr(t, psi(gprec_w(C, nbits2prec(bitprec / q + 32)), q, prec));
     134      969212 :     affrr(addrr(sum, t), sum);
     135             :   }
     136       70000 :   p1 = addrr(sum, psi(C, 1, prec));
     137       70000 :   p2 = psi(C, 2, prec);
     138       70000 :   affrr(mod2(n)? subrr(p1,p2): addrr(p1,p2), sum);
     139       70000 :   return gerepileuptoint (ltop, roundr(mulrr(D,sum)));
     140             : }
     141             : 
     142             : /* for loop over partitions of integer k.
     143             :  * nbounds can restrict partitions to have length between nmin and nmax
     144             :  * (the length is the number of non zero entries) and
     145             :  * abounds restrict to integers between amin and amax.
     146             :  *
     147             :  * Start from central partition.
     148             :  * By default, remove zero entries on the left.
     149             :  *
     150             :  * Algorithm:
     151             :  *
     152             :  * A partition of k is an increasing sequence v1,... vn with sum(vi)=k
     153             :  * The starting point is the minimal n-partition of k: a,...a,a+1,.. a+1
     154             :  * (a+1 is repeated r times with k = a * n + r).
     155             :  *
     156             :  * The procedure to obtain the next partition:
     157             :  * - find the last index i<n such that v{i-1} != v{i} (that is vi is the start
     158             :  * of the last constant range excluding vn).
     159             :  * - decrease vi by one, and set v{i+1},... v{n} to be a minimal partition (of
     160             :  * the right sum).
     161             :  *
     162             :  * Examples: we highlight the index i
     163             :  * 1 1 2 2 3
     164             :  *     ^
     165             :  * 1 1 1 3 3
     166             :  *       ^
     167             :  * 1 1 1 2 4
     168             :  *       ^
     169             :  * 1 1 1 1 5
     170             :  * ^
     171             :  * 0 2 2 2 3
     172             :  *   ^
     173             :  * This is recursive in nature. Restrictions on upper bounds of the vi or on
     174             :  * the length of the partitions are straightforward to take into account. */
     175             : 
     176             : static void
     177         217 : parse_interval(GEN a, long *amin, long *amax)
     178             : {
     179         217 :   switch (typ(a))
     180             :   {
     181          49 :   case t_INT:
     182          49 :     *amax = itos(a);
     183          49 :     break;
     184         168 :   case t_VEC:
     185         168 :     if (lg(a) != 3)
     186           0 :       pari_err_TYPE("forpart [expect vector of type [amin,amax]]",a);
     187         168 :     *amin = gtos(gel(a,1));
     188         168 :     *amax = gtos(gel(a,2));
     189         168 :     if (*amin>*amax || *amin<0 || *amax<=0)
     190           0 :       pari_err_TYPE("forpart [expect 0<=min<=max, 0<max]",a);
     191         168 :     break;
     192           0 :   default:
     193           0 :     pari_err_TYPE("forpart",a);
     194             :   }
     195         217 : }
     196             : 
     197             : void
     198         238 : forpart_init(forpart_t *T, long k, GEN abound, GEN nbound)
     199             : {
     200             : 
     201             :   /* bound on coefficients */
     202         238 :   T->amin=1;
     203         238 :   if (abound) parse_interval(abound,&T->amin,&T->amax);
     204         126 :   else T->amax = k;
     205             :   /* strip leading zeros ? */
     206         238 :   T->strip = (T->amin > 0) ? 1 : 0;
     207             :   /* bound on number of nonzero coefficients */
     208         238 :   T->nmin=0;
     209         238 :   if (nbound) parse_interval(nbound,&T->nmin,&T->nmax);
     210         133 :   else T->nmax = k;
     211             : 
     212             :   /* non empty if nmin*amin <= k <= amax*nmax */
     213         238 :   if ( T->amin*T->nmin > k || k > T->amax * T->nmax )
     214             :   {
     215           0 :     T->nmin = T->nmax = 0;
     216             :   }
     217             :   else
     218             :   {
     219             :     /* to reach nmin one must have k <= nmin*amax, otherwise increase nmin */
     220         238 :     if ( T->nmin * T->amax < k )
     221         154 :       T->nmin = 1 + (k - 1) / T->amax; /* ceil( k/tmax ) */
     222             :     /* decrease nmax (if strip): k <= amin*nmax */
     223         238 :     if (T->strip && T->nmax > k/T->amin)
     224          14 :       T->nmax = k / T->amin; /* strip implies amin>0 */ /* fixme: take ceil( ) */
     225             :     /* no need to change amin */
     226             :     /* decrease amax if amax + (nmin-1)*amin > k  */
     227         238 :     if ( T->amax + (T->nmin-1)* T->amin > k )
     228          56 :       T->amax = k - (T->nmin-1)* T->amin;
     229             :   }
     230             : 
     231         238 :   if ( T->amax < T->amin )
     232          21 :     T->nmin = T->nmax = 0;
     233             : 
     234         238 :   T->v = zero_zv(T->nmax); /* partitions will be of length <= nmax */
     235         238 :   T->k = k;
     236         238 : }
     237             : 
     238             : GEN
     239     3161753 : forpart_next(forpart_t *T)
     240             : {
     241     3161753 :   GEN v = T->v;
     242     3161753 :   long n = lg(v)-1;
     243             :   long i, s, a, k, vi, vn;
     244             : 
     245     3161753 :   if (n>0 && v[n])
     246             :   {
     247             :     /* find index to increase: i s.t. v[i+1],...v[n] is central a,..a,a+1,..a+1
     248             :        keep s = v[i] + v[i+1] + ... + v[n] */
     249     3161508 :     s = a = v[n];
     250     4638872 :     for(i = n-1; i>0 && v[i]+1 >= a; s += v[i--]);
     251     3161508 :     if (i == 0) {
     252             :       /* v is central [ a, a, .. a, a+1, .. a+1 ] */
     253        1120 :       if ((n+1) * T->amin > s || n == T->nmax) return NULL;
     254         980 :       i = 1; n++;
     255         980 :       setlg(v, n+1);
     256         980 :       vi = T->amin;
     257             :     } else {
     258     3160388 :       s += v[i];
     259     3160388 :       vi = v[i]+1;
     260             :     }
     261             :   } else {
     262             :     /* init v */
     263         245 :     s = T->k;
     264         245 :     if (T->amin == 0) T->amin = 1;
     265         245 :     if (T->strip) { n = T->nmin; setlg(T->v, n+1); }
     266         245 :     if (s==0)
     267             :     {
     268          21 :       if (n==0 && T->nmin==0) {T->nmin++; return v;}
     269           7 :       return NULL;
     270             :     }
     271         224 :     if (n==0) return NULL;
     272         217 :     vi = T->amin;
     273         217 :     i = T->strip ? 1 : n + 1 - T->nmin; /* first nonzero index */
     274         217 :     if (s <= (n-i)*vi) return NULL;
     275             :   }
     276             :   /* now fill [ v[i],... v[n] ] with s, start at vi */
     277     3161571 :   vn = s - (n-i)*vi; /* expected value for v[n] */
     278     3161571 :   if (T->amax && vn > T->amax)
     279         140 :   {
     280             :     /* do not exceed amax */
     281             :     long ai, q, r;
     282         140 :     vn -= vi;
     283         140 :     ai = T->amax - vi;
     284         140 :     q = vn / ai; /* number of nmax */
     285         140 :     r = vn % ai; /* value before nmax */
     286             :     /* fill [ v[i],... v[n] ] as [ vi,... vi, vi+r, amax,... amax ] */
     287         469 :     while ( q-- ) v[n--] = T->amax;
     288         140 :     if ( n >= i ) v[n--] = vi + r;
     289         371 :     while ( n >= i ) v[n--] = vi;
     290             :   } else {
     291             :     /* fill as [ v[i], ... v[i], vn ] */
     292     7798840 :     for ( k=i; k<n; v[k++] = vi );
     293     3161431 :     v[n] = vn;
     294             :   }
     295     3161571 :   return v;
     296             : }
     297             : 
     298             : GEN
     299           0 : forpart_prev(forpart_t *T)
     300             : {
     301           0 :   GEN v = T->v;
     302           0 :   long n = lg(v)-1;
     303             :   long j, ni, q, r;
     304             :   long i, s;
     305           0 :   if (n>0 && v[n])
     306             :   {
     307             :     /* find index to decrease: start of last constant sequence, excluding v[n] */
     308           0 :     i = n-1; s = v[n];
     309           0 :     while (i>1 && (v[i-1]==v[i] || v[i+1]==T->amax))
     310           0 :       s+= v[i--];
     311           0 :     if (!i) return NULL;
     312             :     /* amax condition: cannot decrease i if maximal on the right */
     313           0 :     if ( v[i+1] == T->amax ) return NULL;
     314             :     /* amin condition: stop if below except if strip & try to remove */
     315           0 :     if (v[i] == T->amin) {
     316           0 :       if (!T->strip) return NULL;
     317           0 :       s += v[i]; v[i] = 0;
     318             :     } else {
     319           0 :       v[i]--; s++;
     320             :     }
     321             :     /* zero case... */
     322           0 :     if (v[i] == 0)
     323             :     {
     324           0 :       if (T->nmin > n-i) return NULL; /* need too many non zero coeffs */
     325             :       /* reduce size of v ? */
     326           0 :       if (T->strip) {
     327           0 :         i = 0; n--;
     328           0 :         setlg(v, n+1);
     329             :       }
     330             :     }
     331             :   } else
     332             :   {
     333           0 :     s = T->k;
     334           0 :     i = 0;
     335           0 :     if (s==0)
     336             :     {
     337           0 :       if (n==0 && T->nmin==0) {T->nmin++; return v;}
     338           0 :       return NULL;
     339             :     }
     340           0 :     if (n*T->amax < s || s < T->nmin*T->amin) return NULL;
     341             :   }
     342             :   /* set minimal partition of sum s starting from index i+1 */
     343           0 :   ni = n-i;
     344           0 :   q = s / ni;
     345           0 :   r = s % ni;
     346           0 :   for(j=i+1;   j<=n-r; j++) v[j]=q;
     347           0 :   for(j=n-r+1; j<=n;   j++) v[j]=q + 1;
     348           0 :   return v;
     349             : }
     350             : 
     351             : static long
     352          98 : countpart(long k, GEN abound, GEN nbound)
     353             : {
     354          98 :   pari_sp av = avma;
     355             :   long n;
     356             :   forpart_t T;
     357          98 :   if (k<0) return 0;
     358          91 :   forpart_init(&T, k, abound, nbound);
     359         819 :   for (n=0; forpart_next(&T); n++)
     360         728 :   set_avma(av);
     361          91 :   return n;
     362             : }
     363             : 
     364             : GEN
     365          98 : partitions(long k, GEN abound, GEN nbound)
     366             : {
     367             :   GEN v;
     368             :   forpart_t T;
     369          98 :   long i, n = countpart(k,abound,nbound);
     370          98 :   if (n==0) return cgetg(1, t_VEC);
     371          70 :   forpart_init(&T, k, abound, nbound);
     372          70 :   v = cgetg(n+1, t_VEC);
     373         798 :   for (i=1; i<=n; i++)
     374         728 :     gel(v,i)=zv_copy(forpart_next(&T));
     375          70 :   return v;
     376             : }
     377             : 
     378             : void
     379          77 : forpart(void *E, long call(void*, GEN), long k, GEN abound, GEN nbound)
     380             : {
     381          77 :   pari_sp av = avma;
     382             :   GEN v;
     383             :   forpart_t T;
     384          77 :   forpart_init(&T, k, abound, nbound);
     385     3160206 :   while ((v=forpart_next(&T)))
     386     3160129 :     if (call(E, v)) break;
     387          77 :   set_avma(av);
     388          77 : }
     389             : 
     390             : void
     391          84 : forpart0(GEN k, GEN code, GEN abound, GEN nbound)
     392             : {
     393          84 :   pari_sp av = avma;
     394          84 :   if (typ(k) != t_INT) pari_err_TYPE("forpart",k);
     395          84 :   if (signe(k)<0) return;
     396          77 :   push_lex(gen_0, code);
     397          77 :   forpart((void*)code, &gp_evalvoid, itos(k), abound, nbound);
     398          77 :   pop_lex(1);
     399          77 :   set_avma(av);
     400             : }

Generated by: LCOV version 1.14