Just another update

This commit is contained in:
Ingy döt Net 2015-02-20 00:35:01 -05:00
parent a25938f123
commit 00a190b0a6
6591 changed files with 94363 additions and 23227 deletions

View file

@ -1,7 +1,9 @@
{{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:
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:
'''bruteForceClosestPair''' of P(1), P(2), ... P(N)
'''if''' N &lt; 2 '''then'''
@ -20,7 +22,9 @@ The straightforward solution is a O(n<sup>2</sup>) algorithm (which we can call
'''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,
as explained also at [[wp:Closest pair of points problem#Planar_case|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

View file

@ -0,0 +1,115 @@
/*
Author: Kevin Bacon
Date: 04/03/2014
Task: Closest-pair problem
*/
#include <iostream>
#include <vector>
#include <utility>
#include <cmath>
#include <random>
#include <chrono>
#include <algorithm>
#include <iterator>
typedef std::pair<double, double> point_t;
typedef std::pair<point_t, point_t> points_t;
double distance_between(const point_t& a, const point_t& b) {
return std::sqrt(std::pow(b.first - a.first, 2)
+ std::pow(b.second - a.second, 2));
}
std::pair<double, points_t> find_closest_brute(const std::vector<point_t>& points) {
if (points.size() < 2) {
return { -1, { { 0, 0 }, { 0, 0 } } };
}
auto minDistance = std::abs(distance_between(points.at(0), points.at(1)));
points_t minPoints = { points.at(0), points.at(1) };
for (auto i = std::begin(points); i != (std::end(points) - 1); ++i) {
for (auto j = i + 1; j < std::end(points); ++j) {
auto newDistance = std::abs(distance_between(*i, *j));
if (newDistance < minDistance) {
minDistance = newDistance;
minPoints.first = *i;
minPoints.second = *j;
}
}
}
return { minDistance, minPoints };
}
std::pair<double, points_t> find_closest_optimized(const std::vector<point_t>& xP,
const std::vector<point_t>& yP) {
if (xP.size() <= 3) {
return find_closest_brute(xP);
}
auto N = xP.size();
auto xL = std::vector<point_t>();
auto xR = std::vector<point_t>();
std::copy(std::begin(xP), std::begin(xP) + (N / 2), std::back_inserter(xL));
std::copy(std::begin(xP) + (N / 2), std::end(xP), std::back_inserter(xR));
auto xM = xP.at(N / 2).first;
auto yL = std::vector<point_t>();
auto yR = std::vector<point_t>();
std::copy_if(std::begin(yP), std::end(yP), std::back_inserter(yL), [&xM](const point_t& p) {
return p.first <= xM;
});
std::copy_if(std::begin(yP), std::end(yP), std::back_inserter(yR), [&xM](const point_t& p) {
return p.first > xM;
});
auto p1 = find_closest_optimized(xL, yL);
auto p2 = find_closest_optimized(xR, yR);
auto minPair = (p1.first <= p2.first) ? p1 : p2;
auto yS = std::vector<point_t>();
std::copy_if(std::begin(yP), std::end(yP), std::back_inserter(yS), [&minPair, &xM](const point_t& p) {
return std::abs(xM - p.first) < minPair.first;
});
auto result = minPair;
for (auto i = std::begin(yS); i != (std::end(yS) - 1); ++i) {
for (auto k = i + 1; k != std::end(yS) &&
((k->second - i->second) < minPair.first); ++k) {
auto newDistance = std::abs(distance_between(*k, *i));
if (newDistance < result.first) {
result = { newDistance, { *k, *i } };
}
}
}
return result;
}
void print_point(const point_t& point) {
std::cout << "(" << point.first
<< ", " << point.second
<< ")";
}
int main(int argc, char * argv[]) {
std::default_random_engine re(std::chrono::system_clock::to_time_t(
std::chrono::system_clock::now()));
std::uniform_real_distribution<double> urd(-500.0, 500.0);
std::vector<point_t> points(100);
std::generate(std::begin(points), std::end(points), [&urd, &re]() {
return point_t { 1000 + urd(re), 1000 + urd(re) };
});
auto answer = find_closest_brute(points);
std::sort(std::begin(points), std::end(points), [](const point_t& a, const point_t& b) {
return a.first < b.first;
});
auto xP = points;
std::sort(std::begin(points), std::end(points), [](const point_t& a, const point_t& b) {
return a.second < b.second;
});
auto yP = points;
std::cout << "Min distance (brute): " << answer.first << " ";
print_point(answer.second.first);
std::cout << ", ";
print_point(answer.second.second);
answer = find_closest_optimized(xP, yP);
std::cout << "\nMin distance (optimized): " << answer.first << " ";
print_point(answer.second.first);
std::cout << ", ";
print_point(answer.second.second);
return 0;
}

View file

@ -1,12 +1,9 @@
import std.stdio, std.typecons, std.math, std.algorithm,
std.random, std.traits, std.range, std.complex;
//auto bfClosestPair(T)(in T[] points) pure nothrow {
auto bruteForceClosestPair(T)(in T[] points) pure nothrow @nogc {
// return pairwise(points.length.iota, points.length.iota)
// .reduce!(min!((i, j) => abs(points[i] - points[j])));
//}
auto bruteForceClosestPair(T)(in T[] points) pure nothrow {
auto minD = Unqual!(typeof(T.re)).infinity;
T minI, minJ;
foreach (immutable i, const p1; points.dropBackOne)
@ -21,7 +18,7 @@ auto bruteForceClosestPair(T)(in T[] points) pure nothrow {
return tuple(minD, minI, minJ);
}
auto closestPair(T)(T[] points) /*pure nothrow*/ {
auto closestPair(T)(T[] points) pure nothrow {
static Tuple!(typeof(T.re), T, T) inner(in T[] xP, /*in*/ T[] yP)
pure nothrow {
if (xP.length <= 3)

View file

@ -2,7 +2,7 @@ import std.stdio, std.random, std.math, std.typecons, std.complex,
std.traits;
Nullable!(Tuple!(size_t, size_t))
bfClosestPair2(T)(in Complex!T[] points) pure nothrow {
bfClosestPair2(T)(in Complex!T[] points) pure nothrow @nogc {
auto minD = Unqual!(typeof(points[0].re)).infinity;
if (points.length < 2)
return typeof(return)();

View file

@ -1,37 +1,32 @@
/*REXX program to solve the closest pair problem. */
parse arg N low high seed .; if n=='' then n=100
if seed\=='' then call random ,,seed /*use seed, makes rand repeatable*/
if low=='' | low==',' then low=0
if high=='' | high==',' then high=20000
w=length(high); w=w + (w//2==0)
do j=1 for N /*gen random points*/
@.j.xx=random(low,high)
@.j.yy=random(low,high)
/*REXX program solves the closest pair of points problem in 2 dimensions*/
parse arg N low high seed . /*get optional arguments from CL.*/
if N=='' | N==',' then N=100 /*N not specified? Use default.*/
if low=='' | low==',' then low=0
if high=='' | high==',' then high=20000
if seed\==''& seed\==',' then call random ,,seed /*seed for repeatable.*/
w=length(high); w=w + (w//2==0)
/*╔══════════════════════╗*/ do j=1 for N /*gen N random pts.*/
/*║ generate N points. ║*/ @x.j=random(low,high) /*random X.*/
/*╚══════════════════════╝*/ @y.j=random(low,high) /* " Y.*/
end /*j*/
nearA=1
nearB=2
minDD=(@.nearA.xx-@.nearB.xx)**2 + (@.nearA.yy-@.nearB.yy)**2
A=1; B=2
minDD=(@x.A-@x.B)**2 + (@y.A-@y.B)**2 /*distance between 1st two points*/
do j=1 for N-1
do k=j+1 to N
dd=(@.j.xx-@.k.xx)**2 + (@.j.yy-@.k.yy)**2
if dd\=0 then if dd<minDD then do; minDD=dd
nearA=j
nearB=k
end
end /*k*/
end /*j*/
do j=1 for N-1 /*find min 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 it*/
say 'For' N "points:"; say
say ' 'center('x',w,"")' ' center('y',w,"")
say 'The points ['right(@.nearA.xx,w)"," right(@.nearA.yy,w)"]" ' and'
say ' ['right(@.nearB.xx,w)"," right(@.nearB.yy,w)"]"; say
say 'the minimum distance between them is: ' sqrt(abs(minDD))
_= '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 done.*/
/*───────────────────────────────────sqrt subroutine────────────────────*/
sqrt: procedure; parse arg x; if x=0 then return 0;d=digits();numeric digits 11
g=.sqrtG(); do j=0 while p>9; m.j=p; p=p%2+1; end
do k=j+5 to 0 by -1; if m.k>11 then numeric digits m.k; g=.5*(g+x/g); end
numeric digits d; return g/1
.sqrtG: numeric form; m.=11; p=d+d%4+2
parse value format(x,2,1,,0) 'E0' with g 'E' _ .; return g*.5'E'_%2
/*──────────────────────────────────SQRT subroutine───────────────────────*/
sqrt: procedure; parse arg x; if x=0 then return 0; d=digits(); numeric form
numeric digits 11;p=d+d%4+2;parse value format(x,2,1,,0) 'E0' with g 'E' _ .
g=g*.5'E'_%2; m.=11; do j=0 while p>9; m.j=p; p=p%2+1; end
do k=j+5 to 0 by -1; if m.k>11 then numeric digits m.k; g=.5*(g+x/g); end
numeric digits d; return g/1

View file

@ -6,36 +6,26 @@ 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
points.combination(2) do |pi,pj|
dist = distance(pi, pj)
if dist < mindist
mindist = dist
minpts = [pi, pj]
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 = []
return closest_bruteforce(points) if points.length <= 3
xP = points.sort_by(&:x)
mid = points.length / 2
xm = xP[mid].x
dL, pairL = closest_recursive(xP[0,mid])
dR, pairR = closest_recursive(xP[mid..-1])
dmin, dpair = dL<dR ? [dL, pairL] : [dR, pairR]
yP = xP.find_all {|p| (xm - p.x).abs < dmin}.sort_by(&:y)
closest, closestPair = dmin, dpair
0.upto(yP.length - 2) do |i|
(i+1).upto(yP.length - 1) do |k|
break if (yP[k].y - yP[i].y) >= dmin
@ -46,14 +36,9 @@ def closest_recursive(points)
end
end
end
if closest < dmin
[closest, closestPair]
else
[dmin, dpair]
end
[closest, closestPair]
end
points = Array.new(100) {Point.new(rand, rand)}
p ans1 = closest_bruteforce(points)
p ans2 = closest_recursive(points)

View file

@ -1,24 +1,133 @@
import scala.util._
import scala.collection.mutable.ListBuffer
import scala.util.Random
object ClosestPair{
class Point(x:Double, y:Double) extends Pair(x,y){
def distance(p:Point)=math.hypot(_1-p._1, _2-p._2)
}
object ClosestPair {
case class Point(x: Double, y: Double){
def distance(p: Point) = math.hypot(x-p.x, y-p.y)
def closestPairBF(a:Array[Point])={
var minDist=a(0) distance a(1)
var minPoints=(a(0), a(1))
override def toString = "(" + x + ", " + y + ")"
}
for(p1<-a; p2<-a if p1.ne(p2); dist=p1 distance p2 if(dist<minDist)){
minDist=dist;
minPoints=(p1, p2)
case class Pair(point1: Point, point2: Point) {
val distance: Double = point1 distance point2
override def toString = {
point1 + "-" + point2 + " : " + distance
}
}
def sortByX(points: List[Point]) = {
points.sortBy(point => point.x)
}
def sortByY(points: List[Point]) = {
points.sortBy(point => point.y)
}
def divideAndConquer(points: List[Point]): Pair = {
val pointsSortedByX = sortByX(points)
val pointsSortedByY = sortByY(points)
divideAndConquer(pointsSortedByX, pointsSortedByY)
}
def bruteForce(points: List[Point]): Pair = {
val numPoints = points.size
if (numPoints < 2)
return null
var pair = Pair(points(0), points(1))
if (numPoints > 2) {
for (i <- 0 until numPoints - 1) {
val point1 = points(i)
for (j <- i + 1 until numPoints) {
val point2 = points(j)
val distance = point1 distance point2
if (distance < pair.distance)
pair = Pair(point1, point2)
}
}
(minPoints, minDist)
}
}
return pair
}
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)
}
private def divideAndConquer(pointsSortedByX: List[Point], pointsSortedByY: List[Point]): Pair = {
val numPoints = pointsSortedByX.size
if(numPoints <= 3) {
return bruteForce(pointsSortedByX)
}
val dividingIndex = numPoints >>> 1
val leftOfCenter = pointsSortedByX.slice(0, dividingIndex)
val rightOfCenter = pointsSortedByX.slice(dividingIndex, numPoints)
var tempList = leftOfCenter.map(x => x)
//println(tempList)
tempList = sortByY(tempList)
var closestPair = divideAndConquer(leftOfCenter, tempList)
tempList = rightOfCenter.map(x => x)
tempList = sortByY(tempList)
val closestPairRight = divideAndConquer(rightOfCenter, tempList)
if (closestPairRight.distance < closestPair.distance)
closestPair = closestPairRight
tempList = List[Point]()
val shortestDistance = closestPair.distance
val centerX = rightOfCenter(0).x
for (point <- pointsSortedByY) {
if (Math.abs(centerX - point.x) < shortestDistance)
tempList = tempList :+ point
}
closestPair = shortestDistanceF(tempList, shortestDistance, closestPair)
closestPair
}
private def shortestDistanceF(tempList: List[Point], shortestDistance: Double, closestPair: Pair ): Pair = {
var shortest = shortestDistance
var bestResult = closestPair
for (i <- 0 until tempList.size) {
val point1 = tempList(i)
for (j <- i + 1 until tempList.size) {
val point2 = tempList(j)
if ((point2.y - point1.y) >= shortestDistance)
return closestPair
val distance = point1 distance point2
if (distance < closestPair.distance)
{
bestResult = Pair(point1, point2)
shortest = distance
}
}
}
closestPair
}
def main(args: Array[String]) {
val numPoints = if(args.length == 0) 1000 else args(0).toInt
val points = ListBuffer[Point]()
val r = new Random()
for (i <- 0 until numPoints) {
points.+=:(new Point(r.nextDouble(), r.nextDouble()))
}
println("Generated " + numPoints + " random points")
var startTime = System.currentTimeMillis()
val bruteForceClosestPair = bruteForce(points.toList)
var elapsedTime = System.currentTimeMillis() - startTime
println("Brute force (" + elapsedTime + " ms): " + bruteForceClosestPair)
startTime = System.currentTimeMillis()
val dqClosestPair = divideAndConquer(points.toList)
elapsedTime = System.currentTimeMillis() - startTime
println("Divide and conquer (" + elapsedTime + " ms): " + dqClosestPair)
if (bruteForceClosestPair.distance != dqClosestPair.distance)
println("MISMATCH")
}
}