在给定点集中选择最远点的子集 [英] Choosing subset of farthest points in given set of points

本文介绍了在给定点集中选择最远点的子集的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

想象一下,给你3维空间中n个点组成的集合S。任意两点之间的距离是简单的欧几里德距离。您希望从该集合中选择k个点的子集Q,以使它们彼此最远。换言之,不存在k个点的其他子集Q‘,使得Q中所有成对距离的最小值小于Q’中的最小值。

如果n约为1600万,k约为300,我们如何有效地执行此操作?

我的猜测是,这可能是NP难的,所以我们只想关注近似。我能想到的一个想法是使用多维缩放来对一条线上的这些点进行排序,然后使用二进制搜索的版本来获得这条线上距离最远的点。

推荐答案

这称为离散p-色散(Maxmin)问题。

White (1991)Ravi et al. (1994)中证明了最优界,并且Ravi et al. (1994)给出了问题的因子-2近似,后者证明了这个启发式是最好的(除非P=NP)。

因子2近似

因子2近似如下:

Let V be the set of nodes/objects
Let i and j be two nodes at maximum distance
Let p be the number of objects to choose
p = set([i,j])
while size(P)<p:
  Find a node v in V-P such that min_{v' in P} dist(v,v') is maximum
  That is: find the node with the greatest minimum distance to the set P
  P = P.union(v)
Output P

您可以按如下方式在Python中实现:

#!/usr/bin/env python3

import numpy as np

p = 50
N = 400

print("Building distance matrix...")
d = np.random.rand(N,N) #Random matrix
d = (d + d.T)/2         #Make the matrix symmetric

print("Finding initial edge...")
maxdist  = 0
bestpair = ()
for i in range(N):
  for j in range(i+1,N):
    if d[i,j]>maxdist:
      maxdist = d[i,j]
      bestpair = (i,j)

P = set()
P.add(bestpair[0])
P.add(bestpair[1])

print("Finding optimal set...")
while len(P)<p:
  print("P size = {0}".format(len(P)))
  maxdist = 0
  vbest = None
  for v in range(N):
    if v in P:
      continue
    for vprime in P:
      if d[v,vprime]>maxdist:
        maxdist = d[v,vprime]
        vbest   = v
  P.add(vbest)

print(P)

确切解决方案

您也可以将其建模为MIP。对于p=50,n=400的600s以后,最优度差距仍为568%。该近似算法仅需0.47s即可获得100%(或更少)的最优性差距。天真的Gurobi Python表示可能如下所示:

#!/usr/bin/env python
import numpy as np
import gurobipy as grb

p = 50
N = 400

print("Building distance matrix...")
d = np.random.rand(N,N) #Random matrix
d = (d + d.T)/2             #Make the matrix symmetric

m = grb.Model(name="MIP Model")

used  = [m.addVar(vtype=grb.GRB.BINARY) for i in range(N)]

objective = grb.quicksum( d[i,j]*used[i]*used[j] for i in range(0,N) for j in range(i+1,N) )

m.addConstr(
  lhs=grb.quicksum(used),
  sense=grb.GRB.EQUAL,
  rhs=p
)

# for maximization
m.ModelSense = grb.GRB.MAXIMIZE
m.setObjective(objective)

# m.Params.TimeLimit = 3*60

# solving with Glpk
ret = m.optimize()

缩放

显然,初始点的O(N^2)比例是不好的。通过认识到配对必须位于数据集的凸壳上,我们可以更有效地找到它们。这为我们提供了一种O(N Log N)查找配对的方法。一旦我们找到它,我们就像以前一样继续(使用SciPy进行加速)。

缩放的最佳方法是使用R*-树有效地找到候选点p和集合P之间的最小距离。但这在Python中无法有效完成,因为仍涉及for循环。

import numpy as np
from scipy.spatial import ConvexHull
from scipy.spatial.distance import cdist

p = 300
N = 16000000

# Find a convex hull in O(N log N)
points = np.random.rand(N, 3)   # N random points in 3-D

# Returned 420 points in testing
hull = ConvexHull(points)

# Extract the points forming the hull
hullpoints = points[hull.vertices,:]

# Naive way of finding the best pair in O(H^2) time if H is number of points on
# hull
hdist = cdist(hullpoints, hullpoints, metric='euclidean')

# Get the farthest apart points
bestpair = np.unravel_index(hdist.argmax(), hdist.shape)

P = np.array([hullpoints[bestpair[0]],hullpoints[bestpair[1]]])

# Now we have a problem
print("Finding optimal set...")
while len(P)<p:
  print("P size = {0}".format(len(P)))
  distance_to_P        = cdist(points, P)
  minimum_to_each_of_P = np.min(distance_to_P, axis=1)
  best_new_point_idx   = np.argmax(minimum_to_each_of_P)
  best_new_point = np.expand_dims(points[best_new_point_idx,:],0)
  P = np.append(P,best_new_point,axis=0)

print(P)

这篇关于在给定点集中选择最远点的子集的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