Source code for algorithms.search.closest_pair

"""
The closest pair of points problem or closest pair problem is a problem of computational geometry:
given n points in metric space, find a pair of points with the smallest distance between them.
The closest pair problem for points in the Euclidean plane[1] was among the first geometric problems that
were treated at the origins of the systematic study of the computational complexity of geometric algorithms. [Wikipedia]
"""

import math


def _distance(point1, point2):
    """
    Function for calculation distance between 2 points

    Args:
        point1: first point with coordinates as tuple (x, y)
        point2: first point with coordinates as tuple (x, y)

    Returns:
        Distance between 2 points

    """
    return math.sqrt((point1[0] - point2[0]) ** 2 + (point1[1] - point2[1]) ** 2)


[docs]def brute_force_distance(points): """ Brute force solution for closest pair problem Complexity: O(n^2) Args: points: list of points in the following format [(x1, y1), (x2, y2), ... , (xn, yn)] Returns: Minimum distance between points Examples: >>> n_log_n_squared_distance([(2, 3), (12, 30), (40, 50), (5, 1), (12, 10), (3, 4)]) 1.4142135623730951 """ if len(points) == 1: return 0 # Calculating distance between first two points min_d = _distance(points[0], points[1]) for x1, point1 in enumerate(points): for x2, point2 in enumerate(points): distance = _distance(point1, point2) if (x1 != x2) and distance < min_d: min_d = distance return min_d
[docs]def n_log_n_squared_distance(points): """ O(N (LogN)^2) solution for closest pair problem Complexity: O(n (log n)^2) Args: points: list of points in the following format [(x1, y1), (x2, y2), ... , (xn, yn)] Returns: Minimum distance between points Examples: >>> n_log_n_squared_distance([(2, 3), (12, 30), (40, 50), (5, 1), (12, 10), (3, 4)]) 1.4142135623730951 """ # Points have to be sorted by x coordinate points = sorted(points, key=lambda x: x[0]) return _n_log_n_squared_distance(points)
def _n_log_n_squared_distance(points): """ O(N (LogN)^2) solution for closest pair problem Complexity: O(n (log n)^2) Args: points: list of points in the following format [(x1, y1), (x2, y2), ... , (xn, yn)] Returns: Minimum distance between points """ if len(points) == 1: return 0 if len(points) <= 3: return brute_force_distance(points) # splitting points to the 2 parts mid = len(points) // 2 min_d1 = n_log_n_squared_distance(points[:mid]) min_d2 = n_log_n_squared_distance(points[mid:]) min_d = min(min_d1, min_d2) strip = [] # Adding point to the strip array if the distance between point and the "vertical" line that we split # is less than minimum distance that we have find. for point in points: x = point[0] if abs(x - points[mid][0]) < min_d: strip.append(point) return min(min_d, _closest_split_pair(strip, min_d)) def _closest_split_pair(points, delta): """ Function for check boundaries points (points that close to the split line than minimum delta) Args: points: list of points in the following format [(x1, y1), (x2, y2), ... , (xn, yn)] delta: delta (minimum distance) Returns: minimum distance between points """ for i in range(len(points)): for j in range(i + 1, len(points)): if (points[j][1] - points[i][1]) < delta and _distance(points[i], points[j]) < delta: delta = _distance(points[i], points[j]) return delta