न्यूनतम निकटतम-पड़ोसी दूरी और अधिकतम घनत्व के साथ 3 डी अंतरिक्ष में नमूना दिए गए बिंदुओं को stochastically

Jan 10 2021

मेरे पास 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 = 1m

जवाब

2 DavidEisenstat Jan 14 2021 at 08:00

संभवतया एक कुशल बाइसेटरिया सन्निकटन योजना है, लेकिन जब पूर्णांक प्रोग्रामिंग औसतन इतनी जल्दी होती है तो परेशान क्यों होती है?

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()]))
1 DanielF Jan 18 2021 at 16:16

यह एक उपसमुच्चय का बहुत बड़ा हिस्सा नहीं है, लेकिन 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उस हिस्से को तेजी से बना सकते हैं (यदि मेरे पास बाद में समय होगा तो कोशिश करेंगे)।

ShaunHan Jan 19 2021 at 07:07

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