"""
Compute nearest pair of points using two algorithms
First algorithm is 'brute force' comparison of every possible pair.
Second, 'divide and conquer', is based on:
www.cs.iupui.edu/~xkzou/teaching/CS580/Divide-and-conquer-closestPair.ppt
"""
from random import randint, randrange
from operator import itemgetter, attrgetter
infinity = float ( 'inf' )
# Note the use of complex numbers to represent 2D points making distance == abs(P1-P2)
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)
# Points within dm of xDivider sorted by Y coord
closeY = [ p for p in yP if abs ( p.real - xDivider) < dm]
numCloseY = len ( closeY)
if numCloseY > 1 :
# There is a proof that you only need compare a max of 7 next points
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( ) :
''' Time the different functions
'''
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 ( 3 ) :
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( )
#testPl = [(5+9j), (9+3j), (2+0j), (8+4j), (7+4j), (9+10j), (1+9j), (8+2j), 10j, (9+6j)]
#print(closestPair(testPl))
IiIiCiAgQ29tcHV0ZSBuZWFyZXN0IHBhaXIgb2YgcG9pbnRzIHVzaW5nIHR3byBhbGdvcml0aG1zCiAKICBGaXJzdCBhbGdvcml0aG0gaXMgJ2JydXRlIGZvcmNlJyBjb21wYXJpc29uIG9mIGV2ZXJ5IHBvc3NpYmxlIHBhaXIuCiAgU2Vjb25kLCAnZGl2aWRlIGFuZCBjb25xdWVyJywgaXMgYmFzZWQgb246CiAgICB3d3cuY3MuaXVwdWkuZWR1L354a3pvdS90ZWFjaGluZy9DUzU4MC9EaXZpZGUtYW5kLWNvbnF1ZXItY2xvc2VzdFBhaXIucHB0IAoiIiIKIApmcm9tIHJhbmRvbSBpbXBvcnQgcmFuZGludCwgcmFuZHJhbmdlCmZyb20gb3BlcmF0b3IgaW1wb3J0IGl0ZW1nZXR0ZXIsIGF0dHJnZXR0ZXIKIAppbmZpbml0eSA9IGZsb2F0KCdpbmYnKQogCiMgTm90ZSB0aGUgdXNlIG9mIGNvbXBsZXggbnVtYmVycyB0byByZXByZXNlbnQgMkQgcG9pbnRzIG1ha2luZyBkaXN0YW5jZSA9PSBhYnMoUDEtUDIpCiAKZGVmIGJydXRlRm9yY2VDbG9zZXN0UGFpcihwb2ludCk6CiAgICBudW1Qb2ludHMgPSBsZW4ocG9pbnQpCiAgICAgCiAgICAKICAgIGlmIG51bVBvaW50cyA8IDI6CiAgICAgICAgcmV0dXJuIGluZmluaXR5LCAoTm9uZSwgTm9uZSkKICAgIHJldHVybiBtaW4oICgoYWJzKHBvaW50W2ldIC0gcG9pbnRbal0pLCAocG9pbnRbaV0sIHBvaW50W2pdKSkKICAgICAgICAgICAgICAgICBmb3IgaSBpbiByYW5nZShudW1Qb2ludHMtMSkKICAgICAgICAgICAgICAgICBmb3IgaiBpbiByYW5nZShpKzEsbnVtUG9pbnRzKSksCiAgICAgICAgICAgICAgICBrZXk9aXRlbWdldHRlcigwKSkKIApkZWYgY2xvc2VzdFBhaXIocG9pbnQpOgogICAgeFAgPSBzb3J0ZWQocG9pbnQsIGtleT0gYXR0cmdldHRlcigncmVhbCcpKQogICAgeVAgPSBzb3J0ZWQocG9pbnQsIGtleT0gYXR0cmdldHRlcignaW1hZycpKQogICAgcmV0dXJuIF9jbG9zZXN0UGFpcih4UCwgeVApCiAKZGVmIF9jbG9zZXN0UGFpcih4UCwgeVApOgogICAgbnVtUG9pbnRzID0gbGVuKHhQKQogICAgaWYgbnVtUG9pbnRzIDw9IDM6CiAgICAgICAgcmV0dXJuIGJydXRlRm9yY2VDbG9zZXN0UGFpcih4UCkKICAgIFBsID0geFBbOm51bVBvaW50cy8yXQogICAgUHIgPSB4UFtudW1Qb2ludHMvMjpdCiAgICBZbCwgWXIgPSBbXSwgW10KICAgIHhEaXZpZGVyID0gUGxbLTFdLnJlYWwKICAgIGZvciBwIGluIHlQOgogICAgICAgIGlmIHAucmVhbCA8PSB4RGl2aWRlcjoKICAgICAgICAgICAgWWwuYXBwZW5kKHApCiAgICAgICAgZWxzZToKICAgICAgICAgICAgWXIuYXBwZW5kKHApCiAgICBkbCwgcGFpcmwgPSBfY2xvc2VzdFBhaXIoUGwsIFlsKQogICAgZHIsIHBhaXJyID0gX2Nsb3Nlc3RQYWlyKFByLCBZcikKICAgIGRtLCBwYWlybSA9IChkbCwgcGFpcmwpIGlmIGRsIDwgZHIgZWxzZSAoZHIsIHBhaXJyKQogICAgIyBQb2ludHMgd2l0aGluIGRtIG9mIHhEaXZpZGVyIHNvcnRlZCBieSBZIGNvb3JkCiAgICBjbG9zZVkgPSBbcCBmb3IgcCBpbiB5UCAgaWYgYWJzKHAucmVhbCAtIHhEaXZpZGVyKSA8IGRtXQogICAgbnVtQ2xvc2VZID0gbGVuKGNsb3NlWSkKICAgIGlmIG51bUNsb3NlWSA+IDE6CiAgICAgICAgIyBUaGVyZSBpcyBhIHByb29mIHRoYXQgeW91IG9ubHkgbmVlZCBjb21wYXJlIGEgbWF4IG9mIDcgbmV4dCBwb2ludHMKICAgICAgICBjbG9zZXN0WSA9IG1pbiggKChhYnMoY2xvc2VZW2ldIC0gY2xvc2VZW2pdKSwgKGNsb3NlWVtpXSwgY2xvc2VZW2pdKSkKICAgICAgICAgICAgICAgICAgICAgICAgIGZvciBpIGluIHJhbmdlKG51bUNsb3NlWS0xKQogICAgICAgICAgICAgICAgICAgICAgICAgZm9yIGogaW4gcmFuZ2UoaSsxLG1pbihpKzgsIG51bUNsb3NlWSkpKSwKICAgICAgICAgICAgICAgICAgICAgICAga2V5PWl0ZW1nZXR0ZXIoMCkpCiAgICAgICAgcmV0dXJuIChkbSwgcGFpcm0pIGlmIGRtIDw9IGNsb3Nlc3RZWzBdIGVsc2UgY2xvc2VzdFkKICAgIGVsc2U6CiAgICAgICAgcmV0dXJuIGRtLCBwYWlybQogCmRlZiB0aW1lcygpOgogICAgJycnIFRpbWUgdGhlIGRpZmZlcmVudCBmdW5jdGlvbnMKICAgICcnJwogICAgaW1wb3J0IHRpbWVpdAogCiAgICBmdW5jdGlvbnMgPSBbYnJ1dGVGb3JjZUNsb3Nlc3RQYWlyLCBjbG9zZXN0UGFpcl0KICAgIGZvciBmIGluIGZ1bmN0aW9uczoKICAgICAgICBwcmludCAnVGltZSBmb3InLCBmLl9fbmFtZV9fLCB0aW1laXQuVGltZXIoCiAgICAgICAgICAgICclcyhwb2ludExpc3QpJyAlIGYuX19uYW1lX18sCiAgICAgICAgICAgICdmcm9tIGNsb3Nlc3RwYWlyIGltcG9ydCAlcywgcG9pbnRMaXN0JyAlIGYuX19uYW1lX18pLnRpbWVpdChudW1iZXI9MSkKIAogCiAKcG9pbnRMaXN0ID0gW3JhbmRpbnQoMCwxMDAwKSsxaipyYW5kaW50KDAsMTAwMCkgZm9yIGkgaW4gcmFuZ2UoMjAwMCldCiAKaWYgX19uYW1lX18gPT0gJ19fbWFpbl9fJzoKICAgIHBvaW50TGlzdCA9IFsoNSs5aiksICg5KzNqKSwgKDIrMGopLCAoOCs0aiksICg3KzRqKSwgKDkrMTBqKSwgKDErOWopLCAoOCsyaiksIDEwaiwgKDkrNmopXQogICAgcHJpbnQgcG9pbnRMaXN0CiAgICBwcmludCAnICBicnV0ZUZvcmNlQ2xvc2VzdFBhaXI6JywgYnJ1dGVGb3JjZUNsb3Nlc3RQYWlyKHBvaW50TGlzdCkKICAgIHByaW50ICcgICAgICAgICAgICBjbG9zZXN0UGFpcjonLCBjbG9zZXN0UGFpcihwb2ludExpc3QpCiAgICBmb3IgaSBpbiByYW5nZSgzKToKICAgICAgICBwb2ludExpc3QgPSBbcmFuZHJhbmdlKDExKSsxaipyYW5kcmFuZ2UoMTEpIGZvciBpIGluIHJhbmdlKDEwKV0KICAgICAgICBwcmludCAnXG4nLCBwb2ludExpc3QgCiAgICAgICAgcHJpbnQgJyBicnV0ZUZvcmNlQ2xvc2VzdFBhaXI6JywgYnJ1dGVGb3JjZUNsb3Nlc3RQYWlyKHBvaW50TGlzdCkKICAgICAgICBwcmludCAnICAgICAgICAgICBjbG9zZXN0UGFpcjonLCBjbG9zZXN0UGFpcihwb2ludExpc3QpCiAgICBwcmludCAnXG4nCiAgICB0aW1lcygpCiAgICB0aW1lcygpCiAgICB0aW1lcygpCgojdGVzdFBsID0gWyg1KzlqKSwgKDkrM2opLCAoMiswaiksICg4KzRqKSwgKDcrNGopLCAoOSsxMGopLCAoMSs5aiksICg4KzJqKSwgMTBqLCAoOSs2aildCiNwcmludChjbG9zZXN0UGFpcih0ZXN0UGwpKQoK
stdout
[(5+9j), (9+3j), (2+0j), (8+4j), (7+4j), (9+10j), (1+9j), (8+2j), 10j, (9+6j)]
bruteForceClosestPair: (1.0, ((8+4j), (7+4j)))
closestPair: (1.0, ((8+4j), (7+4j)))
[(7+7j), (7+1j), 2j, (7+0j), (2+3j), (2+3j), (10+3j), (3+8j), (9+5j), (3+2j)]
bruteForceClosestPair: (0.0, ((2+3j), (2+3j)))
closestPair: (0.0, ((2+3j), (2+3j)))
[(6+0j), (1+4j), (8+8j), (7+2j), (6+9j), (7+8j), (4+10j), 1j, (8+1j), (1+2j)]
bruteForceClosestPair: (1.0, ((8+8j), (7+8j)))
closestPair: (1.0, ((7+8j), (8+8j)))
[(6+1j), (9+9j), (9+5j), 10j, (6+1j), (2+8j), (2+10j), 9j, 7j, (3+8j)]
bruteForceClosestPair: (0.0, ((6+1j), (6+1j)))
closestPair: (0.0, ((6+1j), (6+1j)))
Time for bruteForceClosestPair
stderr
Traceback (most recent call last):
File "prog.py", line 87, in <module>
File "prog.py", line 70, in times
File "/usr/lib/python2.7/timeit.py", line 195, in timeit
timing = self.inner(it, self.timer)
File "<timeit-src>", line 3, in inner
ImportError: No module named closestpair