• Jerome Kelleher’s original Python function accel_asc, from which genComp()’s C++ code was ported, is now included with the package, with a note of where it came from. Find it with system.file("python", "accel_asc.py", package = "multicool"). His blog is no longer online, so the help for genComp() refers to this copy rather than to an archived web page.

New features

  • allPerm() has a new argument nThreads to generate large results (at least 100,000 permutations) with several threads. It is about 1.4 to 1.9 times faster with 2 to 4 threads, and close to the speed at which the result can be written to memory. Character and factor multisets always use one thread. The default nThreads = 1 works as before.
  • nextPerm() has a new argument n to return the next n permutations as the rows of a matrix (fewer at the end, then FALSE). This makes iterating through permutations much faster, while only holding n of them in memory. For example, nextPerm(m, 1000) costs about 0.016 microseconds per permutation, the same as allPerm(). The default n = 1 works as before.
  • multinom(), Stirling2()/S2() and Bell()/B() are now computed exactly using the ‘gmp’ package, and have a new argument exact. By default they still return doubles, now correct to double precision rather than silently overflowing. With exact = TRUE they return exact big integers of class bigz. The useDouble argument of multinom() is kept for backwards compatibility but no longer has any effect.

Changes in behaviour

  • initMC() now gives an error, rather than a warning, for input with fewer than two elements, and an error for input containing missing values.
  • initMC() keeps the type of its input, so logical multisets are permuted as logicals rather than as the strings "TRUE" and "FALSE".

Bug fixes

  • initMC() with non-whole numbers (e.g. c(1.5, 1.5, 2.5)) permuted the counts of each value rather than the values themselves.
  • Stirling2() and Bell() overflowed for moderate arguments, and much sooner on Windows (e.g. Stirling2(20, 5) and Bell(16) were wrong).
  • multinom() overflowed silently for large coefficients.
  • genComp() crashed R when n was zero or negative, and returned NULL when len was greater than n.
  • Calling allPerm() no longer resets the position of nextPerm().
  • Fixed a memory leak in the permutation object.

Improvements

  • genComp() is much faster for larger n. The time taken previously grew quadratically with the number of partitions (about 100 seconds for n = 50).
  • allPerm() is 10 to 30 times faster and uses much less memory. It writes the elements straight into the result matrix in C++. In the permutation benchmarks from https://stackoverflow.com/questions/22569176, it now takes 1.4 to 1.9 times as long as single-threaded ‘RcppAlgos’ (before, 15 to 54 times as long), and 1.0 to 1.5 times as long as ‘arrangements’.
  • initMC() keeps integer input as integer, so allPerm() returns an integer matrix for integer input.
  • nextPerm() is about 9 times faster per call (about 0.9 rather than 8.4 microseconds), because the permutation object is now reached through an external pointer rather than an Rcpp Module.
  • nextPerm() checks that its argument is an mc object.
  • Using an mc object after it has been saved and reloaded gives a clear error asking you to call initMC() again.
  • Native routines are now registered, and documentation and NAMESPACE are generated with roxygen2.

Acknowledgements

  • Earlier versions of this package used C++ code by Dave Barber (http://tamivox.org/dave/multinomial/code.html) to compute multinomial coefficients. It has been replaced by exact computation with the ‘gmp’ package, but we thank Dave for the code that the package relied on for many years.