2016 Update

This commit is contained in:
Tina Müller 2016-12-05 22:15:40 +01:00
parent 948b86eafa
commit dcf5d15da3
7965 changed files with 139854 additions and 31002 deletions

View file

@ -1,9 +1,10 @@
{{Wikipedia|Closest pair of points problem}}
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 [[wp:Closest pair of points problem|Closest pair of points problem]] in the ''planar'' case.
The straightforward solution is a O(n<sup>2</sup>) algorithm
(which we can call ''brute-force algorithm'');
the pseudocode (using indexes) could be simply:
;Task:
Provide a function to find the closest two points among a set of given points in two dimensions, &nbsp; i.e. to solve the &nbsp; [[wp:Closest pair of points problem|Closest pair of points problem]] &nbsp; in the &nbsp; ''planar'' &nbsp; case.
The straightforward solution is a &nbsp; O(n<sup>2</sup>) &nbsp; algorithm &nbsp; (which we can call ''brute-force algorithm''); &nbsp; the pseudo-code (using indexes) could be simply:
'''bruteForceClosestPair''' of P(1), P(2), ... P(N)
'''if''' N &lt; 2 '''then'''
@ -22,9 +23,7 @@ the pseudocode (using indexes) could be simply:
'''return''' minDistance, minPoints
'''endif'''
A better algorithm is based on the recursive divide&amp;conquer approach,
as explained also at [[wp:Closest pair of points problem#Planar_case|Wikipedia]],
which is O(''n'' log ''n''); a pseudocode could be:
A better algorithm is based on the recursive divide&amp;conquer approach, &nbsp; as explained also at &nbsp; [[wp:Closest pair of points problem#Planar_case|Wikipedia's Closest pair of points problem]], &nbsp; which is &nbsp; O(''n'' log ''n''); &nbsp; a pseudo-code could be:
'''closestPair''' of (xP, yP)
where xP is P(1) .. P(N) sorted by x coordinate, and
@ -59,9 +58,10 @@ which is O(''n'' log ''n''); a pseudocode could be:
'''endif'''
'''References and further readings'''
* [[wp:Closest pair of points problem|Closest pair of points problem]]
* [http://www.cs.mcgill.ca/~cs251/ClosestPair/ClosestPairDQ.html Closest Pair (McGill)]
* [http://www.cs.ucsb.edu/~suri/cs235/ClosestPair.pdf Closest Pair (UCSB)]
* [http://classes.cec.wustl.edu/~cse241/handouts/closestpair.pdf Closest pair (WUStL)]
* [http://www.cs.iupui.edu/~xkzou/teaching/CS580/Divide-and-conquer-closestPair.ppt Closest pair (IUPUI)]
;References and further readings:
* &nbsp; [[wp:Closest pair of points problem|Closest pair of points problem]]
* &nbsp; [http://www.cs.mcgill.ca/~cs251/ClosestPair/ClosestPairDQ.html Closest Pair (McGill)]
* &nbsp; [http://www.cs.ucsb.edu/~suri/cs235/ClosestPair.pdf Closest Pair (UCSB)]
* &nbsp; [http://classes.cec.wustl.edu/~cse241/handouts/closestpair.pdf Closest pair (WUStL)]
* &nbsp; [http://www.cs.iupui.edu/~xkzou/teaching/CS580/Divide-and-conquer-closestPair.ppt Closest pair (IUPUI)]
<br><br>

View file

@ -1,19 +1,47 @@
defmodule Closest_pair do
def bruteForce([p0,p1|_] = points) do
pnts = List.to_tuple(points)
minDist = distance(p0, p1)
n = tuple_size(pnts)
{minDistance, minPoints} = Enum.reduce(0..n-2, {minDist, [0,1]}, fn i,{mD,mP} ->
Enum.reduce(i+1..n-1, {mD,mP}, fn j,{md,mp} ->
dist = distance(elem(pnts,i), elem(pnts,j))
if dist < md, do: {dist, [i,j]}, else: {md,mp}
end)
end)
{:math.sqrt(minDistance), minPoints}
# brute-force algorithm:
def bruteForce([p0,p1|_] = points), do: bf_loop(points, {distance(p0, p1), {p0, p1}})
defp bf_loop([_], acc), do: acc
defp bf_loop([h|t], acc), do: bf_loop(t, bf_loop(h, t, acc))
defp bf_loop(_, [], acc), do: acc
defp bf_loop(p0, [p1|t], {minD, minP}) do
dist = distance(p0, p1)
if dist < minD, do: bf_loop(p0, t, {dist, {p0, p1}}),
else: bf_loop(p0, t, {minD, minP})
end
defp distance({p0x,p0y}, {p1x,p1y}) do
(p1x - p0x) * (p1x - p0x) + (p1y - p0y) * (p1y - p0y)
:math.sqrt( (p1x - p0x) * (p1x - p0x) + (p1y - p0y) * (p1y - p0y) )
end
# recursive divide&conquer approach:
def recursive(points) do
recursive(Enum.sort(points), Enum.sort_by(points, fn {_x,y} -> y end))
end
def recursive(xP, _yP) when length(xP) <= 3, do: bruteForce(xP)
def recursive(xP, yP) do
{xL, xR} = Enum.split(xP, div(length(xP), 2))
{xm, _} = hd(xR)
{yL, yR} = Enum.partition(yP, fn {x,_} -> x < xm end)
{dL, pairL} = recursive(xL, yL)
{dR, pairR} = recursive(xR, yR)
{dmin, pairMin} = if dL<dR, do: {dL, pairL}, else: {dR, pairR}
yS = Enum.filter(yP, fn {x,_} -> abs(xm - x) < dmin end)
merge(yS, {dmin, pairMin})
end
defp merge([_], acc), do: acc
defp merge([h|t], acc), do: merge(t, merge_loop(h, t, acc))
defp merge_loop(_, [], acc), do: acc
defp merge_loop(p0, [p1|_], {dmin,_}=acc) when dmin <= elem(p1,1) - elem(p0,1), do: acc
defp merge_loop(p0, [p1|t], {dmin, pair}) do
dist = distance(p0, p1)
if dist < dmin, do: merge_loop(p0, t, {dist, {p0, p1}}),
else: merge_loop(p0, t, {dmin, pair})
end
end
@ -22,3 +50,10 @@ data = [{0.654682, 0.925557}, {0.409382, 0.619391}, {0.891663, 0.888594}, {0.716
{0.293786, 0.691701}, {0.839186, 0.728260}]
IO.inspect Closest_pair.bruteForce(data)
IO.inspect Closest_pair.recursive(data)
data2 = for _ <- 1..5000, do: {:rand.uniform, :rand.uniform}
IO.puts "\nBrute-force:"
IO.inspect :timer.tc(fn -> Closest_pair.bruteForce(data2) end)
IO.puts "Recursive divide&conquer:"
IO.inspect :timer.tc(fn -> Closest_pair.recursive(data2) end)

View file

@ -4,6 +4,7 @@ import (
"fmt"
"math"
"math/rand"
"time"
)
type xy struct {
@ -11,18 +12,17 @@ type xy struct {
}
const n = 1000
const scale = 1.
const scale = 100.
func d(p1, p2 xy) float64 {
dx := p2.x - p1.x
dy := p2.y - p1.y
return math.Sqrt(dx*dx + dy*dy)
return math.Hypot(p2.x-p1.x, p2.y-p1.y)
}
func main() {
rand.Seed(time.Now().Unix())
points := make([]xy, n)
for i := range points {
points[i] = xy{rand.Float64(), rand.Float64() * scale}
points[i] = xy{rand.Float64() * scale, rand.Float64() * scale}
}
p1, p2 := closestPair(points)
fmt.Println(p1, p2)

View file

@ -6,6 +6,7 @@ import (
"fmt"
"math"
"math/rand"
"time"
)
// number of points to search for closest pair
@ -13,7 +14,7 @@ const n = 1e6
// size of bounding box for points.
// x and y will be random with uniform distribution in the range [0,scale).
const scale = 1.
const scale = 100.
// point struct
type xy struct {
@ -21,17 +22,15 @@ type xy struct {
key int64 // an annotation used in the algorithm
}
// Euclidian distance
func d(p1, p2 xy) float64 {
dx := p2.x - p1.x
dy := p2.y - p1.y
return math.Sqrt(dx*dx + dy*dy)
return math.Hypot(p2.x-p1.x, p2.y-p1.y)
}
func main() {
rand.Seed(time.Now().Unix())
points := make([]xy, n)
for i := range points {
points[i] = xy{rand.Float64(), rand.Float64() * scale, 0}
points[i] = xy{rand.Float64() * scale, rand.Float64() * scale, 0}
}
p1, p2 := closestPair(points)
fmt.Println(p1, p2)
@ -64,14 +63,14 @@ func closestPair(s []xy) (p1, p2 xy) {
mx := int64(scale*invB) + 1 // mx is number of cells along a side
// construct map as a histogram:
// key is index into mesh. value is count of points in cell
hm := make(map[int64]int)
hm := map[int64]int{}
for ip, p := range s1 {
key := int64(p.x*invB)*mx + int64(p.y*invB)
s1[ip].key = key
hm[key]++
}
// construct s2 = s1 less the points without neighbors
var s2 []xy
s2 := make([]xy, 0, len(s1))
nx := []int64{-mx - 1, -mx, -mx + 1, -1, 0, 1, mx - 1, mx, mx + 1}
for i, p := range s1 {
nn := 0
@ -93,7 +92,7 @@ func closestPair(s []xy) (p1, p2 xy) {
// step 4: compute answer from approximation
invB := 1 / dxi
mx := int64(scale*invB) + 1
hm := make(map[int64][]int)
hm := map[int64][]int{}
for i, p := range s {
key := int64(p.x*invB)*mx + int64(p.y*invB)
s[i].key = key

View file

@ -1,4 +1,4 @@
vecl =: +/"1&.:*: NB. length of each of vectors
vecl =: +/"1&.:*: NB. length of each vector
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

View file

@ -0,0 +1,67 @@
program closestPoints;
{$IFDEF FPC}
{$MODE Delphi}
{$ENDIF}
const
PointCnt = 10000;//31623;
type
TdblPoint = Record
ptX,
ptY : double;
end;
tPtLst = array of TdblPoint;
tMinDIstIdx = record
md1,
md2 : NativeInt;
end;
function ClosPointBruteForce(var ptl :tPtLst):tMinDIstIdx;
Var
i,j,k : NativeInt;
mindst2,dst2: double; //square of distance, no need to sqrt
p0,p1 : ^TdblPoint; //using pointer, since calc of ptl[?] takes much time
Begin
i := Low(ptl);
j := High(ptl);
result.md1 := i;result.md2 := j;
mindst2 := sqr(ptl[i].ptX-ptl[j].ptX)+sqr(ptl[i].ptY-ptl[j].ptY);
repeat
p0 := @ptl[i];
p1 := p0; inc(p1);
For k := i+1 to j do
Begin
dst2:= sqr(p0^.ptX-p1^.ptX)+sqr(p0^.ptY-p1^.ptY);
IF mindst2 > dst2 then
Begin
mindst2 := dst2;
result.md1 := i;
result.md2 := k;
end;
inc(p1);
end;
inc(i);
until i = j;
end;
var
PointLst :tPtLst;
cloPt : tMinDIstIdx;
i : NativeInt;
Begin
randomize;
setlength(PointLst,PointCnt);
For i := 0 to PointCnt-1 do
with PointLst[i] do
Begin
ptX := random;
ptY := random;
end;
cloPt:= ClosPointBruteForce(PointLst) ;
i := cloPt.md1;
Writeln('P[',i:4,']= x: ',PointLst[i].ptX:0:8,
' y: ',PointLst[i].ptY:0:8);
i := cloPt.md2;
Writeln('P[',i:4,']= x: ',PointLst[i].ptX:0:8,
' y: ',PointLst[i].ptY:0:8);
end.

View file

@ -1,33 +1,32 @@
/*REXX program solves the closest pair of points problem in two dimensions.*/
parse arg N low high seed . /*obtain optional arguments from the CL*/
if N=='' | N==',' then N=100 /*Not specified? Then use the default.*/
if low=='' | low==',' then low=0 /* " " " " " " */
if high=='' |high==',' then high=20000 /* " " " " " " */
if datatype(seed,'W') then call random ,,seed /*seed for RANDOM repeatable.*/
/*REXX program solves the closest pair of points problem (in two dimensions). */
parse arg N low high seed . /*obtain optional arguments from the CL*/
if N=='' | N=="," then N= 100 /*Not specified? Then use the default.*/
if low=='' | low=="," then low= 0 /* " " " " " " */
if high=='' | high=="," then high=20000 /* " " " " " " */
if datatype(seed,'W') then call random ,,seed /*seed for RANDOM (BIF) repeatability.*/
w=length(high); w=w + (w//2==0)
/*╔══════════════════════╗*/ do j=1 for N /*generate N random points. */
/*║ generate N points. ║*/ @x.j=random(low,high) /*a random X. */
/*╚══════════════════════╝*/ @y.j=random(low,high) /*" " Y. */
end /*j*/
A=1; B=2
minDD=(@x.A-@x.B)**2 + (@y.A-@y.B)**2 /*distance between first two points. */
/*╔══════════════════════╗*/ do j=1 for N /*generate N random points.*/
/*║ generate N points. ║*/ @x.j=random(low,high) /* " a random X. */
/*╚══════════════════════╝*/ @y.j=random(low,high) /* " " " Y. */
end /*j*/ /*X and Y make the point*/
A=1; B=2 /* [↓] MINDD is actually the unsquared*/
minDD=(@x.A-@x.B)**2 + (@y.A-@y.B)**2 /*distance between the first two points*/
/* [↓] use of XJ & YJ speed things up.*/
do j=1 for N-1; xj=@x.j; yj=@y.j /*find minimum distance between a ··· */
do k=j+1 to N /* ··· point and all the other points.*/
dd=(xj - @x.k)**2 + (yj - @y.k)**2 /*compute squared distance from points.*/
if dd<minDD then if dd\=0 then parse value dd j k with minDD A B
end /*k*/ /* [↑] needn't take SQRT of DD (yet).*/
end /*j*/ /* [↑] when done, A & B are the ones*/
do j=1 for N-1 /*find minimum distance between a ··· */
do k=j+1 to N /* ··· point and all the other points.*/
dd=(@x.j - @x.k)**2 + (@y.j - @y.k)**2
if dd\=0 then if dd<minDD then do; minDD=dd; A=j; B=k; end
end /*k*/
end /*j*/ /* [↑] when done, A & B are the ones*/
_= 'For ' N " points, the minimum distance between the two points: "
say _ center("x",w,'')" " center('y',w,"") ' is: ' sqrt(abs(minDD))
say left('', length(_)-1) '['right(@x.A, w)"," right(@y.A, w)"]"
say left('', length(_)-1) '['right(@x.B, w)"," right(@y.B, w)"]"
exit /*stick a fork in it, we're all done. */
/*────────────────────────────────────────────────────────────────────────────*/
sqrt: procedure; parse arg x; if x=0 then return 0; d=digits(); i=; m.=9
numeric digits 9; numeric form; h=d+6; if x<0 then do; x=-x; i='i'; end
parse value format(x,2,1,,0) 'E0' with g 'E' _ .; g=g*.5'e'_%2
do j=0 while h>9; m.j=h; h=h%2+1; end /*j*/
do k=j+5 to 0 by -1; numeric digits m.k; g=(g+x/g)*.5; end /*k*/
numeric digits d; return (g/1)i /*make complex if X < 0.*/
_= 'For ' N " points, the minimum distance between the two points: "
say _ center("x", w, '')" " center('y', w, "") ' is: ' sqrt(abs(minDD))/1
say left('', length(_)-1) "["right(@x.A, w)',' right(@y.A, w)"]"
say left('', length(_)-1) "["right(@x.B, w)',' right(@y.B, w)"]"
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
sqrt: procedure; parse arg x; if x=0 then return 0; d=digits(); m.=9; numeric form; h=d+6
numeric digits; parse value format(x,2,1,,0) 'E0' with g 'E' _ .; g=g *.5'e'_ % 2
do j=0 while h>9; m.j=h; h=h%2+1; end /*j*/
do k=j+5 to 0 by -1; numeric digits m.k; g=(g+x/g)*.5; end /*k*/
return g

View file

@ -0,0 +1,23 @@
10 DIM x(10): DIM y(10)
20 FOR i=1 TO 10
30 READ x(i),y(i)
40 NEXT i
50 LET min=1e30
60 FOR i=1 TO 9
70 FOR j=i+1 TO 10
80 LET p1=x(i)-x(j): LET p2=y(i)-y(j): LET dsq=p1*p1+p2*p2
90 IF dsq<min THEN LET min=dsq: LET mini=i: LET minj=j
100 NEXT j
110 NEXT i
120 PRINT "Closest pair is ";mini;" and ";minj;" at distance ";SQR min
130 STOP
140 DATA 0.654682,0.925557
150 DATA 0.409382,0.619391
160 DATA 0.891663,0.888594
170 DATA 0.716629,0.996200
180 DATA 0.477721,0.946355
190 DATA 0.925092,0.818220
200 DATA 0.624291,0.142924
210 DATA 0.211332,0.221507
220 DATA 0.293786,0.691701
230 DATA 0.839186,0.728260