First off, I am the author of RcppAlgos
. There are a couple of ways around your current issue.
Before we start attacking your main issue, let’s start by simplifying your code a bit.
Using FUN
Instead of generating all permutations then calling asplit
, we can make use of the FUN
parameter to convert our vector to a matrix on the fly just as we can with combn
:
library(RcppAlgos)
m <- 3L
n <- 2L
perms <- permuteGeneral(c(1L, -1L), m * n, TRUE, FUN = \(x) {
matrix(x, m, n)
})
perms[1:2]
#> [[1]]
#> [,1] [,2]
#> [1,] 1 1
#> [2,] 1 1
#> [3,] 1 1
#>
#> [[2]]
#> [,1] [,2]
#> [1,] 1 1
#> [2,] 1 1
#> [3,] 1 -1
perms[63:64]
#> [[1]]
#> [,1] [,2]
#> [1,] -1 -1
#> [2,] -1 -1
#> [3,] -1 1
#>
#> [[2]]
#> [,1] [,2]
#> [1,] -1 -1
#> [2,] -1 -1
#> [3,] -1 -1
Attacking the Memory Problem
Using lower
and upper
We can make use of the lower
and upper
parameters so that we can generate permutations in chunks:
## Generate the first 2 results
permuteGeneral(c(1L, -1L), m * n, TRUE, FUN = \(x) {
matrix(x, m, n)
}, upper = 2)
#> [[1]]
#> [,1] [,2]
#> [1,] 1 1
#> [2,] 1 1
#> [3,] 1 1
#>
#> [[2]]
#> [,1] [,2]
#> [1,] 1 1
#> [2,] 1 1
#> [3,] 1 -1
## Get the next 2 results
permuteGeneral(c(1L, -1L), m * n, TRUE, FUN = \(x) {
matrix(x, m, n)
}, lower = 3, upper = 4)
#> [[1]]
#> [,1] [,2]
#> [1,] 1 1
#> [2,] 1 -1
#> [3,] 1 1
#>
#> [[2]]
#> [,1] [,2]
#> [1,] 1 1
#> [2,] 1 -1
#> [3,] 1 -1
This gets the job done, however it is somewhat cumbersome.
Is there is a more elegant solution?
A Better Way
RcppAlgos
offers combinatorial iterators so that one can generate n results at a time, thus keeping memory low.
Using iterators
iter <- permuteIter(c(1L, -1L), m * n, TRUE, FUN = \(x) {
matrix(x, m, n)
})
## See the first result
iter@nextIter()
#> [,1] [,2]
#> [1,] 1 1
#> [2,] 1 1
#> [3,] 1 1
## Get the next 2 results (Note we are using nextNIter instead of nextIter)
iter@nextNIter(2)
#> [[1]]
#> [,1] [,2]
#> [1,] 1 1
#> [2,] 1 1
#> [3,] 1 -1
#>
#> [[2]]
#> [,1] [,2]
#> [1,] 1 1
#> [2,] 1 -1
#> [3,] 1 1
The really nice thing about these iterators is that they are bidirectional and they also offer random access:
## See the previous result
iter@prevIter()
#> [,1] [,2]
#> [1,] 1 1
#> [2,] 1 1
#> [3,] 1 -1
## Get a quick summary
iter@summary()
#> $description
#> [1] "Permutations with repetition of 2 choose 6"
#>
#> $currentIndex
#> [1] 2
#>
#> $totalResults
#> [1] 64
#>
#> $totalRemaining
#> [1] 62
## Go to the middle
middle <- permuteCount(2, m * n, TRUE) %/% 2L
middle
#> [1] 32
iter[[middle]]
#> [,1] [,2]
#> [1,] 1 -1
#> [2,] -1 -1
#> [3,] -1 -1
## See the last result
iter@back()
#> [,1] [,2]
#> [1,] -1 -1
#> [2,] -1 -1
#> [3,] -1 -1
## Go back to the front
iter@front()
#> [,1] [,2]
#> [1,] 1 1
#> [2,] 1 1
#> [3,] 1 1
And as for the question at hand, memory will be no problem!
m_big <- 12L
n_big <- 6L
iter_big <- permuteIter(c(1L, -1L), m_big * n_big, TRUE, FUN = \(x) {
matrix(x, m_big, n_big)
})
iter_big@nextIter()
#> [,1] [,2] [,3] [,4] [,5] [,6]
#> [1,] 1 1 1 1 1 1
#> [2,] 1 1 1 1 1 1
#> [3,] 1 1 1 1 1 1
#> [4,] 1 1 1 1 1 1
#> [5,] 1 1 1 1 1 1
#> [6,] 1 1 1 1 1 1
#> [7,] 1 1 1 1 1 1
#> [8,] 1 1 1 1 1 1
#> [9,] 1 1 1 1 1 1
#> [10,] 1 1 1 1 1 1
#> [11,] 1 1 1 1 1 1
#> [12,] 1 1 1 1 1 1
iter_big@summary()
#> $description
#> [1] "Permutations with repetition of 2 choose 72"
#>
#> $currentIndex
#> Big Integer ('bigz') :
#> [1] 1
#>
#> $totalResults
#> Big Integer ('bigz') :
#> [1] 4722366482869645213696
#>
#> $totalRemaining
#> Big Integer ('bigz') :
#> [1] 4722366482869645213695
iter_big@back()
#> [,1] [,2] [,3] [,4] [,5] [,6]
#> [1,] -1 -1 -1 -1 -1 -1
#> [2,] -1 -1 -1 -1 -1 -1
#> [3,] -1 -1 -1 -1 -1 -1
#> [4,] -1 -1 -1 -1 -1 -1
#> [5,] -1 -1 -1 -1 -1 -1
#> [6,] -1 -1 -1 -1 -1 -1
#> [7,] -1 -1 -1 -1 -1 -1
#> [8,] -1 -1 -1 -1 -1 -1
#> [9,] -1 -1 -1 -1 -1 -1
#> [10,] -1 -1 -1 -1 -1 -1
#> [11,] -1 -1 -1 -1 -1 -1
#> [12,] -1 -1 -1 -1 -1 -1
iter_big[["100"]]
#> [,1] [,2] [,3] [,4] [,5] [,6]
#> [1,] 1 1 1 1 1 1
#> [2,] 1 1 1 1 1 1
#> [3,] 1 1 1 1 1 1
#> [4,] 1 1 1 1 1 1
#> [5,] 1 1 1 1 1 1
#> [6,] 1 1 1 1 1 -1
#> [7,] 1 1 1 1 1 -1
#> [8,] 1 1 1 1 1 1
#> [9,] 1 1 1 1 1 1
#> [10,] 1 1 1 1 1 1
#> [11,] 1 1 1 1 1 -1
#> [12,] 1 1 1 1 1 -1
iter_big@prevNIter(2)
#> [[1]]
#> [,1] [,2] [,3] [,4] [,5] [,6]
#> [1,] 1 1 1 1 1 1
#> [2,] 1 1 1 1 1 1
#> [3,] 1 1 1 1 1 1
#> [4,] 1 1 1 1 1 1
#> [5,] 1 1 1 1 1 1
#> [6,] 1 1 1 1 1 -1
#> [7,] 1 1 1 1 1 -1
#> [8,] 1 1 1 1 1 1
#> [9,] 1 1 1 1 1 1
#> [10,] 1 1 1 1 1 1
#> [11,] 1 1 1 1 1 -1
#> [12,] 1 1 1 1 1 1
#>
#> [[2]]
#> [,1] [,2] [,3] [,4] [,5] [,6]
#> [1,] 1 1 1 1 1 1
#> [2,] 1 1 1 1 1 1
#> [3,] 1 1 1 1 1 1
#> [4,] 1 1 1 1 1 1
#> [5,] 1 1 1 1 1 1
#> [6,] 1 1 1 1 1 -1
#> [7,] 1 1 1 1 1 -1
#> [8,] 1 1 1 1 1 1
#> [9,] 1 1 1 1 1 1
#> [10,] 1 1 1 1 1 1
#> [11,] 1 1 1 1 1 1
#> [12,] 1 1 1 1 1 -1