Für Permutationen ist rcppalgos großartig. Leider gibt es 479 Millionen Möglichkeiten mit 12 Feldern, was bedeutet, dass die meisten Menschen zu viel Speicherplatz beanspruchen:
library(RcppAlgos)
elements <- 12
permuteGeneral(elements, elements)
#> Error: cannot allocate vector of size 21.4 Gb
Es gibt einige Alternativen.
Nehmen Sie eine Probe der Permutationen. Das heißt, nur 1 Million statt 479 Millionen. Dazu können Sie verwenden permuteSample(12, 12, n = 1e6)
. Siehe @ JosephWoods Antwort für einen etwas ähnlichen Ansatz, außer dass er 479 Millionen Permutationen abtastet;)
Erstellen Sie eine Schleife in rcpp , um die Permutation bei der Erstellung auszuwerten. Dies spart Speicher, da Sie am Ende die Funktion erstellen würden, um nur die richtigen Ergebnisse zurückzugeben.
Gehen Sie das Problem mit einem anderen Algorithmus an. Ich werde mich auf diese Option konzentrieren.
Neuer Algorithmus mit Einschränkungen
Segmente sollten 26 sein
Wir wissen, dass jedes Liniensegment im obigen Stern bis zu 26 addieren muss. Wir können diese Einschränkung zur Erzeugung unserer Permutationen hinzufügen - geben Sie nur Kombinationen an, die bis zu 26 addieren:
# only certain combinations will add to 26
lucky_combo <- comboGeneral(12, 4, comparisonFun = '==', constraintFun = 'sum', limitConstraints = 26L)
ABCD und EFGH Gruppen
Im obigen Stern habe ich drei Gruppen unterschiedlich gefärbt: ABCD , EFGH und IJLK . Die ersten beiden Gruppen haben ebenfalls keine gemeinsamen Punkte und sind auch auf interessierenden Liniensegmenten. Daher können wir eine weitere Einschränkung hinzufügen: Für Kombinationen, die sich zu 26 addieren, müssen wir sicherstellen, dass ABCD und EFGH keine Zahlenüberlappung aufweisen. IJLK werden die restlichen 4 Nummern zugewiesen.
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)))
Permute durch die Gruppen
Wir müssen alle Permutationen jeder Gruppe finden. Das heißt, wir haben nur Kombinationen, die sich zu 26 addieren. Zum Beispiel müssen wir nehmen 1, 2, 11, 12
und machen 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]
Endgültige Berechnungen
Der letzte Schritt ist die Mathematik. Ich benutze lapply()
und Reduce()
hier, um mehr funktionale Programmierung zu machen - sonst würde viel Code sechsmal eingegeben. In der ursprünglichen Lösung finden Sie eine ausführlichere Erläuterung des mathematischen Codes.
# 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
Swapping ABCD und EFGH
Am Ende des obigen Codes habe ich den Vorteil genutzt, dass wir tauschen ABCD
und EFGH
die verbleibenden Permutationen erhalten können. Hier ist der Code, um zu bestätigen, dass wir die beiden Gruppen austauschen und korrekt sein können:
# 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
Performance
Am Ende haben wir nur 1,3 Millionen der 479 Permutationen ausgewertet und nur 550 MB RAM gemischt. Die Ausführung dauert ca. 0,7 Sekunden
# 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:elements
und was noch wichtiger istL1 <- y[,1] + y[,3] + y[,6] + y[,8]
. Dies würde Ihrem Speicherproblem nicht wirklich helfen, so dass Sie immer in rcpp