न्यूनतम निकटतम-पड़ोसी दूरी और अधिकतम घनत्व के साथ 3 डी अंतरिक्ष में नमूना दिए गए बिंदुओं को stochastically
मेरे पास n
एक 3 डी स्थान में अंक हैं। मैं stochastically सभी निकटतम पड़ोसी दूरियों के साथ अंकों का सबसेट नमूना करना चाहता हूं r
। सबसेट m
का आकार अज्ञात है, लेकिन मैं चाहता हूं कि नमूना अंक यथासंभव घने हों।
इसी तरह के सवाल हैं, लेकिन वे सभी दिए गए बिंदुओं से नमूना लेने के बजाय अंक उत्पन्न करने के बारे में हैं।
न्यूनतम निकटतम-पड़ोसी दूरी के साथ 3 डी अंतरिक्ष में यादृच्छिक अंक उत्पन्न करें
उनमें से प्रत्येक के बीच न्यूनतम दूरी के साथ 3-डी यादृच्छिक अंक उत्पन्न करें?
कहो कि मेरे पास 300 यादृच्छिक 3 डी अंक हैं,
import numpy as np
n = 300
points = np.random.uniform(0, 10, size=(n, 3))
अधिकतम करते समय m
न्यूनतम निकटतम-पड़ोसी दूरी के साथ सबसेट प्राप्त करने का सबसे तेज़ तरीका क्या है ?r = 1
m
जवाब
संभवतया एक कुशल बाइसेटरिया सन्निकटन योजना है, लेकिन जब पूर्णांक प्रोग्रामिंग औसतन इतनी जल्दी होती है तो परेशान क्यों होती है?
import numpy as np
n = 300
points = np.random.uniform(0, 10, size=(n, 3))
from ortools.linear_solver import pywraplp
solver = pywraplp.Solver.CreateSolver("SCIP")
variables = [solver.BoolVar("x[{}]".format(i)) for i in range(n)]
solver.Maximize(sum(variables))
for j, q in enumerate(points):
for i, p in enumerate(points[:j]):
if np.linalg.norm(p - q) <= 1:
solver.Add(variables[i] + variables[j] <= 1)
solver.EnableOutput()
solver.Solve()
print(len([i for (i, variable) in enumerate(variables) if variable.SolutionValue()]))
यह एक उपसमुच्चय का बहुत बड़ा हिस्सा नहीं है, लेकिन KDTree
दूरी की गणना का अनुकूलन करने के लिए बहुत लंबा समय नहीं लेते हुए करीब होना चाहिए :
from scipy.spatial import KDTree
import numpy as np
def space_sample(n = 300, low = 0, high = 10, dist = 1):
points = np.random.uniform(low, high, size=(n, 3))
k = KDTree(points)
pairs = np.array(list(k.query_pairs(dist)))
def reduce_pairs(pairs, remove = []): #iteratively remove the most connected node
p = pairs[~np.isin(pairs, remove).any(1)]
if p.size >0:
count = np.bincount(p.flatten(), minlength = n)
r = remove + [count.argmax()]
return reduce_pairs(p, r)
else:
return remove
return np.array([p for i, p in enumerate(points) if not(i in reduce_pairs(pairs))])
subset = space_sample()
Iteratively सबसे जुड़े नोड को हटाना इष्टतम नहीं है (लगभग 300 में से 200 अंक रखता है), लेकिन संभवतः सबसे तेज एल्गोरिथम है जो इष्टतम के करीब है (केवल एक चीज तेजी से यादृच्छिक पर हटा रहा है)। आप संभवतः @njit
reduce_pairs
उस हिस्से को तेजी से बना सकते हैं (यदि मेरे पास बाद में समय होगा तो कोशिश करेंगे)।
30 अंकों के साथ @David Eisenstat के उत्तर का परीक्षण:
from ortools.linear_solver import pywraplp
import numpy as np
def subset_David_Eisenstat(points, r):
solver = pywraplp.Solver.CreateSolver("SCIP")
variables = [solver.BoolVar("x[{}]".format(i)) for i in range(len(points))]
solver.Maximize(sum(variables))
for j, q in enumerate(points):
for i, p in enumerate(points[:j]):
if np.linalg.norm(p - q) <= r:
solver.Add(variables[i] + variables[j] <= 1)
solver.EnableOutput()
solver.Solve()
indices = [i for (i, variable) in enumerate(variables) if variable.SolutionValue()]
return points[indices]
points = np.array(
[[ 7.32837882, 12.12765786, 15.01412241],
[ 8.25164031, 11.14830379, 15.01412241],
[ 8.21790113, 13.05647987, 13.05647987],
[ 7.30031002, 13.08276009, 14.05452502],
[ 9.18056467, 12.0800735 , 13.05183844],
[ 9.17929647, 11.11270337, 14.03027534],
[ 7.64737905, 11.48906945, 15.34274827],
[ 7.01315886, 12.77870699, 14.70301668],
[ 8.88132414, 10.81243313, 14.68685022],
[ 7.60617372, 13.39792166, 13.39792166],
[ 8.85967682, 12.72946394, 12.72946394],
[ 9.50060705, 11.43361294, 13.37866092],
[ 8.21790113, 12.08471494, 14.02824481],
[ 7.32837882, 12.12765786, 16.98587759],
[ 8.25164031, 11.14830379, 16.98587759],
[ 7.30031002, 13.08276009, 17.94547498],
[ 8.21790113, 13.05647987, 18.94352013],
[ 9.17929647, 11.11270337, 17.96972466],
[ 9.18056467, 12.0800735 , 18.94816156],
[ 7.64737905, 11.48906945, 16.65725173],
[ 7.01315886, 12.77870699, 17.29698332],
[ 8.88132414, 10.81243313, 17.31314978],
[ 7.60617372, 13.39792166, 18.60207834],
[ 8.85967682, 12.72946394, 19.27053606],
[ 9.50060705, 11.43361294, 18.62133908],
[ 8.21790113, 12.08471494, 17.97175519],
[ 7.32837882, 15.01412241, 12.12765786],
[ 8.25164031, 15.01412241, 11.14830379],
[ 7.30031002, 14.05452502, 13.08276009],
[ 9.18056467, 13.05183844, 12.0800735 ],])
जब अपेक्षित न्यूनतम दूरी 1 है:
subset1 = subset_David_Eisenstat(points, r=1.)
print(len(subset1))
# Output: 18
न्यूनतम दूरी की जाँच करें:
from scipy.spatial.distance import cdist
dist = cdist(subset1, subset1, metric='euclidean')
# Delete diagonal
res = dist[~np.eye(dist.shape[0],dtype=bool)].reshape(dist.shape[0],-1)
print(np.min(res))
# Output: 1.3285513450926985
अपेक्षित न्यूनतम दूरी 2 में बदलें:
subset2 = subset_David_Eisenstat(points, r=2.)
print(len(subset2))
# Output: 10
न्यूनतम दूरी की जाँच करें:
from scipy.spatial.distance import cdist
dist = cdist(subset2, subset2, metric='euclidean')
# Delete diagonal
res = dist[~np.eye(dist.shape[0],dtype=bool)].reshape(dist.shape[0],-1)
print(np.min(res))
# Output: 2.0612041004376223