प्रश्न की कई मान्य व्याख्याएँ हैं। टिप्पणी - विशेष रूप से 15 या अधिक तत्वों के क्रमांकन का संकेत देने वाले एक की आवश्यकता है (15! = 1307674368000 बड़ा हो रहा है) - सुझाव दें कि जो चाहता था वह अपेक्षाकृत छोटा यादृच्छिक नमूना है, प्रतिस्थापन के बिना, सभी n! = n * (n-1) (n-2) ... * 2 * 1 1: n के क्रमपरिवर्तन। यदि यह सच है, तो कुछ हद तक कुशल समाधान मौजूद हैं।
निम्न फ़ंक्शन, rperm
दो तर्कों n
(नमूने m
के क्रमपरिवर्तन का आकार ) और (आकार n के क्रमपरिवर्तन की संख्या ) को स्वीकार करता है । यदि m निकट या n से अधिक है, तो फ़ंक्शन को लंबा समय लगेगा और कई NA मान लौटाएंगे: यह उपयोग के लिए अभिप्रेत है जब n अपेक्षाकृत बड़ा हो (कहते हैं, 8 या अधिक) और m n से बहुत छोटा है! यह अब तक पाए गए क्रमपरिवर्तन के एक स्ट्रिंग प्रतिनिधित्व को कैशिंग करके काम करता है और तब तक नए क्रमपरिवर्तन (यादृच्छिक रूप से) उत्पन्न करता है जब तक कि एक नया नहीं मिलता है। यह R की साहचर्य सूची-अनुक्रमण क्षमता का शोषण करता है जो पहले से पाए गए क्रमपरिवर्तन की सूची को जल्दी से खोज लेता है।
rperm <- function(m, size=2) { # Obtain m unique permutations of 1:size
# Function to obtain a new permutation.
newperm <- function() {
count <- 0 # Protects against infinite loops
repeat {
# Generate a permutation and check against previous ones.
p <- sample(1:size)
hash.p <- paste(p, collapse="")
if (is.null(cache[[hash.p]])) break
# Prepare to try again.
count <- count+1
if (count > 1000) { # 1000 is arbitrary; adjust to taste
p <- NA # NA indicates a new permutation wasn't found
hash.p <- ""
break
}
}
cache[[hash.p]] <<- TRUE # Update the list of permutations found
p # Return this (new) permutation
}
# Obtain m unique permutations.
cache <- list()
replicate(m, newperm())
} # Returns a `size` by `m` matrix; each column is a permutation of 1:size.
कॉलम वैक्टर के replicate
रूप में क्रमपरिवर्तन को वापस करने की प्रकृति है ; उदाहरण के लिए , निम्नलिखित मूल प्रश्न में एक उदाहरण प्रस्तुत करता है, ट्रांसपोज़्ड :
> set.seed(17)
> rperm(6, size=4)
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 2 4 4 3 4
[2,] 3 4 1 3 1 2
[3,] 4 1 3 2 2 3
[4,] 2 3 2 1 4 1
टाइमिंग छोटे से मध्यम मूल्यों के लिए उत्कृष्ट हैं, लगभग 10,000 तक, लेकिन बड़ी समस्याओं के लिए नीचा दिखाते हैं। उदाहरण के लिए, n = 1000 तत्वों (10 मिलियन मानों का एक मैट्रिक्स) के m = 10,000 क्रमोन्नति का एक नमूना 10 सेकंड में प्राप्त किया गया था; n = 20 तत्वों के m = 20,000 क्रमोन्नति का एक नमूना 11 सेकंड के लिए आवश्यक था, भले ही आउटपुट (400,000 प्रविष्टियों का एक मैट्रिक्स) बहुत छोटा था; और n = 20 तत्वों के m = 100,000 क्रमांकन का नमूना नमूना 260 सेकंड के बाद निरस्त कर दिया गया (मेरे पास पूरा होने की प्रतीक्षा करने का धैर्य नहीं था)। यह स्केलिंग समस्या R के साहचर्य संबोधन में स्केलिंग अक्षमताओं से संबंधित प्रतीत होती है। 1000 या तो के समूहों में नमूने उत्पन्न करके, उसके चारों ओर काम कर सकता है, फिर उन नमूनों को एक बड़े नमूने में जोड़कर और डुप्लिकेट को हटा सकता है।
संपादित करें
हम कैश को दो कैश के पदानुक्रम में तोड़कर रैखिक असममित प्रदर्शन के पास प्राप्त कर सकते हैं , ताकि आर को एक बड़ी सूची के माध्यम से कभी भी खोज न करना पड़े। वैचारिक रूप से (हालांकि इसे लागू नहीं किया गया है), क्रमचय के पहले तत्वों द्वारा अनुक्रमित एक सरणी बनाएं । इस सरणी में प्रविष्टियाँ उन सभी तत्वों को साझा करने वाले सभी क्रमपरिवर्तन की सूची हैं। यह जांचने के लिए कि क्या एक क्रमचय देखा गया है, कैश में अपनी प्रविष्टि को खोजने के लिए उसके पहले तत्वों का उपयोग करें और फिर उस प्रविष्टि के भीतर उस क्रमचय की खोज करें। हम सभी सूचियों के अपेक्षित आकार को संतुलित करने के लिए को चुन सकते हैं । वास्तविक कार्यान्वयन का उपयोग नहीं करता हैk k k kककककक-फोल्ड सरणी, जो पर्याप्त सामान्यता में प्रोग्राम करना मुश्किल होगा, लेकिन इसके बजाय एक अन्य सूची का उपयोग करता है।
यहां कुछ समय के लिए क्रमपरिवर्तन आकारों और अनुरोधित अलग-अलग परमिटों की संख्या के लिए कुछ बीता हुआ समय है:
Number Size=10 Size=15 Size=1000 size=10000 size=100000
10 0.00 0.00 0.02 0.08 1.03
100 0.01 0.01 0.07 0.64 8.36
1000 0.08 0.09 0.68 6.38
10000 0.83 0.87 7.04 65.74
100000 11.77 10.51 69.33
1000000 195.5 125.5
(आकार = 10 से आकार = 15 तक स्पष्ट रूप से विषम गति इसलिए है क्योंकि कैश का पहला स्तर आकार = 15 के लिए बड़ा है, दूसरे स्तर की सूचियों में प्रविष्टियों की औसत संख्या को कम करता है, जिससे आर की साहचर्य खोज को गति मिलती है। रैम में लागत, निष्पादन को ऊपरी स्तर के कैश आकार को बढ़ाकर तेजी से बनाया जा सकता है। बस k.head
1 से बढ़ रहा है (जो ऊपरी स्तर के आकार को 10 से गुणा करता है) rperm(100000, size=10)
उदाहरण के लिए 11.77 सेकंड से 8.72 सेकंड तक फैला है, जो ऊपरी स्तर का बना रहा है। कैश 10 गुना बड़ा है, फिर भी कोई सराहनीय लाभ नहीं हुआ, 8.51 सेकंड में देखा।)
10 तत्वों के 1,000,000 अद्वितीय क्रमपरिवर्तन के मामले को छोड़कर (सभी 10 का पर्याप्त हिस्सा! = 3.63 मिलियन ऐसे क्रमपरिवर्तन के बारे में), व्यावहारिक रूप से कभी टकराव का पता नहीं चला। इस असाधारण मामले में, 169,301 टकराव हुए, लेकिन पूरी तरह से असफलताएं (एक मिलियन अद्वितीय क्रमपरिवर्तन वास्तव में प्राप्त हुए थे)।
ध्यान दें कि बड़े क्रमचय आकार (20 या अधिक से अधिक) के साथ, एक नमूने में भी दो समान क्रमपरिवर्तन प्राप्त करने की संभावना है, जितना कि 1,000,000,000 बड़े पैमाने पर छोटा है। इस प्रकार, यह समाधान उन स्थितियों में मुख्य रूप से लागू होता है जहां (ए) ( और बीच (बी) के अनूठे क्रमपरिवर्तन की बड़ी संख्या उत्पन्न होती है, लेकिन फिर भी, (सी) सभी तुलना में काफी कम हैक्रमपरिवर्तन की आवश्यकता है।n = 15 n !n = 5n = 15n !
वर्किंग कोड इस प्रकार है।
rperm <- function(m, size=2) { # Obtain m unique permutations of 1:size
max.failures <- 10
# Function to index into the upper-level cache.
prefix <- function(p, k) { # p is a permutation, k is the prefix size
sum((p[1:k] - 1) * (size ^ ((1:k)-1))) + 1
} # Returns a value from 1 through size^k
# Function to obtain a new permutation.
newperm <- function() {
# References cache, k.head, and failures in parent context.
# Modifies cache and failures.
count <- 0 # Protects against infinite loops
repeat {
# Generate a permutation and check against previous ones.
p <- sample(1:size)
k <- prefix(p, k.head)
ip <- cache[[k]]
hash.p <- paste(tail(p,-k.head), collapse="")
if (is.null(ip[[hash.p]])) break
# Prepare to try again.
n.failures <<- n.failures + 1
count <- count+1
if (count > max.failures) {
p <- NA # NA indicates a new permutation wasn't found
hash.p <- ""
break
}
}
if (count <= max.failures) {
ip[[hash.p]] <- TRUE # Update the list of permutations found
cache[[k]] <<- ip
}
p # Return this (new) permutation
}
# Initialize the cache.
k.head <- min(size-1, max(1, floor(log(m / log(m)) / log(size))))
cache <- as.list(1:(size^k.head))
for (i in 1:(size^k.head)) cache[[i]] <- list()
# Count failures (for benchmarking and error checking).
n.failures <- 0
# Obtain (up to) m unique permutations.
s <- replicate(m, newperm())
s[is.na(s)] <- NULL
list(failures=n.failures, sample=matrix(unlist(s), ncol=size))
} # Returns an m by size matrix; each row is a permutation of 1:size.