This commit is contained in:
Ingy döt Net 2013-04-10 21:29:02 -07:00
parent 764da6cbbb
commit db842d013d
19005 changed files with 197040 additions and 7 deletions

View file

@ -0,0 +1,118 @@
class Point
{
Float x
Float y
// create a random point
new make (Float x := Float.random * 10, Float y := Float.random * 10)
{
this.x = x
this.y = y
}
Float distance (Point p)
{
((x-p.x)*(x-p.x) + (y-p.y)*(y-p.y)).sqrt
}
override Str toStr () { "($x, $y)" }
}
class Main
{
// use brute force approach
static Point[] findClosestPair1 (Point[] points)
{
if (points.size < 2) return points // list too small
Point[] closestPair := [points[0], points[1]]
Float closestDistance := points[0].distance(points[1])
(1..<points.size).each |Int i|
{
((i+1)..<points.size).each |Int j|
{
Float trydistance := points[i].distance(points[j])
if (trydistance < closestDistance)
{
closestPair = [points[i], points[j]]
closestDistance = trydistance
}
}
}
return closestPair
}
// use recursive divide-and-conquer approach
static Point[] findClosestPair2 (Point[] points)
{
if (points.size <= 3) return findClosestPair1(points)
points.sort |Point a, Point b -> Int| { a.x <=> b.x }
bestLeft := findClosestPair2 (points[0..(points.size/2)])
bestRight := findClosestPair2 (points[(points.size/2)..-1])
Float minDistance
Point[] closePoints := [,]
if (bestLeft[0].distance(bestLeft[1]) < bestRight[0].distance(bestRight[1]))
{
minDistance = bestLeft[0].distance(bestLeft[1])
closePoints = bestLeft
}
else
{
minDistance = bestRight[0].distance(bestRight[1])
closePoints = bestRight
}
yPoints := points.findAll |Point p -> Bool|
{
(points.last.x - p.x).abs < minDistance
}.sort |Point a, Point b -> Int| { a.y <=> b.y }
closestPair := [,]
closestDist := Float.posInf
for (Int i := 0; i < yPoints.size - 1; ++i)
{
for (Int j := (i+1); j < yPoints.size; ++j)
{
if ((yPoints[j].y - yPoints[i].y) >= minDistance)
{
break
}
else
{
dist := yPoints[i].distance (yPoints[j])
if (dist < closestDist)
{
closestDist = dist
closestPair = [yPoints[i], yPoints[j]]
}
}
}
}
if (closestDist < minDistance)
return closestPair
else
return closePoints
}
public static Void main (Str[] args)
{
Int numPoints := 10 // default value, in case a number not given on command line
if ((args.size > 0) && (args[0].toInt(10, false) != null))
{
numPoints = args[0].toInt(10, false)
}
Point[] points := [,]
numPoints.times { points.add (Point()) }
Int t1 := Duration.now.toMillis
echo (findClosestPair1(points.dup))
Int t2 := Duration.now.toMillis
echo ("Time taken: ${(t2-t1)}ms")
echo (findClosestPair2(points.dup))
Int t3 := Duration.now.toMillis
echo ("Time taken: ${(t3-t2)}ms")
}
}

View file

@ -0,0 +1,6 @@
class Point {
final Number x, y
Point(Number x = 0, Number y = 0) { this.x = x; this.y = y }
Number distance(Point that) { ((this.x - that.x)**2 + (this.y - that.y)**2)**0.5 }
String toString() { "{x:${x}, y:${y}}" }
}

View file

@ -0,0 +1,23 @@
def bruteClosest(Collection pointCol) {
assert pointCol
List l = pointCol
int n = l.size()
assert n > 1
if (n == 2) return [distance:l[0].distance(l[1]), points:[l[0],l[1]]]
def answer = [distance: Double.POSITIVE_INFINITY]
(0..<(n-1)).each { i ->
((i+1)..<n).findAll { j ->
(l[i].x - l[j].x).abs() < answer.distance &&
(l[i].y - l[j].y).abs() < answer.distance
}.each { j ->
if ((l[i].x - l[j].x).abs() < answer.distance &&
(l[i].y - l[j].y).abs() < answer.distance) {
def dist = l[i].distance(l[j])
if (dist < answer.distance) {
answer = [distance:dist, points:[l[i],l[j]]]
}
}
}
}
answer
}

View file

