[libmath-prime-util-perl] 30/55: forpart now does restricted partitions

Partha P. Mukherjee ppm-guest at moszumanska.debian.org
Thu May 21 18:53:41 UTC 2015


This is an automated email from the git hooks/post-receive script.

ppm-guest pushed a commit to annotated tag v0.41
in repository libmath-prime-util-perl.

commit 7c2fb0a13a33c15ef2af210ece08eeb0c1121288
Author: Dana Jacobsen <dana at acm.org>
Date:   Sat May 10 02:22:06 2014 -0700

    forpart now does restricted partitions
---
 XS.xs                  | 51 ++++++++++++++++++++++++++++++++++++++++++++------
 lib/Math/Prime/Util.pm | 13 ++++++-------
 2 files changed, 51 insertions(+), 13 deletions(-)

diff --git a/XS.xs b/XS.xs
index 1da21cb..d56da8f 100644
--- a/XS.xs
+++ b/XS.xs
@@ -208,6 +208,29 @@ static int _vcallsubn(pTHX_ I32 flags, I32 stashflags, const char* name, int nar
        else                     { PUSHs(sv_2mortal(newSViv(r_))); } \
   } while (0)
 
+static void part_setminmax(UV* min, UV* max, SV* sv, const char* text) {
+  if (!sv) return;
+  if (SvIOK(sv)) {
+    *min = 0;
+    *max = my_svuv(sv);
+  } else if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVAV) {
+    SV** svmin;
+    SV** svmax;
+    AV* array_a = (AV*) SvRV(sv);
+    if (av_len(array_a)+1 != 2)
+      croak("%s must have exactly 2 elements", text);
+    svmin = av_fetch(array_a, 0, 0);
+    svmax = av_fetch(array_a, 1, 0);
+    if (!svmin || !svmax || !SvIOK(*svmin) || !SvIOK(*svmax))
+      croak("Invalid data in %s", text);
+    *min = my_svuv(*svmin);
+    *max = my_svuv(*svmax);
+  } else {
+    /* Allow fall through for non-existant arg */
+    /* croak("Invalid data in %s", text); */
+  }
+}
+
 MODULE = Math::Prime::Util	PACKAGE = Math::Prime::Util
 
 PROTOTYPES: ENABLE
@@ -1229,14 +1252,15 @@ fordivisors (SV* block, IN SV* svn)
     Safefree(divs);
 
 void
-forpart (SV* block, IN SV* svn)
-  PROTOTYPE: &$
+forpart (SV* block, IN SV* svn, IN SV* svra = 0, IN SV* svrn = 0)
+  PROTOTYPE: &$;$$
   PREINIT:
-    UV i, m, h, n;
+    UV i, m, h, n, mina, maxa, minn, maxn;
     UV *x;
     GV *gv;
     HV *stash;
     CV *cv;
+    SV** svals;
   PPCODE:
     cv = sv_2cv(block, &stash, &gv, 0);
     if (cv == Nullcv)
@@ -1247,17 +1271,29 @@ forpart (SV* block, IN SV* svn)
     }
     n = my_svuv(svn);
 
+    New(0, svals, n+1, SV*);
+    for (i = 0; i <= n; i++) {
+      svals[i] = newSVuv(i);
+      SvREADONLY_on(svals[i]);
+    }
+
     /* ZS1 algorithm from Zoghbi and Stojmenovic 1998) */
     New(0, x, n+1, UV);
     for(i = 0; i <= n; i++)  x[i] = 1;
     x[1] = n;
     m = (n > 0) ? 1 : 0;   /* n=0 => one call with empty list */
     h = 1;
+
+    mina = 0;  maxa = n;  minn = 0;  maxn = n;
+    if (svra != 0) part_setminmax( &mina, &maxa, svra, "forpart A arg" );
+    if (svrn != 0) part_setminmax( &minn, &maxn, svrn, "forpart N arg" );
+
     {
       while (1) {
-        { dSP; ENTER; SAVETMPS; PUSHMARK(SP); EXTEND(SP, m);
-          for (i = m; i >= 1; i--) { PUSH_NPARITY(x[i]); }
-          PUTBACK; call_sv((SV*)cv, G_VOID|G_DISCARD); FREETMPS; LEAVE;
+        if (m >= minn && m <= maxn && x[m] >= mina && x[1] <= maxa)
+        { dSP; ENTER; PUSHMARK(SP);
+          EXTEND(SP, m); for (i=1; i <= m; i++) { PUSHs(svals[x[i]]); }
+          PUTBACK; call_sv((SV*)cv, G_VOID|G_DISCARD); LEAVE;
         }
         if (x[1] <= 1)
           break;
@@ -1277,3 +1313,6 @@ forpart (SV* block, IN SV* svn)
       }
     }
     Safefree(x);
+    for (i = 0; i <= n; i++)
+      SvREFCNT_dec(svals[i]);
+    Safefree(svals);
diff --git a/lib/Math/Prime/Util.pm b/lib/Math/Prime/Util.pm
index 33f08fb..14e7900 100644
--- a/lib/Math/Prime/Util.pm
+++ b/lib/Math/Prime/Util.pm
@@ -27,7 +27,7 @@ our @EXPORT_OK =
       miller_rabin miller_rabin_random
       lucas_sequence
       primes
-      forprimes forcomposites fordivisors
+      forprimes forcomposites fordivisors forpart
       prime_iterator prime_iterator_object
       next_prime  prev_prime
       prime_count
@@ -2123,15 +2123,14 @@ This uses a combinatorial calculation, which means it will not be very
 fast compared to Pari, Mathematica, or FLINT which use the Rademacher
 formula using multi-precision floating point.  In 10 seconds:
 
-           65    Integer::Partition
+           70    Integer::Partition
+           90    MPU forpart { $n++ }
        10_000    MPU pure Perl partitions
-      200_000    MPU GMP partitions
-   22_000_000    Pari's numbpart
+      250_000    MPU GMP partitions
+   35_000_000    Pari's numbpart
   500_000_000    Jonathan Bober's partitions_c.cc v0.6
 
-If you want the enumerated partitions, see L<Integer::Partition>.  It uses
-a memory efficient iterator and is very fast for enumeration.  It is not
-practical for producing large partition numbers as seen above.
+If you want the enumerated partitions, see L</forpart>.
 
 
 =head2 carmichael_lambda

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-perl/packages/libmath-prime-util-perl.git



More information about the Pkg-perl-cvs-commits mailing list