Closest-pair problem

From Rosetta Code

Jump to: navigation, search
Task
Closest-pair problem
You are encouraged to solve this task according to the task description, using any language you may know.
This page uses content from Wikipedia. The original article was at Closest-pair problem. The list of authors can be seen in the page history. As with Rosetta Code, the text of Wikipedia is available under the GNU Free Documentation License.

The aim of this task is to provide a function to find the closest two points among a set of given points in two dimensions, i.e. to solve the Closest pair of points problem in the planar case.

The straightforward solution is a O(n2) algorithm (which we can call brute-force algorithm); the pseudocode (using indexes) could be simply:

bruteForceClosestPair of P(1), P(2), ... P(N)
if N < 2 then
  returnelse
  minDistance ← |P(1) - P(2)|
  minPoints ← { P(1), P(2) }
  foreach i ∈ [1, N-1]
    foreach j ∈ [i+1, N]
      if |P(i) - P(j)| < minDistance then
        minDistance ← |P(i) - P(j)|
        minPoints ← { P(i), P(j) } 
      endif
    endfor
  endfor
  return minDistance, minPoints
 endif

A better algorithm is based on the recursive divide&conquer approach, as explained also at Wikipedia, which is O(n log n); a pseudocode could be:

closestPair of (xP, yP)
               where xP is P(1) .. P(N) sorted by x coordinate, and
                     yP is P(1) .. P(N) sorted by y coordinate (ascending order)
if N ≤ 3 then
  return closest points of xP using brute-force algorithm
else
  xL ← points of xP from 1 to ⌈N/2⌉
  xR ← points of xP from ⌈N/2⌉+1 to N
  xm ← xP(⌈N/2⌉)x
  yL ← { p ∈ yP : px ≤ xm }
  yR ← { p ∈ yP : px > xm }
  (dL, pairL) ← closestPair of (xL, yL)
  (dR, pairR) ← closestPair of (xR, yR)
  (dmin, pairMin) ← (dR, pairR)
  if dL < dR then
    (dmin, pairMin) ← (dL, pairL)
  endif
  yS ← { p ∈ yP : |xm - px| < dmin }
  nS ← number of points in yS
  (closest, closestPair) ← (dmin, pairMin)
  for i from 1 to nS - 1
    k ← i + 1
    while k ≤ nS and yS(k)y - yS(i)y < dmin
      if |yS(k) - yS(i)| < closest then
        (closest, closestPair) ← (|yS(k) - yS(i)|, {yS(k), yS(i)})
      endif
      k ← k + 1
    endwhile
  endfor
  return closest, closestPair
endif


References and further readings

Contents

[edit] C

See Closest pair problem/C

[edit] Common Lisp

Points are conses whose cars are x coördinates and whose cdrs are y coördinates. This version includes the optimizations given in the McGill description of the algorithm.

(defun point-distance (p1 p2)
(destructuring-bind (x1 . y1) p1
(destructuring-bind (x2 . y2) p2
(let ((dx (- x2 x1)) (dy (- y2 y1)))
(sqrt (+ (* dx dx) (* dy dy)))))))
 
(defun closest-pair-bf (points)
(let ((pair (list (first points) (second points)))
(dist (point-distance (first points) (second points))))
(dolist (p1 points (values pair dist))
(dolist (p2 points)
(unless (eq p1 p2)
(let ((pdist (point-distance p1 p2)))
(when (< pdist dist)
(setf (first pair) p1
(second pair) p2
dist pdist))))))))
 
