कोई भी सही मायने में सामान्य-उद्देश्य प्रभावी पद्धति आकृतियों के अभ्यावेदन को मानकीकृत करेगी ताकि वे आंतरिक प्रतिनिधित्व में रोटेशन, अनुवाद, प्रतिबिंब, या तुच्छ परिवर्तन पर नहीं बदलेंगे।
इसका एक तरीका यह है कि प्रत्येक जुड़े हुए आकार को एक छोर से शुरू करते हुए, किनारे की लंबाई और (हस्ताक्षरित) कोणों के एक वैकल्पिक अनुक्रम के रूप में सूचीबद्ध किया जाए। (कोई शून्य-लंबाई वाले किनारे या सीधे कोण होने के अर्थ में आकार "साफ" होना चाहिए।) इस अदर्शन को प्रतिबिंब के तहत बनाने के लिए, सभी कोणों को नकारात्मक करें यदि पहला गैर-शून्य एक नकारात्मक है।
(के किसी भी कनेक्ट किए पॉलीलाइन क्योंकि n कोने होगा एन -1 किनारों से अलग कर दिया एन -2 कोण, मैं इसे में सुविधाजनक पाया है R
कोड के नीचे दो सरणियों, किनारे लंबाई के लिए एक से मिलकर एक डेटा संरचना का उपयोग करने $lengths
और अन्य के लिए कोण, $angles
एक पंक्ति खंड में कोई कोण नहीं होगा, इसलिए ऐसी डेटा संरचना में शून्य-लंबाई सरणियों को संभालना महत्वपूर्ण है।)
इस तरह के प्रतिनिधित्व को शाब्दिक रूप से आदेश दिया जा सकता है। मानकीकरण प्रक्रिया के दौरान संचित फ्लोटिंग-पॉइंट त्रुटियों के लिए कुछ भत्ता बनाया जाना चाहिए। एक सुरुचिपूर्ण प्रक्रिया मूल निर्देशांक के कार्य के रूप में उन त्रुटियों का अनुमान लगाती है। नीचे दिए गए समाधान में, एक सरल विधि का उपयोग किया जाता है जिसमें दो लंबाई को समान माना जाता है जब वे एक रिश्तेदार आधार पर बहुत कम राशि से भिन्न होते हैं। कोण निरपेक्ष आधार पर केवल बहुत कम राशि से भिन्न हो सकते हैं।
अंतर्निहित अभिविन्यास के उत्क्रमण के तहत उन्हें अपरिवर्तनीय बनाने के लिए, पॉलिऑनोग्राफिक रूप से सबसे शुरुआती प्रतिनिधित्व को पॉलीलाइन और उसके उत्क्रमण के बीच चुनें।
बहु-भाग पॉलीइलाइन को संभालने के लिए, उनके घटकों को लेक्सिकोग्राफ़िक क्रम में व्यवस्थित करें।
यूक्लिडियन परिवर्तनों के तहत समतुल्यता वर्गों को खोजने के लिए ,
आकृतियों के मानकीकृत अभ्यावेदन बनाएँ।
मानकीकृत अभ्यावेदन का एक लेक्सोग्राफिक प्रकार करें।
समान अभ्यावेदन के अनुक्रमों की पहचान करने के लिए क्रमबद्ध क्रम से गुजरें।
अभिकलन समय O (n * log (n) * N) के समानुपाती होता है जहाँ n सुविधाओं की संख्या होती है और N किसी भी विशेषता में सबसे बड़ी संख्या है। यह कुशल है।
संभवतः यह पारित करने के लायक है कि उस केंद्र के बारे में पॉलीलाइन लंबाई, केंद्र और क्षणों जैसे आसानी से गणना किए गए अपरिवर्तनीय ज्यामितीय गुणों के आधार पर एक प्रारंभिक समूह , अक्सर पूरी प्रक्रिया को कारगर बनाने के लिए लागू किया जा सकता है। प्रत्येक को ऐसे प्रत्येक प्रारंभिक समूह के भीतर बधाई सुविधाओं के उपसमूहों को खोजने की आवश्यकता है। यहां दी गई पूरी विधि को आकृतियों के लिए आवश्यक होगा जो अन्यथा इतनी उल्लेखनीय रूप से समान होगी कि ऐसे सरल आक्रमणकारी अभी भी उन्हें अलग नहीं करेंगे। उदाहरण के लिए, रेखापुंज डेटा से निर्मित सरल विशेषताओं में ऐसी विशेषताएं हो सकती हैं। हालाँकि, यहाँ दिए गए समाधान वैसे भी इतने कुशल हैं, कि यदि कोई इसे लागू करने के प्रयास में जाने वाला है, तो यह अपने आप ही ठीक काम कर सकता है।
उदाहरण
बाएं हाथ का आंकड़ा पांच पॉलीलाइन प्लस 15 से अधिक दिखाता है जो कि यादृच्छिक अनुवाद, रोटेशन, प्रतिबिंब और आंतरिक अभिविन्यास (जो दिखाई नहीं देता है) के उत्क्रमण के माध्यम से प्राप्त किया गया था। दाएं हाथ के आंकड़े उन्हें उनके यूक्लिडियन तुल्यता वर्ग के अनुसार रंग देते हैं: एक सामान्य रंग के सभी आंकड़े बधाई हैं; अलग-अलग रंग बधाई नहीं हैं।
R
कोड इस प्रकार है। जब इनपुट्स को 500 आकृतियों, 500 अतिरिक्त (सर्वांगसम) आकृतियों में अद्यतन किया गया, तो प्रति आकृति 100 चक्कर के साथ, इस मशीन पर निष्पादन का समय 3 सेकंड था।
यह कोड अधूरा है: क्योंकि R
इसमें मूल लेक्सोग्राफिक सॉर्ट नहीं है, और मुझे खरोंच से एक कोडिंग की तरह महसूस नहीं हुआ था, मैं बस प्रत्येक मानकीकृत आकार के पहले समन्वय पर छँटाई करता हूं। यहां बनाई गई यादृच्छिक आकृतियों के लिए यह ठीक होगा, लेकिन उत्पादन कार्य के लिए एक पूर्ण लेक्सिकोग्राफिक प्रकार लागू किया जाना चाहिए। इस परिवर्तन से कार्य order.shape
प्रभावित होगा। इसका इनपुट मानकीकृत आकार की एक सूची है s
और इसका आउटपुट अनुक्रमित अनुक्रम है s
जो इसमें क्रमबद्ध होगा।
#
# Create random shapes.
#
n.shapes <- 5 # Unique shapes, up to congruence
n.shapes.new <- 15 # Additional congruent shapes to generate
p.mean <- 5 # Expected number of vertices per shape
set.seed(17) # Create a reproducible starting point
shape.random <- function(n) matrix(rnorm(2*n), nrow=2, ncol=n)
shapes <- lapply(2+rpois(n.shapes, p.mean-2), shape.random)
#
# Randomly move them around.
#
move.random <- function(xy) {
a <- runif(1, 0, 2*pi)
reflection <- sign(runif(1, -1, 1))
translation <- runif(2, -8, 8)
m <- matrix(c(cos(a), sin(a), -sin(a), cos(a)), 2, 2) %*%
matrix(c(reflection, 0, 0, 1), 2, 2)
m <- m %*% xy + translation
if (runif(1, -1, 0) < 0) m <- m[ ,dim(m)[2]:1]
return (m)
}
i <- sample(length(shapes), n.shapes.new, replace=TRUE)
shapes <- c(shapes, lapply(i, function(j) move.random(shapes[[j]])))
#
# Plot the shapes.
#
range.shapes <- c(min(sapply(shapes, min)), max(sapply(shapes, max)))
palette(gray.colors(length(shapes)))
par(mfrow=c(1,2))
plot(range.shapes, range.shapes, type="n",asp=1, bty="n", xlab="", ylab="")
invisible(lapply(1:length(shapes), function(i) lines(t(shapes[[i]]), col=i, lwd=2)))
#
# Standardize the shape description.
#
standardize <- function(xy) {
n <- dim(xy)[2]
vectors <- xy[ ,-1, drop=FALSE] - xy[ ,-n, drop=FALSE]
lengths <- sqrt(colSums(vectors^2))
if (which.min(lengths - rev(lengths))*2 < n) {
lengths <- rev(lengths)
vectors <- vectors[, (n-1):1]
}
if (n > 2) {
vectors <- vectors / rbind(lengths, lengths)
perps <- rbind(-vectors[2, ], vectors[1, ])
angles <- sapply(1:(n-2), function(i) {
cosine <- sum(vectors[, i+1] * vectors[, i])
sine <- sum(perps[, i+1] * vectors[, i])
atan2(sine, cosine)
})
i <- min(which(angles != 0))
angles <- sign(angles[i]) * angles
} else angles <- numeric(0)
list(lengths=lengths, angles=angles)
}
shapes.std <- lapply(shapes, standardize)
#
# Sort lexicographically. (Not implemented: see the text.)
#
order.shape <- function(s) {
order(sapply(s, function(s) s$lengths[1]))
}
i <- order.shape(shapes.std)
#
# Group.
#
equal.shape <- function(s.0, s.1) {
same.length <- function(a,b) abs(a-b) <= (a+b) * 1e-8
same.angle <- function(a,b) min(abs(a-b), abs(a-b)-2*pi) < 1e-11
r <- function(u) {
a <- u$angles
if (length(a) > 0) {
a <- rev(u$angles)
i <- min(which(a != 0))
a <- sign(a[i]) * a
}
list(lengths=rev(u$lengths), angles=a)
}
e <- function(u, v) {
if (length(u$lengths) != length(v$lengths)) return (FALSE)
all(mapply(same.length, u$lengths, v$lengths)) &&
all(mapply(same.angle, u$angles, v$angles))
}
e(s.0, s.1) || e(r(s.0), s.1)
}
g <- rep(1, length(shapes.std))
for (j in 2:length(i)) {
i.0 <- i[j-1]
i.1 <- i[j]
if (equal.shape(shapes.std[[i.0]], shapes.std[[i.1]]))
g[j] <- g[j-1] else g[j] <- g[j-1]+1
}
palette(rainbow(max(g)))
plot(range.shapes, range.shapes, type="n",asp=1, bty="n", xlab="", ylab="")
invisible(lapply(1:length(i), function(j) lines(t(shapes[[i[j]]]), col=g[j], lwd=2)))