Per le permutazioni, rcppalgos è fantastico. Sfortunatamente, ci sono 479 milioni di possibilità con 12 campi, il che significa che occupa troppa memoria per la maggior parte delle persone:
library(RcppAlgos)
elements <- 12
permuteGeneral(elements, elements)
#> Error: cannot allocate vector of size 21.4 Gb
Ci sono alcune alternative.
Prendi un campione delle permutazioni. Ciò significa che solo 1 milione invece di 479 milioni. Per fare questo, puoi usare permuteSample(12, 12, n = 1e6). Vedi la risposta di @ JosephWood per un approccio un po 'simile, tranne per il fatto che campiona 479 milioni di permutazioni;)
Crea un ciclo in rcpp per valutare la permutazione alla creazione. Ciò consente di risparmiare memoria perché si finirà per costruire la funzione per restituire solo i risultati corretti.
Affronta il problema con un algoritmo diverso. Mi concentrerò su questa opzione.
Nuovo algoritmo con vincoli

I segmenti dovrebbero essere 26
Sappiamo che ogni segmento di linea nella stella sopra deve aggiungere fino a 26. Possiamo aggiungere quel vincolo alla generazione delle nostre permutazioni - dandoci solo combinazioni che aggiungono fino a 26:
# only certain combinations will add to 26
lucky_combo <- comboGeneral(12, 4, comparisonFun = '==', constraintFun = 'sum', limitConstraints = 26L)
Gruppi ABCD ed EFGH
Nella stella sopra, ho colorato tre gruppi in modo diverso: ABCD , EFGH e IJLK . I primi due gruppi inoltre non hanno punti in comune e sono anche segmenti di interesse online. Pertanto, possiamo aggiungere un altro vincolo: per le combinazioni che aggiungono fino a 26, dobbiamo garantire che ABCD ed EFGH non abbiano sovrapposizioni di numeri. Ad IJLK verranno assegnati i 4 numeri rimanenti.
library(RcppAlgos)
lucky_combo <- comboGeneral(12, 4, comparisonFun = '==', constraintFun = 'sum', limitConstraints = 26L)
two_combo <- comboGeneral(nrow(lucky_combo), 2)
unique_combos <- !apply(cbind(lucky_combo[two_combo[, 1], ], lucky_combo[two_combo[, 2], ]), 1, anyDuplicated)
grp1 <- lucky_combo[two_combo[unique_combos, 1],]
grp2 <- lucky_combo[two_combo[unique_combos, 2],]
grp3 <- t(apply(cbind(grp1, grp2), 1, function(x) setdiff(1:12, x)))
Permuta attraverso i gruppi
Dobbiamo trovare tutte le permutazioni di ciascun gruppo. Cioè, abbiamo solo combinazioni che aggiungono fino a 26. Ad esempio, dobbiamo prendere 1, 2, 11, 12e creare 1, 2, 12, 11; 1, 12, 2, 11; ....
#create group perms (i.e., we need all permutations of grp1, grp2, and grp3)
n <- 4
grp_perms <- permuteGeneral(n, n)
n_perm <- nrow(grp_perms)
# We create all of the permutations of grp1. Then we have to repeat grp1 permutations
# for all grp2 permutations and then we need to repeat one more time for grp3 permutations.
stars <- cbind(do.call(rbind, lapply(asplit(grp1, 1), function(x) matrix(x[grp_perms], ncol = n)))[rep(seq_len(sum(unique_combos) * n_perm), each = n_perm^2), ],
do.call(rbind, lapply(asplit(grp2, 1), function(x) matrix(x[grp_perms], ncol = n)[rep(1:n_perm, n_perm), ]))[rep(seq_len(sum(unique_combos) * n_perm^2), each = n_perm), ],
do.call(rbind, lapply(asplit(grp3, 1), function(x) matrix(x[grp_perms], ncol = n)[rep(1:n_perm, n_perm^2), ])))
colnames(stars) <- LETTERS[1:12]
Calcoli finali
L'ultimo passo è fare la matematica. Io uso lapply()e Reduce()qui per fare una programmazione più funzionale, altrimenti un sacco di codice verrebbe digitato sei volte. Vedi la soluzione originale per una spiegazione più approfondita del codice matematico.
# creating a list will simplify our math as we can use Reduce()
col_ind <- list(c('A', 'B', 'C', 'D'), #these two will always be 26
c('E', 'F', 'G', 'H'), #these two will always be 26
c('I', 'C', 'J', 'H'),
c('D', 'J', 'G', 'K'),
c('K', 'F', 'L', 'A'),
c('E', 'L', 'B', 'I'))
# Determine which permutations result in a lucky star
L <- lapply(col_ind, function(cols) rowSums(stars[, cols]) == 26)
soln <- Reduce(`&`, L)
# A couple of ways to analyze the result
rbind(stars[which(soln),], stars[which(soln), c(1,8, 9, 10, 11, 6, 7, 2, 3, 4, 5, 12)])
table(Reduce('+', L)) * 2
2 3 4 6
2090304 493824 69120 960
Scambio di ABCD ed EFGH
Alla fine del codice sopra, ho approfittato del fatto che possiamo scambiare ABCDe EFGHottenere le permutazioni rimanenti. Ecco il codice per confermare che sì, possiamo scambiare i due gruppi ed essere corretti:
# swap grp1 and grp2
stars2 <- stars[, c('E', 'F', 'G', 'H', 'A', 'B', 'C', 'D', 'I', 'J', 'K', 'L')]
# do the calculations again
L2 <- lapply(col_ind, function(cols) rowSums(stars2[, cols]) == 26)
soln2 <- Reduce(`&`, L2)
identical(soln, soln2)
#[1] TRUE
#show that col_ind[1:2] always equal 26:
sapply(L, all)
[1] TRUE TRUE FALSE FALSE FALSE FALSE
Prestazione
Alla fine, abbiamo valutato solo 1,3 milioni delle 479 permutazioni e solo mischiato attraverso 550 MB di RAM. Sono necessari circa 0,7 secondi per l'esecuzione
# A tibble: 1 x 13
expression min median `itr/sec` mem_alloc `gc/sec` n_itr n_gc
<bch:expr> <bch> <bch:> <dbl> <bch:byt> <dbl> <int> <dbl>
1 new_algo 688ms 688ms 1.45 550MB 7.27 1 5

x<- 1:elementse ancora più importanteL1 <- y[,1] + y[,3] + y[,6] + y[,8]. Questo non aiuterebbe davvero il tuo problema di memoria, quindi puoi sempre esaminare rcpp