@ -0,0 +1,48 @@
def elegantClosest(Collection pointCol) {
assert pointCol
List xList = (pointCol as List).sort { it.x }
List yList = xList.clone().sort { it.y }
reductionClosest(xList, xList)
}
def reductionClosest(List xPoints, List yPoints) {
// assert xPoints && yPoints
// assert (xPoints as Set) == (yPoints as Set)
int n = xPoints.size()
if (n < 10) return bruteClosest(xPoints)
int nMid = Math.ceil(n/2)
List xLeft = xPoints[0..<nMid]
List xRight = xPoints[nMid..<n]
Number xMid = xLeft[-1].x
List yLeft = yPoints.findAll { it.x <= xMid }
List yRight = yPoints.findAll { it.x > xMid }
if (xRight[0].x == xMid) {
yLeft = xLeft.collect{ it }.sort { it.y }
yRight = xRight.collect{ it }.sort { it.y }
}
Map aLeft = reductionClosest(xLeft, yLeft)
Map aRight = reductionClosest(xRight, yRight)
Map aMin = aRight.distance < aLeft.distance ? aRight : aLeft
List yMid = yPoints.findAll { (xMid - it.x).abs() < aMin.distance }
int nyMid = yMid.size()
if (nyMid < 2) return aMin
Map answer = aMin
(0..<(nyMid-1)).each { i ->
((i+1)..<nyMid).findAll { j ->
(yMid[j].x - yMid[i].x).abs() < aMin.distance &&
(yMid[j].y - yMid[i].y).abs() < aMin.distance &&
yMid[j].distance(yMid[i]) < aMin.distance
}.each { k ->
if ((yMid[k].x - yMid[i].x).abs() < answer.distance && (yMid[k].y - yMid[i].y).abs() < answer.distance) {
def ikDist = yMid[i].distance(yMid[k])
if ( ikDist < answer.distance) {
answer = [distance:ikDist, points:[yMid[i],yMid[k]]]
}
}
}
}
answer
}

View file

@ -0,0 +1,28 @@
def random = new Random()
(1..4).each {
def point10 = (0..<(10**it)).collect { new Point(random.nextInt(1000001) - 500000,random.nextInt(1000001) - 500000) }
def startE = System.currentTimeMillis()
def closestE = elegantClosest(point10)
def elapsedE = System.currentTimeMillis() - startE
println """
${10**it} POINTS
-----------------------------------------
Elegant reduction:
elapsed: ${elapsedE/1000} s
closest: ${closestE}
"""
def startB = System.currentTimeMillis()
def closestB = bruteClosest(point10)
def elapsedB = System.currentTimeMillis() - startB
println """Brute force:
elapsed: ${elapsedB/1000} s
closest: ${closestB}
Speedup ratio (B/E): ${elapsedB/elapsedE}
=========================================
"""
}

View file

@ -0,0 +1,25 @@
record point(x,y)
procedure main()
minDist := 0
minPair := &null
every (points := [],p1 := readPoint()) do {
if *points == 1 then minDist := dSquared(p1,points[1])
every minDist >=:= dSquared(p1,p2 := !points) do minPair := [p1,p2]
push(points, p1)
}
if \minPair then {
write("(",minPair[1].x,",",minPair[1].y,") -> ",
"(",minPair[2].x,",",minPair[2].y,")")
}
else write("One or fewer points!")
end
procedure readPoint() # Skips lines that don't have two numbers on them
suspend !&input ? point(numeric(tab(upto(', '))), numeric((move(1),tab(0))))
end
procedure dSquared(p1,p2) # Compute the square of the distance
return (p2.x-p1.x)^2 + (p2.y-p1.y)^2 # (sufficient for closeness)
end

View file

@ -0,0 +1,4 @@
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

View file

@ -0,0 +1,17 @@
]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| |
+-----------------+---------+

View file

@ -0,0 +1,17 @@
]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| |
+------------------------------------+--------+

View file

@ -0,0 +1,41 @@
N =10
dim x( N), y( N)
firstPt =0
secondPt =0
for i =1 to N
read f: x( i) =f
read f: y( i) =f
next i
minDistance =1E6
for i =1 to N -1
for j =i +1 to N
dxSq =( x( i) -x( j))^2
dySq =( y( i) -y( j))^2
D =abs( ( dxSq +dySq)^0.5)
if D <minDistance then
minDistance =D
firstPt =i
secondPt =j
end if
next j
next i
print "Distance ="; minDistance; " between ( "; x( firstPt); ", "; y( firstPt); ") and ( "; x( secondPt); ", "; y( secondPt); ")"
end
data 0.654682, 0.925557
data 0.409382, 0.619391
data 0.891663, 0.888594
data 0.716629, 0.996200
data 0.477721, 0.946355
data 0.925092, 0.818220
data 0.624291, 0.142924
data 0.211332, 0.221507
data 0.293786, 0.691701
data 0.839186, 0.72826

View file

@ -0,0 +1,4 @@
nearestPair[data_] :=
Block[{pos, dist = N[Outer[EuclideanDistance, data, data, 1]]},
pos = Position[dist, Min[DeleteCases[Flatten[dist], 0.]]];
data[[pos[[1]]]]]