Task: Closest-pair problem







Python: 

from random import randint, randrange
from operator import itemgetter, attrgetter

infinity = float('inf')



def bruteForceClosestPair(point):
    numPoints = len(point)
    if numPoints < 2:
        return infinity, (None, None)
    return min( ((abs(point[i] - point[j]), (point[i], point[j]))
                 for i in range(numPoints-1)
                 for j in range(i+1,numPoints)),
                key=itemgetter(0))

def closestPair(point):
    xP = sorted(point, key= attrgetter('real'))
    yP = sorted(point, key= attrgetter('imag'))
    return _closestPair(xP, yP)

def _closestPair(xP, yP):
    numPoints = len(xP)
    if numPoints <= 3:
        return bruteForceClosestPair(xP)
    Pl = xP[:numPoints/2]
    Pr = xP[numPoints/2:]
    Yl, Yr = [], []
    xDivider = Pl[-1].real
    for p in yP:
        if p.real <= xDivider:
            Yl.append(p)
        else:
            Yr.append(p)
    dl, pairl = _closestPair(Pl, Yl)
    dr, pairr = _closestPair(Pr, Yr)
    dm, pairm = (dl, pairl) if dl < dr else (dr, pairr)
    
    closeY = [p for p in yP  if abs(p.real - xDivider) < dm]
    numCloseY = len(closeY)
    if numCloseY > 1:
        
        closestY = min( ((abs(closeY[i] - closeY[j]), (closeY[i], closeY[j]))
                         for i in range(numCloseY-1)
                         for j in range(i+1,min(i+8, numCloseY))),
                        key=itemgetter(0))
        return (dm, pairm) if dm <= closestY[0] else closestY
    else:
        return dm, pairm
    
def times():
    
    import timeit

    functions = [bruteForceClosestPair, closestPair]
    for f in functions:
        print 'Time for', f.__name__, timeit.Timer(
            '%s(pointList)' % f.__name__,
            'from closestpair import %s, pointList' % f.__name__).timeit(number=1)
    


pointList = [randint(0,1000)+1j*randint(0,1000) for i in range(2000)]

if __name__ == '__main__':
    pointList = [(5+9j), (9+3j), (2+0j), (8+4j), (7+4j), (9+10j), (1+9j), (8+2j), 10j, (9+6j)]
    print pointList
    print '  bruteForceClosestPair:', bruteForceClosestPair(pointList)
    print '            closestPair:', closestPair(pointList)
    for i in range(10):
        pointList = [randrange(11)+1j*randrange(11) for i in range(10)]
        print '\n', pointList
        print ' bruteForceClosestPair:', bruteForceClosestPair(pointList)
        print '           closestPair:', closestPair(pointList)
    print '\n'
    times()
    times()
    times()


VB: Option Explicit

Private Type MyPoint
    X As Single
    Y As Single
End Type

Private Type MyPair
    p1 As MyPoint
    p2 As MyPoint
End Type

Sub Main()
Dim points() As MyPoint, i As Long, BF As MyPair, d As Single, Nb As Long
Dim T#
Randomize Timer
    Nb = 10
    Do
        ReDim points(1 To Nb)
        For i = 1 To Nb
            points(i).X = Rnd * Nb
            points(i).Y = Rnd * Nb
        Next
        d = 1000000000000#
T = Timer
        BF = BruteForce(points, d)
        Debug.Print "For " & Nb & " points, runtime : " & Timer - T & " sec."
        Debug.Print "point 1 : X:" & BF.p1.X & " Y:" & BF.p1.Y
        Debug.Print "point 2 : X:" & BF.p2.X & " Y:" & BF.p2.Y
        Debug.Print "dist : " & d
        Debug.Print "--------------------------------------------------"
        Nb = Nb * 10
    Loop While Nb <= 10000
End Sub

Private Function BruteForce(p() As MyPoint, mindist As Single) As MyPair
Dim i As Long, j As Long, d As Single, ClosestPair As MyPair
    For i = 1 To UBound(p) - 1
        For j = i + 1 To UBound(p)
            d = Dist(p(i), p(j))
            If d < mindist Then
                mindist = d
                ClosestPair.p1 = p(i)
                ClosestPair.p2 = p(j)
            End If
        Next
    Next
    BruteForce = ClosestPair
End Function

Private Function Dist(p1 As MyPoint, p2 As MyPoint) As Single
    Dist = Sqr((p1.X - p2.X) ^ 2 + (p1.Y - p2.Y) ^ 2)
End Function