(defun closest-pair (points)
(labels
((cp (xp &aux (length (length xp)))
(if (<= length 3)
(multiple-value-bind (pair distance) (closest-pair-bf xp)
(values pair distance (sort xp '< :key 'cdr)))
(let* ((xr (nthcdr (1- (floor length 2)) xp))
(xm (/ (+ (caar xr) (caadr xr)) 2)))
(psetf xr (rest xr)
(rest xr) '())
(multiple-value-bind (lpair ldist yl) (cp xp)
(multiple-value-bind (rpair rdist yr) (cp xr)
(multiple-value-bind (dist pair)
(if (< ldist rdist)
(values ldist lpair)
(values rdist rpair))
(let* ((all-ys (merge 'vector yl yr '< :key 'cdr))
(ys (remove-if #'(lambda (p)
(> (abs (- (car p) xm)) dist))
all-ys))
(ns (length ys)))
(dotimes (i ns)
(do ((k (1+ i) (1+ k)))
((or (= k ns)
(> (- (cdr (aref ys k))
(cdr (aref ys i)))
dist)))
(let ((pd (point-distance (aref ys i)
(aref ys k))))
(when (< pd dist)
(setf dist pd
(first pair) (aref ys i)
(second pair) (aref ys k))))))
(values pair dist all-ys)))))))))
(multiple-value-bind (pair distance)
(cp (sort (copy-list points) '< :key 'car))
(values pair distance))))

[edit] C#

We provide a small helper class for distance comparisons:

class Segment
{
public Segment(PointF p1, PointF p2)
{
P1 = p1;
P2 = p2;
}
 
public readonly PointF P1;
public readonly PointF P2;
 
public float Length()
{
return (float)Math.Sqrt(LengthSquared());
}
 
public float LengthSquared()
{
return (P1.X - P2.X) * (P1.X - P2.X)
+ (P1.Y - P2.Y) * (P1.Y - P2.Y);
}
}

Brute force:

Segment Closest_BruteForce(List<PointF> points)
{
int n = points.Count;
var result = Enumerable.Range( 0, n-1)
.SelectMany( i => Enumerable.Range( i+1, n-(i+1) )
.Select( j => new Segment( points[i], points[j] )))
.OrderBy( seg => seg.LengthSquared())
.First();
 
return result;
}

And divide-and-conquer. Notice that the code has been written for brevity and to demonstrate the algorithm, not true optimization. There are further language-specific optimizations that could be applied.

Segment Closest_Recursive(List<PointF> points)
{
if (points.Count() < 4) return Closest_BruteForce(points.ToList());
 
int split = points.Count() / 2;
var ordered = points.OrderBy(point => point.X);
var pointsOnLeft = ordered.Take(split).ToList();
var pointsOnRight = ordered.Skip(split).ToList();
 
var leftMin = Closest_Recursive(pointsOnLeft);
float leftDist = leftMin.Length();
var rightMin = Closest_Recursive(pointsOnRight);
float rightDist = rightMin.Length();
 
float minDist = Math.Min(leftDist, rightDist);
var xDivider = pointsOnLeft.Last().X;
var closeY = pointsOnRight.TakeWhile(point => point.X - xDivider < minDist).OrderBy(point => point.Y);
 
var crossingPairs = pointsOnLeft.SkipWhile(point => xDivider - point.X > minDist)
.SelectMany(p1 => closeY.SkipWhile(i => i.Y < p1.Y - minDist)
.TakeWhile(i => i.Y < p1.Y + minDist)
.Select(p2 => new Segment( p1, p2 )));
 
return crossingPairs.Union( new [] { leftMin, rightMin })
.OrderBy(segment => segment.Length()).First();
}

However, the difference in speed is still remarkable.

Some lines in this example are too long (more than 80 characters). Please fix the code if it's possible and remove this message.
var randomizer = new Random(10);
var points = Enumerable.Range( 0, 10000).Select( i => new PointF( (float)randomizer.NextDouble(), (float)randomizer.NextDouble())).ToList();
Stopwatch sw = Stopwatch.StartNew();
var r1 = Closest_BruteForce(points);
sw.Stop();
Debugger.Log(1, "", string.Format("Time used (Brute force) (float): {0} ms", sw.Elapsed.TotalMilliseconds));
Stopwatch sw2 = Stopwatch.StartNew();
var result2 = Closest_Recursive(points);
sw2.Stop();
Debugger.Log(1, "", string.Format("Time used (Divide & Conquer): {0} ms",sw2.Elapsed.TotalMilliseconds));
Assert.Equal(r1.Length(), result2.Length());

Output:

Time used (Brute force) (float): 145731.8935 ms
Time used (Divide & Conquer): 1139.2111 ms

[edit] D

This implements the brute force method. It is currently locked to a single data type and structure, but could easily be templated to apply to other types or more dimensions.

import std.math;
struct point {
real x,y;
}
real distance(point p1,point p2) {
real xdiff = p1.x-p2.x,ydiff = p1.y-p2.y;
return sqrt(xdiff*xdiff+ydiff*ydiff);
}
point[]closest_pair(point[]input) {
real tmp,savedist = -1;
int savei = -1,savej = -1;
foreach(i,p1;input) foreach(j,p2;input) {
if (i==j) continue;
if (savedist == -1) {
savei = i;
savej = j;
savedist = distance(p1,p2);
continue;
}
tmp = distance(p1,p2);
if (tmp < savedist) {
savei = i;
savej = j;
savedist = tmp;
}
}
if (savedist == -1) return null;
return [input[savei],input[savej]];
}

[edit] F#

Brute force:

 
let closest_pairs (xys: Point []) =
let n = xys.Length
seq { for i in 0..n-2 do
for j in i+1..n-1 do
yield xys.[i], xys.[j] }
|> Seq.minBy (fun (p0, p1) -> (p1 - p0).LengthSquared)
 

For example:

 
closest_pairs
[|Point(0.0, 0.0); Point(1.0, 0.0); Point (2.0, 2.0)|]
 

gives:

 
(0,0, 1,0)
 

[edit] Fortran

See Closest pair problem/Fortran

[edit] Haskell

BF solution:

import Data.List
import System.Random
import Control.Monad
import Control.Arrow
import Data.Ord
 
vecLeng [[a,b],[p,q]] = sqrt $ (a-p)^2+(b-q)^2
 
findClosestPair = foldl1' ((minimumBy (comparing vecLeng). ). (. return). (:)) .
concatMap (\(x:xs) -> map ((x:).return) xs) . init . tails
 
testCP = do
g <- newStdGen
let pts :: [[Double]]
pts = take 1000. unfoldr (Just. splitAt 2) $ randomRs(-1,1) g
print . (id &&& vecLeng ) . findClosestPair $ pts

Output example:

*Main> testCP
([[0.8347201880148426,0.40774840545089647],[0.8348731214261784,0.4087113189531284]],9.749825850154334e-4)
(4.02 secs, 488869056 bytes)

[edit] J

Solution of the simpler (brute-force) problem:

vecl   =:  +/"1&.:*:                  NB. length of each of vectors
dist =: <@:vecl@:({: -"1 }:)\ NB. calculate all distances among vectors
minpair=: ({~ > {.@($ #: I.@,)@:= <./@;)dist NB. find one pair of the closest points
closestpairbf =: (; vecl@:-/)@minpair NB. the pair and their distance

Examples of use:

   ]pts=:10 2 ?@$ 0
0.654682 0.925557
0.409382 0.619391
0.891663 0.888594
0.716629 0.9962
0.477721 0.946355
0.925092 0.81822
0.624291 0.142924
0.211332 0.221507
0.293786 0.691701
0.839186 0.72826
 
closestpairbf pts
+-----------------+---------+
|0.891663 0.888594|0.0779104|
|0.925092 0.81822| |
+-----------------+---------+

The program also works for higher dimensional vectors:

   ]pts=:10 4 ?@$ 0
0.559164 0.482993 0.876 0.429769
0.217911 0.729463 0.97227 0.132175
0.479206 0.169165 0.495302 0.362738
0.316673 0.797519 0.745821 0.0598321
0.662585 0.726389 0.658895 0.653457
0.965094 0.664519 0.084712 0.20671
0.840877 0.591713 0.630206 0.99119
0.221416 0.114238 0.0991282 0.174741
0.946262 0.505672 0.776017 0.307362
0.262482 0.540054 0.707342 0.465234
 
closestpairbf pts
+------------------------------------+--------+
|0.217911 0.729463 0.97227 0.132175|0.708555|
|0.316673 0.797519 0.745821 0.0598321| |
+------------------------------------+--------+

[edit] JavaScript

Using bruteforce algorithm, the bruteforceClosestPair method below expects an array of objects with x- and y-members set to numbers, and returns an object containing the members distance and points.

function distance(p1, p2) {
var dx = Math.abs(p1.x - p2.x);
var dy = Math.abs(p1.y - p2.y);
return Math.sqrt(dx*dx + dy*dy);
}
 
function bruteforceClosestPair(arr) {
if (arr.length < 2) {
return Infinity;
} else {
var minDist = distance(arr[0], arr[1]);
var minPoints = arr.slice(0, 2);
 
for (var i=0; i<arr.length-1; i++) {
for (var j=i+1; j<arr.length; j++) {
if (distance(arr[i], arr[j]) < minDist) {
minDist = distance(arr[i], arr[j]);
minPoints = [ arr[i], arr[j] ];
}
}
}
return {
distance: minDist,
points: minPoints
};
}
}

[edit] MATLAB

This solution is an almost direct translation of the above pseudo-code into MATLAB.

function [closest,closestpair] = closestPair(xP,yP)
 
N = numel(xP);
 
if(N <= 3)
 
%Brute force closestpair
if(N < 2)
closest = +Inf;
closestpair = {};
else
closest = norm(xP{1}-xP{2});
closestpair = {xP{1},xP{2}};
 
for i = ( 1:N-1 )
for j = ( (i+1):N )
if ( norm(xP{i} - xP{j}) < closest )
closest = norm(xP{i}-xP{j});
closestpair = {xP{i},xP{j}};
end %if
end %for
end %for
end %if (N < 2)
else
 
halfN = ceil(N/2);
 
xL = { xP{1:halfN} };
xR = { xP{halfN+1:N} };
xm = xP{halfN}(1);
 
%cellfun( @(p)le(p(1),xm),yP ) is the same as { p ∈ yP : px ≤ xm }
yLIndicies = cellfun( @(p)le(p(1),xm),yP );
 
yL = { yP{yLIndicies} };
yR = { yP{~yLIndicies} };
 
[dL,pairL] = closestPair(xL,yL);
[dR,pairR] = closestPair(xR,yR);
 
if dL < dR
dmin = dL;
pairMin = pairL;
else
dmin = dR;
pairMin = pairR;
end
 
%cellfun( @(p)lt(norm(xm-p(1)),dmin),yP ) is the same as
%{ p ∈ yP : |xm - px| < dmin }
yS = {yP{ cellfun( @(p)lt(norm(xm-p(1)),dmin),yP ) }};
nS = numel(yS);
 
closest = dmin;
closestpair = pairMin;
 
for i = (1:nS-1)
k = i+1;
 
while( (k<=nS) && (yS{k}(2)-yS{i}(2) < dmin) )
 
if norm(yS{k}-yS{i}) < closest
closest = norm(yS{k}-yS{i});
closestpair = {yS{k},yS{i}};
end
 
k = k+1;
end %while
end %for
end %if (N <= 3)
end %closestPair

Sample Output:

[distance,pair]=closestPair({[0 -.3],[1 1],[1.5 2],[2 2],[3 3]},{[0 -.3],[1 1],[1.5 2],[2 2],[3 3]})
 
distance =
 
0.500000000000000
 
 
pair =
 
[1x2 double] [1x2 double] %The pair is [1.5 2] and [2 2] which is correct

[edit] Objective-C

See Closest pair problem/Objective-C

[edit] Oz

Translation of pseudocode:

declare
fun {Distance X1#Y1 X2#Y2}
{Sqrt {Pow X2-X1 2.0} + {Pow Y2-Y1 2.0}}
end
 
%% brute force
fun {BFClosestPair Points=P1|P2|_}
Ps = {List.toTuple unit Points} %% for efficient random access
N = {Width Ps}
MinDist = {NewCell {Distance P1 P2}}
MinPoints = {NewCell P1#P2}
in
for I in 1..N-1 do
for J in I+1..N do
IJDist = {Distance Ps.I Ps.J}
in
if IJDist < @MinDist then
MinDist := IJDist
MinPoints := Ps.I#Ps.J
end
end
end
@MinPoints
end
 
%% divide and conquer
fun {ClosestPair Points}
case {ClosestPair2
{Sort Points {LessThanBy X}}
{Sort Points {LessThanBy Y}}}
of Distance#Pair then
Pair
end
end
 
%% XP: points sorted by X, YP: sorted by Y
%% returns a pair Distance#Pair
fun {ClosestPair2 XP YP}
N = {Length XP} = {Length YP}
in
if N =< 3 then
P = {BFClosestPair XP}
in
{Distance P.1 P.2}#P
else
XL XR
{List.takeDrop XP (N div 2) ?XL ?XR}
XM = {Nth XP (N div 2)}.X
YL YR
{List.partition YP fun {$ P} P.X =< XM end ?YL ?YR}
DL#PairL = {ClosestPair2 XL YL}
DR#PairR = {ClosestPair2 XR YR}
DMin#PairMin = if DL < DR then DL#PairL else DR#PairR end
YSList = {Filter YP fun {$ P} {Abs XM-P.X} < DMin end}
YS = {List.toTuple unit YSList} %% for efficient random access
NS = {Width YS}
Closest = {NewCell DMin}
ClosestPair = {NewCell PairMin}
in
for I in 1..NS-1 do
for K in I+1..NS while:YS.K.Y - YS.I.Y < DMin do
DistKI = {Distance YS.K YS.I}
in
if DistKI < @Closest then
Closest := DistKI
ClosestPair := YS.K#YS.I
end
end
end
@Closest#@ClosestPair
end
end
 
%% To access components when points are represented as pairs
X = 1
Y = 2
 
%% returns a less-than predicate that accesses feature F
fun {LessThanBy F}
fun {$ A B}
A.F < B.F
end
end
 
fun {Random Min Max}
Min +
{Int.toFloat {OS.rand}} * (Max-Min)
/ {Int.toFloat {OS.randLimits _}}
end
 
fun {RandomPoint}
{Random 0.0 100.0}#{Random 0.0 100.0}
end
 
Points = {MakeList 5}
in
{ForAll Points RandomPoint}
{Show Points}
{Show {ClosestPair Points}}

[edit] Perl

#! /usr/bin/perl
use strict;
use POSIX qw(ceil);
 
sub dist
{
my ( $a, $b) = @_;
return sqrt( ($a->[0] - $b->[0])**2 +
($a->[1] - $b->[1])**2 );
}
 
sub closest_pair_simple
{
my $ra = shift;
my @arr = @$ra;
my $inf = 1e600;
return $inf if scalar(@arr) < 2;
my ( $a, $b, $d ) = ($arr[0], $arr[1], dist($arr[0], $arr[1]));
while( @arr ) {
my $p = pop @arr;
foreach my $l (@arr) {
my $t = dist($p, $l);
($a, $b, $d) = ($p, $l, $t) if $t < $d;
}
}
return ($a, $b, $d);
}
 
sub closest_pair
{
my $r = shift;
my @ax = sort { $a->[0] <=> $b->[0] } @$r;
my @ay = sort { $a->[1] <=> $b->[1] } @$r;
return closest_pair_real(\@ax, \@ay);
}
 
sub closest_pair_real
{
my ($rx, $ry) = @_;
my @xP = @$rx;
my @yP = @$ry;
my $N = @xP;
return closest_pair_simple($rx) if scalar(@xP) <= 3;
 
my $inf = 1e600;
my $midx = ceil($N/2)-1;
 
my @PL = @xP[0 .. $midx];
my @PR = @xP[$midx+1 .. $N-1];
 
my $xm = ${$xP[$midx]}[0];
 
my @yR = ();
my @yL = ();
foreach my $p (@yP) {
if ( ${$p}[0] <= $xm ) {
push @yR, $p;
} else {
push @yL, $p;
}
}
 
my ($al, $bl, $dL) = closest_pair_real(\@PL, \@yR);
my ($ar, $br, $dR) = closest_pair_real(\@PR, \@yL);
 
my ($m1, $m2, $dmin) = ($al, $bl, $dL);
($m1, $m2, $dmin) = ($ar, $br, $dR) if $dR < $dL;
 
my @yS = ();
foreach my $p (@yP) {
push @yS, $p if abs($xm - ${$p}[0]) < $dmin;
}
 
if ( @yS ) {
my ( $w1, $w2, $closest ) = ($m1, $m2, $dmin);
foreach my $i (0 .. ($#yS - 1)) {
 
my $k = $i + 1;
while ( ($k <= $#yS) && ( (${$yS[$k]}[1] - ${$yS[$i]}[1]) < $dmin) ) {
my $d = dist($yS[$k], $yS[$i]);
($w1, $w2, $closest) = ($yS[$k], $yS[$i], $d) if $d < $closest;
$k++;
}
 
}
return ($w1, $w2, $closest);
 
} else {
return ($m1, $m2, $dmin);
}
}
 
 
 
my @points = ();
my $N = 5000;
 
foreach my $i (1..$N) {
push @points, [rand(20)-10.0, rand(20)-10.0];
}
 
 
my ($a, $b, $d) = closest_pair_simple(\@points);
print "$d\n";
 
my ($a1, $b1, $d1) = closest_pair(\@points);
#print "$d1\n";

Time for the brute-force algorithm gave 40.63user 0.12system 0:41.06elapsed, while the divide&conqueer algorithm gave 0.37user 0.00system 0:00.38elapsed with 5000 points.

[edit] PL/I

 
/* Closest Pair Problem */
closest: procedure options (main);
declare n fixed binary;
 
get list (n);
begin;
declare 1 P(n),
2 x float,
2 y float;
declare (i, ii, j, jj) fixed binary;
declare (distance, min_distance initial (0) ) float;
 
get list (P);
min_distance = sqrt( (P.x(1) - P.x(2))**2 + (P.y(1) - P.y(2))**2 );
ii = 1; jj = 2;
do i = 1 to n;
do j = 1 to n;
distance = sqrt( (P.x(i) - P.x(j))**2 + (P.y(i) - P.y(j))**2 );
if distance > 0 then
if distance < min_distance then
do;
min_distance = distance;
ii = i; jj = j;
end;
end;
end;
put skip edit ('The minimum distance ', min_distance,
' is between the points [', P.x(ii),
',', P.y(ii), '] and [', P.x(jj), ',', P.y(jj), ']' )
(a, f(6,2));
end;
end closest;
 

[edit] PureBasic

Brute force version

Procedure.d bruteForceClosestPair(Array P.coordinate(1))
Protected N=ArraySize(P()), i, j
Protected mindistance.f=Infinity(), t.d
Shared a, b
If N<2
a=0: b=0
Else
For i=0 To N-1
For j=i+1 To N
t=Pow(Pow(P(i)\x-P(j)\x,2)+Pow(P(i)\y-P(j)\y,2),0.5)
If mindistance>t
mindistance=t
a=i: b=j
EndIf
Next
Next
EndIf
ProcedureReturn mindistance
EndProcedure
 

Implementation can be as

Structure coordinate
x.d
y.d
EndStructure
 
Dim DataSet.coordinate(9)
Define i, x.d, y.d, a, b
 
;- Load data from datasection
Restore DataPoints
For i=0 To 9
Read.d x: Read.d y
DataSet(i)\x=x
DataSet(i)\y=y
Next i
 
If OpenConsole()
PrintN("Mindistance= "+StrD(bruteForceClosestPair(DataSet()),6))
PrintN("Point 1= "+StrD(DataSet(a)\x,6)+": "+StrD(DataSet(a)\y,6))
PrintN("Point 2= "+StrD(DataSet(b)\x,6)+": "+StrD(DataSet(b)\y,6))
Print(#CRLF$+"Press ENTER to quit"): Input()
EndIf
 
DataSection
DataPoints:
Data.d 0.654682, 0.925557, 0.409382, 0.619391, 0.891663, 0.888594
Data.d 0.716629, 0.996200, 0.477721, 0.946355, 0.925092, 0.818220
Data.d 0.624291, 0.142924, 0.211332, 0.221507, 0.293786, 0.691701, 0.839186, 0.72826
EndDataSection

Output

Mindistance= 0.077910
Point 1= 0.891663: 0.888594
Point 2= 0.925092: 0.818220

Press ENTER to quit

[edit] Python

"""
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
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(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()

Sample output followed by timing comparisons
(Note how the two algorithms agree on the minimum distance, but may return a different pair of points if more than one pair of points share that minimum separation):

[(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)))

[(10+6j), (7+0j), (9+4j), (4+8j), (7+5j), (6+4j), (1+9j), (6+4j), (1+3j), (5+0j)]
 bruteForceClosestPair: (0.0, ((6+4j), (6+4j)))
           closestPair: (0.0, ((6+4j), (6+4j)))

[(4+10j), (8+5j), (10+3j), (9+7j), (2+5j), (6+7j), (6+2j), (9+6j), (3+8j), (5+1j)]
 bruteForceClosestPair: (1.0, ((9+7j), (9+6j)))
           closestPair: (1.0, ((9+7j), (9+6j)))

[(10+0j), (3+10j), (10+7j), (1+8j), (5+10j), (8+8j), (4+7j), (6+2j), (6+10j), (9+3j)]
 bruteForceClosestPair: (1.0, ((5+10j), (6+10j)))
           closestPair: (1.0, ((5+10j), (6+10j)))

[(3+7j), (5+3j), 0j, (2+9j), (2+5j), (9+6j), (5+9j), (4+3j), (3+8j), (8+7j)]
 bruteForceClosestPair: (1.0, ((3+7j), (3+8j)))
           closestPair: (1.0, ((4+3j), (5+3j)))

[(4+3j), (10+9j), (2+7j), (7+8j), 0j, (3+10j), (10+2j), (7+10j), (7+3j), (1+4j)]
 bruteForceClosestPair: (2.0, ((7+8j), (7+10j)))
           closestPair: (2.0, ((7+8j), (7+10j)))

[(9+2j), (9+8j), (6+4j), (7+0j), (10+2j), (10+0j), (2+7j), (10+7j), (9+2j), (1+5j)]
 bruteForceClosestPair: (0.0, ((9+2j), (9+2j)))
           closestPair: (0.0, ((9+2j), (9+2j)))

[(3+3j), (8+2j), (4+0j), (1+1j), (9+10j), (5+0j), (2+3j), 5j, (5+0j), (7+0j)]
 bruteForceClosestPair: (0.0, ((5+0j), (5+0j)))
           closestPair: (0.0, ((5+0j), (5+0j)))

[(1+5j), (8+3j), (8+10j), (6+8j), (10+9j), (2+0j), (2+7j), (8+7j), (8+4j), (1+2j)]
 bruteForceClosestPair: (1.0, ((8+3j), (8+4j)))
           closestPair: (1.0, ((8+3j), (8+4j)))

[(8+4j), (8+6j), (8+0j), 0j, (10+7j), (10+6j), 6j, (1+3j), (1+8j), (6+9j)]
 bruteForceClosestPair: (1.0, ((10+7j), (10+6j)))
           closestPair: (1.0, ((10+7j), (10+6j)))

[(6+8j), (10+1j), 3j, (7+9j), (4+10j), (4+7j), (5+7j), (6+10j), (4+7j), (2+4j)]
 bruteForceClosestPair: (0.0, ((4+7j), (4+7j)))
           closestPair: (0.0, ((4+7j), (4+7j)))


Time for bruteForceClosestPair 4.57953371169
Time for closestPair 0.122539596513
Time for bruteForceClosestPair 5.13221177552
Time for closestPair 0.124602707886
Time for bruteForceClosestPair 4.83609397284
Time for closestPair 0.119326618327
>>> 

[edit] R

This example may be incorrect.
It is only a brute force algorithm and not optimized.
Please verify it and remove this message. If the example does not match the requirements or does not work, replace this message with Template:incorrect or fix the code yourself.

Works with: R version 2.81

This is just a brute force solution for R that makes use of the apply function native to R for dealing with matrices. It expects x and y to take the form of separate vectors.

closestPair<-function(x,y)
{
distancev <- function(pointsv)
{
x1 <- pointsv[1]
y1 <- pointsv[2]
x2 <- pointsv[3]
y2 <- pointsv[4]
return(sqrt((x1 - x2)^2 + (y1 - y2)^2))
}
pairstocompare <- t(combn(length(x),2))
pointsv <- cbind(x[pairstocompare[,1]],y[pairstocompare[,1]],x[pairstocompare[,2]],y[pairstocompare[,2]])
pairstocompare <- cbind(pairstocompare,apply(pointsv,1,distancev))
minrow <- pairstocompare[pairstocompare[,3] == min(pairstocompare[,3])]
if (!is.null(nrow(minrow))) {print("More than one point at this distance!"); minrow <- minrow[1,]}
cat("The closest pair is:\n\tPoint 1: ",x[minrow[1]],", ",y[minrow[1]],
"\n\tPoint 2: ",x[minrow[2]],", ",y[minrow[2]],
"\n\tDistance: ",minrow[3],"\n",sep="")
return(as.list(c(closest=minrow[3],x1=x[minrow[1]],y1=y[minrow[1]],x2=x[minrow[2]],y2=y[minrow[2]])))
}


This is a version that makes use of the 'dist' function of R. It takes a two-column object of x,y-values as input, or creates such an object from seperate x and y-vectors.

closest.pairs <- function(x, y=NULL, ...){
# takes two-column object(x,y-values), or creates such an object from x and y values
if(!is.null(y)) x <- cbind(x, y)
 
distances <- dist(x)
min.dist <- min(distances)
point.pair <- combn(1:nrow(x), 2)[, which.min(distances)]
 
cat("The closest pair is:\n\t",
sprintf("Point 1: %.3f, %.3f \n\tPoint 2: %.3f, %.3f \n\tDistance: %.3f.\n",
x[point.pair[1],1], x[point.pair[1],2],
x[point.pair[2],1], x[point.pair[2],2],
min.dist),
sep="" )
return(list( "Point 1" = c( x[point.pair[1],1], x[point.pair[1],2]),
"Point 2" = c( x[point.pair[2],1], x[point.pair[2],2]),
"Distance" = min.dist))
}

[edit] Ruby

Point = Struct.new(:x, :y)
 
def distance(p1, p2)
Math.hypot(p1.x - p2.x, p1.y - p2.y)
end
 
def closest_bruteforce(points)
mindist, minpts = Float::MAX, []
points.length.times do |i|
(i+1).upto(points.length - 1) do |j|
dist = distance(points[i], points[j])
if dist < mindist
mindist = dist
minpts = [points[i], points[j]]
end
end
end
[mindist, minpts]
end
 
def closest_recursive(points)
if points.length <= 3
return closest_bruteforce(points)
end
xP = points.sort_by {|p| p.x}
mid = (points.length / 2.0).ceil
pL = xP[0,mid]
pR = xP[mid..-1]
dL, pairL = closest_recursive(pL)
dR, pairR = closest_recursive(pR)
if dL < dR
dmin, dpair = dL, pairL
else
dmin, dpair = dR, pairR
end
yP = xP.find_all {|p| (pL[-1].x - p.x).abs < dmin}.sort_by {|p| p.y}
closest = Float::MAX
closestPair = []
0.upto(yP.length - 2) do |i|
(i+1).upto(yP.length - 1) do |k|
break if (yP[k].y - yP[i].y) >= dmin
dist = distance(yP[i], yP[k])
if dist < closest
closest = dist
closestPair = [yP[i], yP[k]]
end
end
end
if closest < dmin
[closest, closestPair]
else
[dmin, dpair]
end
end
 
 
points = Array.new(100) {Point.new(rand, rand)}
p ans1 = closest_bruteforce(points)
p ans2 = closest_recursive(points)
fail "bogus!" if ans1[0] != ans2[0]
 
require 'benchmark'
 
points = Array.new(10000) {Point.new(rand, rand)}
Benchmark.bm(12) do |x|
x.report("bruteforce") {ans1 = closest_bruteforce(points)}
x.report("recursive") {ans2 = closest_recursive(points)}
end
[0.00522229060545241, [#<struct Point x=0.43887011964135, y=0.00656904813877568>, #<struct Point x=0.433711197400243, y=0.00575797448120408>]]
[0.00522229060545241, [#<struct Point x=0.433711197400243, y=0.00575797448120408>, #<struct Point x=0.43887011964135, y=0.00656904813877568>]]
                  user     system      total        real
bruteforce  133.437000   0.000000 133.437000 (134.633000)
recursive     0.516000   0.000000   0.516000 (  0.559000)

[edit] Scala

import scala.util._
 
object ClosestPair{
class Point(x:Double, y:Double) extends Pair(x,y){
def distance(p:Point)=math.hypot(_1-p._1, _2-p._2)
}
 
def closestPairBF(a:Array[Point])={
var minDist=a(0) distance a(1)
var minPoints=(a(0), a(1))
 
for(p1<-a; p2<-a if p1.ne(p2); dist=p1 distance p2 if(dist<minDist)){
minDist=dist;
minPoints=(p1, p2)
}
(minPoints, minDist)
}
 
def main(args: Array[String]): Unit = {
val a=Array.fill(1000)(new Point(Random.nextDouble, Random.nextDouble))
val (points, dist)=closestPairBF(a)
println("min: "+points._1+" - "+points._2+" ->"+dist)
}
}

[edit] Seed7

This is the brute force algorithm:

const type: point is new struct
var float: x is 0.0;
var float: y is 0.0;
end struct;
 
const func float: distance (in point: p1, in point: p2) is
return sqrt((p1.x-p2.x)**2+(p1.y-p2.y)**2);
 
const func array point: closest_pair (in array point: points) is func
result
var array point: result is 0 times point.value;
local
var float: dist is 0.0;
var float: minDistance is Infinity;
var integer: i is 0;
var integer: j is 0;
var integer: savei is 0;
var integer: savej is 0;
begin
for i range 1 to pred(length(points)) do
for j range succ(i) to length(points) do
dist := distance(points[i], points[j]);
if dist < minDistance then
minDistance := dist;
savei := i;
savej := j;
end if;
end for;
end for;
if minDistance <> Infinity then
result := [] (points[savei], points[savej]);
end if;
end func;

[edit] Smalltalk

See Closest pair problem/Smalltalk

[edit] Tcl

Each point is represented as a list of two floating-point numbers, the first being the x coordinate, and the second being the y.

package require Tcl 8.5
 
# retrieve the x-coordinate
proc x p {lindex $p 0}
# retrieve the y-coordinate
proc y p {lindex $p 1}
 
proc distance {p1 p2} {
expr {hypot(([x $p1]-[x $p2]), ([y $p1]-[y $p2]))}
}
 
proc closest_bruteforce {points} {
set n [llength $points]
set mindist Inf
set minpts {}
for {set i 0} {$i < $n - 1} {incr i} {
for {set j [expr {$i + 1}]} {$j < $n} {incr j} {
set p1 [lindex $points $i]
set p2 [lindex $points $j]
set dist [distance $p1 $p2]
if {$dist < $mindist} {
set mindist $dist
set minpts [list $p1 $p2]
}
}
}
return [list $mindist $minpts]
}
 
proc closest_recursive {points} {
set n [llength $points]
if {$n <= 3} {
return [closest_bruteforce $points]
}
set xP [lsort -real -increasing -index 0 $points]
set mid [expr {int(ceil($n/2.0))}]
set PL [lrange $xP 0 [expr {$mid-1}]]
set PR [lrange $xP $mid end]
set procname [lindex [info level 0] 0]
lassign [$procname $PL] dL pairL
lassign [$procname $PR] dR pairR
if {$dL < $dR} {
set dmin $dL
set dpair $pairL
} else {
set dmin $dR
set dpair $pairR
}
 
set xM [x [lindex $PL end]]
foreach p $xP {
if {abs($xM - [x $p]) < $dmin} {
lappend S $p
}
}
set yP [lsort -real -increasing -index 1 $S]
set closest Inf
set nP [llength $yP]
for {set i 0} {$i <= $nP-2} {incr i} {
set yPi [lindex $yP $i]
for {set k [expr {$i+1}]; set yPk [lindex $yP $k]} {
$k < $nP-1 && ([y $yPk]-[y $yPi]) < $dmin
} {incr k; set yPk [lindex $yP $k]} {
set dist [distance $yPk $yPi]
if {$dist < $closest} {
set closest $dist
set closestPair [list $yPi $yPk]
}
}
}
expr {$closest < $dmin ? [list $closest $closestPair] : [list $dmin $dpair]}
}
 
# testing
set N 10000
for {set i 1} {$i <= $N} {incr i} {
lappend points [list [expr {rand()*100}] [expr {rand()*100}]]
}
 
# instrument the number of calls to [distance] to examine the
# efficiency of the recursive solution
trace add execution distance enter comparisons
proc comparisons args {incr ::comparisons}
 
puts [format "%-10s  %9s  %9s  %s" method compares time closest]
foreach method {bruteforce recursive} {
set ::comparisons 0
set time [time {set ::dist($method) [closest_$method $points]} 1]
puts [format "%-10s  %9d  %9d  %s" $method $::comparisons [lindex $time 0] [lindex $::dist($method) 0]]
}

Example output

method      compares      time closest
bruteforce  49995000 512967207 0.0015652738546658382
recursive      14613    488094 0.0015652738546658382

Note that the lindex and llength commands are both O(1).

[edit] Ursala

The brute force algorithm is easy. Reading from left to right, clop is defined as a function that forms the Cartesian product of its argument, and then extracts the member whose left side is a minimum with respect to the floating point comparison relation after deleting equal pairs and attaching to the left of each remaining pair the sum of the squares of the differences between corresponding coordinates.

#import flo
 
clop = @iiK0 fleq$-&l+ *EZF ^\~& plus+ sqr~~+ minus~~bbI

The divide and conquer algorithm following the specification given above is a little more hairy but not much longer. The eudist library function is used to compute the distance between points.

#import std
#import flo
 
clop =
 
^(fleq-<&l,fleq-<&r); @blrNCCS ~&lrbhthPX2X+ ~&a^& fleq$-&l+ leql/8?al\^(eudist,~&)*altK33htDSL -+
^C/~&rr ^(eudist,~&)*tK33htDSL+ @rlrlPXPlX ~| fleq^\~&lr abs+ minus@llPrhPX,
^/~&ar @farlK30K31XPGbrlrjX3J ^/~&arlhh @W lesser fleq@bl+-

test program:

test_data =
 
<
(1.547290e+00,3.313053e+00),
(5.250805e-01,-7.300260e+00),
(7.062114e-02,1.220251e-02),
(-4.473024e+00,-5.393712e+00),
(-2.563714e+00,-3.595341e+00),
(-2.132372e+00,2.358850e+00),
(2.366238e+00,-9.678425e+00),
(-1.745694e+00,3.276434e+00),
(8.066843e+00,-9.101268e+00),
(-8.256901e+00,-8.717900e+00),
(7.397744e+00,-5.366434e+00),
(2.060291e-01,2.840891e+00),
(-6.935319e+00,-5.192438e+00),
(9.690418e+00,-9.175753e+00),
(3.448993e+00,2.119052e+00),
(-7.769218e+00,4.647406e-01)>
 
#cast %eeWWA
 
example = clop test_data

The output shows the minimum distance and the two points separated by that distance. (If the brute force algorithm were used, it would have displayed the square of the distance.)

9.957310e-01: (
   (-2.132372e+00,2.358850e+00),
   (-1.745694e+00,3.276434e+00))
Personal tools
Support