मैं एक ऐसा R
समाधान पेश करूँगा, जो R
यह बताने के लिए थोड़ा गैर- तरीके से कोडित हो कि यह अन्य प्लेटफार्मों पर कैसे संपर्क किया जा सकता है।
R
(साथ ही कुछ अन्य प्लेटफार्मों, विशेष रूप से जो एक कार्यात्मक प्रोग्रामिंग शैली का पक्ष लेते हैं) में चिंता यह है कि लगातार बड़े सरणी को अपडेट करना बहुत महंगा हो सकता है। इसके बजाय, फिर, यह एल्गोरिथ्म अपनी निजी डेटा संरचना को बनाए रखता है जिसमें (ए) अब तक भरी गई सभी कोशिकाओं को सूचीबद्ध किया गया है और (बी) उन सभी कोशिकाओं को चुना जाएगा जो चुने जाने के लिए उपलब्ध हैं (भरी हुई कोशिकाओं की परिधि के आसपास) सूचीबद्ध हैं। यद्यपि इस डेटा संरचना में हेरफेर करना किसी सरणी में सीधे अनुक्रमण की तुलना में कम कुशल है, संशोधित डेटा को एक छोटे आकार में रखकर, यह संभवतः कम गणना समय लेगा। ( R
या तो इसके लिए अनुकूलन का कोई प्रयास नहीं किया गया है , राज्य के पूर्व-डॉक्टरों को कुछ निष्पादन समय बचाने के लिए आवंटित करना चाहिए, यदि आप भीतर काम करना पसंद करते हैं R
।)
कोड टिप्पणी की है और पढ़ने के लिए सीधा होना चाहिए। एल्गोरिथ्म को यथासंभव पूरा करने के लिए, यह परिणाम को प्लॉट करने के लिए अंत को छोड़कर किसी भी ऐड-ऑन का उपयोग नहीं करता है। केवल मुश्किल हिस्सा यह है कि दक्षता और सादगी के लिए यह 1 डी इंडेक्स का उपयोग करके 2 डी ग्रिड में इंडेक्स करना पसंद करता है। रूपांतरण neighbors
फ़ंक्शन में होता है , जिसे 2 डी इंडेक्सिंग की आवश्यकता होती है ताकि यह पता लगाया जा सके कि सेल के सुलभ पड़ोसी क्या हो सकते हैं और फिर उन्हें 1 डी इंडेक्स में परिवर्तित कर देता है। यह रूपांतरण मानक है, इसलिए मैं इस पर आगे टिप्पणी नहीं करूंगा, सिवाय इसके कि अन्य जीआईएस प्लेटफार्मों में आप कॉलम और पंक्ति इंडेक्स की भूमिकाओं को उलटना चाह सकते हैं। ( R
स्तंभ अनुक्रमणिका करने से पहले पंक्ति अनुक्रमणिका में परिवर्तन होता है।)
वर्णन करने के लिए, यह कोड x
भूमि का प्रतिनिधित्व करने वाला ग्रिड और दुर्गम बिंदुओं की एक नदी जैसी सुविधा लेता है, उस ग्रिड में एक विशिष्ट स्थान (5, 21) पर शुरू होता है (नदी के निचले मोड़ के पास) और 250 बिंदुओं को कवर करने के लिए इसे यादृच्छिक रूप से विस्तारित करता है। । कुल समय 0.03 सेकंड है। (जब सरणी का आकार 10,000 से 3000 पंक्तियों के कारक 5000 स्तंभों से बढ़ा दिया जाता है, तो समय केवल 0.09 सेकंड तक चला जाता है - केवल 3 या तो का एक कारक - इस एल्गोरिथ्म की मापनीयता का प्रदर्शन।) इसके बजाय। बस 0, 1, और 2 के ग्रिड को आउटपुट करना, यह उस अनुक्रम को आउटपुट करता है जिसके साथ नई कोशिकाओं को आवंटित किया गया था। आंकड़े पर सबसे पहले कोशिकाएं हरे रंग की हैं, जो सुनारों के माध्यम से सामन रंगों में स्नातक हैं।
यह स्पष्ट होना चाहिए कि प्रत्येक कोशिका के आठ-बिंदु पड़ोस का उपयोग किया जा रहा है। अन्य पड़ोस के लिए, बस nbrhood
मूल्य को संशोधित करें expand
: यह किसी भी दिए गए सेल के सापेक्ष सूचकांक ऑफसेट की एक सूची है। उदाहरण के लिए, "D4" पड़ोस को निर्दिष्ट किया जा सकता है matrix(c(-1,0, 1,0, 0,-1, 0,1), nrow=2)
।
यह भी स्पष्ट है कि फैलने के इस तरीके की अपनी समस्याएं हैं: यह पीछे छेद छोड़ देता है। यदि वह नहीं है जो इरादा था, तो इस समस्या को ठीक करने के विभिन्न तरीके हैं। उदाहरण के लिए, उपलब्ध कोशिकाओं को एक कतार में रखें ताकि सबसे पहले पाए जाने वाले सेल भी जल्द से जल्द भरे जाएं। कुछ रैंडमाइजेशन अभी भी लागू किया जा सकता है, लेकिन उपलब्ध कोशिकाओं को अब समान (समान) संभावनाओं के साथ नहीं चुना जाएगा। एक और, अधिक जटिल तरीका, संभावनाओं के साथ उपलब्ध कोशिकाओं का चयन करना होगा जो इस बात पर निर्भर करते हैं कि उनके पास कितने भरे हुए पड़ोसी हैं। एक बार एक सेल घेर लिया जाता है, तो आप इसके चयन की संभावना को इतना अधिक कर सकते हैं कि कुछ छेद अधूरा रह जाएगा।
मैं यह टिप्पणी करके समाप्त करूंगा कि यह काफी सेल्युलर ऑटोमेटन (सीए) नहीं है, जो सेल द्वारा सेल आगे नहीं बढ़ाएगा, बल्कि प्रत्येक पीढ़ी में कोशिकाओं के पूरे स्वेट को अपडेट करेगा। अंतर सूक्ष्म है: सीए के साथ, कोशिकाओं के लिए चयन संभावनाएं समान नहीं होंगी।
#
# Expand a patch randomly within indicator array `x` (1=unoccupied) by
# `n.size` cells beginning at index `start`.
#
expand <- function(x, n.size, start) {
if (x[start] != 1) stop("Attempting to begin on an unoccupied cell")
n.rows <- dim(x)[1]
n.cols <- dim(x)[2]
nbrhood <- matrix(c(-1,-1, -1,0, -1,1, 0,-1, 0,1, 1,-1, 1,0, 1,1), nrow=2)
#
# Adjoin one more random cell and update `state`, which records
# (1) the immediately available cells and (2) already occupied cells.
#
grow <- function(state) {
#
# Find all available neighbors that lie within the extent of `x` and
# are unoccupied.
#
neighbors <- function(i) {
n <- c((i-1)%%n.rows+1, floor((i-1)/n.rows+1)) + nbrhood
n <- n[, n[1,] >= 1 & n[2,] >= 1 & n[1,] <= n.rows & n[2,] <= n.cols,
drop=FALSE] # Remain inside the extent of `x`.
n <- n[1,] + (n[2,]-1)*n.rows # Convert to *vector* indexes into `x`.
n <- n[x[n]==1] # Stick to valid cells in `x`.
n <- setdiff(n, state$occupied)# Remove any occupied cells.
return (n)
}
#
# Select one available cell uniformly at random.
# Return an updated state.
#
j <- ceiling(runif(1) * length(state$available))
i <- state$available[j]
return(list(index=i,
available = union(state$available[-j], neighbors(i)),
occupied = c(state$occupied, i)))
}
#
# Initialize the state.
# (If `start` is missing, choose a value at random.)
#
if(missing(start)) {
indexes <- 1:(n.rows * n.cols)
indexes <- indexes[x[indexes]==1]
start <- sample(indexes, 1)
}
if(length(start)==2) start <- start[1] + (start[2]-1)*n.rows
state <- list(available=start, occupied=c())
#
# Grow for as long as possible and as long as needed.
#
i <- 1
indices <- c(NA, n.size)
while(length(state$available) > 0 && i <= n.size) {
state <- grow(state)
indices[i] <- state$index
i <- i+1
}
#
# Return a grid of generation numbers from 1, 2, ... through n.size.
#
indices <- indices[!is.na(indices)]
y <- matrix(NA, n.rows, n.cols)
y[indices] <- 1:length(indices)
return(y)
}
#
# Create an interesting grid `x`.
#
n.rows <- 3000
n.cols <- 5000
x <- matrix(1, n.rows, n.cols)
ij <- sapply(1:n.cols, function(i)
c(ceiling(n.rows * 0.5 * (1 + exp(-0.5*i/n.cols) * sin(8*i/n.cols))), i))
x[t(ij)] <- 0; x[t(ij - c(1,0))] <- 0; x[t(ij + c(1,0))] <- 0
#
# Expand around a specified location in a random but reproducible way.
#
set.seed(17)
system.time(y <- expand(x, 250, matrix(c(5, 21), 1)))
#
# Plot `y` over `x`.
#
library(raster)
plot(raster(x[n.rows:1,], xmx=n.cols, ymx=n.rows), col=c("#2020a0", "#f0f0f0"))
plot(raster(y[n.rows:1,] , xmx=n.cols, ymx=n.rows),
col=terrain.colors(255), alpha=.8, add=TRUE)
थोड़े संशोधनों के साथ हम expand
कई क्लस्टर बनाने के लिए लूप कर सकते हैं। एक पहचानकर्ता द्वारा समूहों को अलग करना उचित है, जो यहां 2, 3, ... आदि चलाएगा।
पहले, एक त्रुटि और (बी) के बजाय एक मैट्रिक्स में मान होने पर पहली पंक्ति में expand
वापसी (ए) NA
में बदलें । ( प्रत्येक कॉल के साथ एक नया मैट्रिक्स बनाने में समय बर्बाद न करें।) किए गए इस बदलाव के साथ, लूपिंग आसान है: एक यादृच्छिक शुरुआत चुनें, इसके चारों ओर विस्तार करने का प्रयास करें, यदि सफल रहे, तो क्लस्टर इंडेक्स को संचित करें और जब तक दोहराएं। लूप का एक महत्वपूर्ण हिस्सा कई पुनरावृत्तियों को प्राप्त नहीं होने की स्थिति में पुनरावृत्तियों की संख्या को सीमित करना है: इसके साथ ऐसा किया जाता है ।indices
y
y
indices
count.max
यहां एक उदाहरण दिया गया है जहां 60 क्लस्टर केंद्रों को समान रूप से यादृच्छिक पर चुना जाता है।
size.clusters <- 250
n.clusters <- 60
count.max <- 200
set.seed(17)
system.time({
n <- n.rows * n.cols
cells.left <- 1:n
cells.left[x!=1] <- -1 # Indicates occupancy of cells
i <- 0
indices <- c()
ids <- c()
while(i < n.clusters && length(cells.left) >= size.clusters && count.max > 0) {
count.max <- count.max-1
xy <- sample(cells.left[cells.left > 0], 1)
cluster <- expand(x, size.clusters, xy)
if (!is.na(cluster[1]) && length(cluster)==size.clusters) {
i <- i+1
ids <- c(ids, rep(i, size.clusters))
indices <- c(indices, cluster)
cells.left[indices] <- -1
}
}
y <- matrix(NA, n.rows, n.cols)
y[indices] <- ids
})
cat(paste(i, "cluster(s) created.", sep=" "))
यहां 500 ग्रिड द्वारा 310 पर लागू होने पर परिणाम (क्लस्टर्स के लिए पर्याप्त रूप से छोटा और मोटे होना) स्पष्ट है। इसे निष्पादित करने में दो सेकंड लगते हैं; 5000 ग्रिड (100 गुना बड़ा) पर 3100 से अधिक समय (24 सेकंड) लगता है, लेकिन समय काफी अच्छी तरह से बढ़ रहा है। (अन्य प्लेटफार्मों पर, जैसे कि C ++, समय को शायद ही ग्रिड आकार पर निर्भर होना चाहिए।)