Task: Closest-pair problem





Java: import java.util.*;

public class ClosestPair
{
  public static class Point
  {
    public final double x;
    public final double y;
    
    public Point(double x, double y)
    {
      this.x = x;
      this.y = y;
    }
    
    public String toString()
    {  return "(" + x + ", " + y + ")";  }
  }
  
  public static class Pair
  {
    public Point point1 = null;
    public Point point2 = null;
    public double distance = 0.0;
    
    public Pair()
    {  }
    
    public Pair(Point point1, Point point2)
    {
      this.point1 = point1;
      this.point2 = point2;
      calcDistance();
    }
    
    public void update(Point point1, Point point2, double distance)
    {
      this.point1 = point1;
      this.point2 = point2;
      this.distance = distance;
    }
    
    public void calcDistance()
    {  this.distance = distance(point1, point2);  }
    
    public String toString()
    {  return point1 + "-" + point2 + " : " + distance;  }
  }
  
  public static double distance(Point p1, Point p2)
  {
    double xdist = p2.x - p1.x;
    double ydist = p2.y - p1.y;
    return Math.hypot(xdist, ydist);
  }
  
  public static Pair bruteForce(List<? extends Point> points)
  {
    int numPoints = points.size();
    if (numPoints < 2)
      return null;
    Pair pair = new Pair(points.get(0), points.get(1));
    if (numPoints > 2)
    {
      for (int i = 0; i < numPoints - 1; i++)
      {
        Point point1 = points.get(i);
        for (int j = i + 1; j < numPoints; j++)
        {
          Point point2 = points.get(j);
          double distance = distance(point1, point2);
          if (distance < pair.distance)
            pair.update(point1, point2, distance);
        }
      }
    }
    return pair;
  }
  
  public static void sortByX(List<? extends Point> points)
  {
    Collections.sort(points, new Comparator<Point>() {
        public int compare(Point point1, Point point2)
        {
          if (point1.x < point2.x)
            return -1;
          if (point1.x > point2.x)
            return 1;
          return 0;
        }
      }
    );
  }
  
  public static void sortByY(List<? extends Point> points)
  {
    Collections.sort(points, new Comparator<Point>() {
        public int compare(Point point1, Point point2)
        {
          if (point1.y < point2.y)
            return -1;
          if (point1.y > point2.y)
            return 1;
          return 0;
        }
      }
    );
  }
  
  public static Pair divideAndConquer(List<? extends Point> points)
  {
    List<Point> pointsSortedByX = new ArrayList<Point>(points);
    sortByX(pointsSortedByX);
    List<Point> pointsSortedByY = new ArrayList<Point>(points);
    sortByY(pointsSortedByY);
    return divideAndConquer(pointsSortedByX, pointsSortedByY);
  }
  
  private static Pair divideAndConquer(List<? extends Point> pointsSortedByX, List<? extends Point> pointsSortedByY)
  {
    int numPoints = pointsSortedByX.size();
    if (numPoints <= 3)
      return bruteForce(pointsSortedByX);
    
    int dividingIndex = numPoints >>> 1;
    List<? extends Point> leftOfCenter = pointsSortedByX.subList(0, dividingIndex);
    List<? extends Point> rightOfCenter = pointsSortedByX.subList(dividingIndex, numPoints);
    
    List<Point> tempList = new ArrayList<Point>(leftOfCenter);
    sortByY(tempList);
    Pair closestPair = divideAndConquer(leftOfCenter, tempList);
    
    tempList.clear();
    tempList.addAll(rightOfCenter);
    sortByY(tempList);
    Pair closestPairRight = divideAndConquer(rightOfCenter, tempList);
    
    if (closestPairRight.distance < closestPair.distance)
      closestPair = closestPairRight;
    
    tempList.clear();
    double shortestDistance =closestPair.distance;
    double centerX = rightOfCenter.get(0).x;
    for (Point point : pointsSortedByY)
      if (Math.abs(centerX - point.x) < shortestDistance)
        tempList.add(point);
    
    for (int i = 0; i < tempList.size() - 1; i++)
    {
      Point point1 = tempList.get(i);
      for (int j = i + 1; j < tempList.size(); j++)
      {
        Point point2 = tempList.get(j);
        if ((point2.y - point1.y) >= shortestDistance)
          break;
        double distance = distance(point1, point2);
        if (distance < closestPair.distance)
        {
          closestPair.update(point1, point2, distance);
          shortestDistance = distance;
        }
      }
    }
    return closestPair;
  }
  
  public static void main(String[] args)
  {
    int numPoints = (args.length == 0) ? 1000 : Integer.parseInt(args[0]);
    List<Point> points = new ArrayList<Point>();
    Random r = new Random();
    for (int i = 0; i < numPoints; i++)
      points.add(new Point(r.nextDouble(), r.nextDouble()));
    System.out.println("Generated " + numPoints + " random points");
    long startTime = System.currentTimeMillis();
    Pair bruteForceClosestPair = bruteForce(points);
    long elapsedTime = System.currentTimeMillis() - startTime;
    System.out.println("Brute force (" + elapsedTime + " ms): " + bruteForceClosestPair);
    startTime = System.currentTimeMillis();
    Pair dqClosestPair = divideAndConquer(points);
    elapsedTime = System.currentTimeMillis() - startTime;
    System.out.println("Divide and conquer (" + elapsedTime + " ms): " + dqClosestPair);
    if (bruteForceClosestPair.distance != dqClosestPair.distance)
      System.out.println("MISMATCH");
  }
}







Ada: with Ada.Numerics.Generic_Elementary_Functions;
with Ada.Text_IO;

procedure Closest is
   package Math is new Ada.Numerics.Generic_Elementary_Functions (Float);

   Dimension : constant := 2;
   type Vector is array (1 .. Dimension) of Float;
   type Matrix is array (Positive range <>) of Vector;

   
   function Distance (Left, Right : Vector) return Float is
      Result : Float := 0.0;
      Offset : Natural := 0;
   begin
      loop
         Result := Result + (Left(Left'First + Offset) - Right(Right'First + Offset))**2;
         Offset := Offset + 1;
         exit when Offset >= Left'Length;
      end loop;
      return Math.Sqrt (Result);
   end Distance;

   
   function Get_Closest_Points (Cloud : Matrix) return Matrix is
      Result : Matrix (1..2);
      Min_Distance : Float;
   begin
      if Cloud'Length(1) < 2 then
         raise Constraint_Error;
      end if;
      Result := (Cloud (Cloud'First), Cloud (Cloud'First + 1));
      Min_Distance := Distance (Cloud (Cloud'First), Cloud (Cloud'First + 1));
      for I in Cloud'First (1) .. Cloud'Last(1) - 1 loop
         for J in I + 1 .. Cloud'Last(1) loop
            if Distance (Cloud (I), Cloud (J)) < Min_Distance then
               Min_Distance := Distance (Cloud (I), Cloud (J));
               Result := (Cloud (I), Cloud (J));
            end if;
         end loop;
      end loop;
      return Result;
   end Get_Closest_Points;

   Test_Cloud : constant Matrix (1 .. 10) := ( (5.0, 9.0),  (9.0, 3.0),
                                               (2.0, 0.0),  (8.0, 4.0),
                                               (7.0, 4.0),  (9.0, 10.0),
                                               (1.0, 9.0),  (8.0, 2.0),
                                               (0.0, 10.0), (9.0, 6.0));
   Closest_Points : Matrix := Get_Closest_Points (Test_Cloud);

   Second_Test : constant Matrix (1 .. 10) := ( (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));
   Second_Points : Matrix := Get_Closest_Points (Second_Test);
begin
   Ada.Text_IO.Put_Line ("Closest Points:");
   Ada.Text_IO.Put_Line ("P1: " & Float'Image (Closest_Points (1) (1)) & " " & Float'Image (Closest_Points (1) (2)));
   Ada.Text_IO.Put_Line ("P2: " & Float'Image (Closest_Points (2) (1)) & " " & Float'Image (Closest_Points (2) (2)));
   Ada.Text_IO.Put_Line ("Distance: " & Float'Image (Distance (Closest_Points (1), Closest_Points (2))));
   Ada.Text_IO.Put_Line ("Closest Points 2:");
   Ada.Text_IO.Put_Line ("P1: " & Float'Image (Second_Points (1) (1)) & " " & Float'Image (Second_Points (1) (2)));
   Ada.Text_IO.Put_Line ("P2: " & Float'Image (Second_Points (2) (1)) & " " & Float'Image (Second_Points (2) (2)));
   Ada.Text_IO.Put_Line ("Distance: " & Float'Image (Distance (Second_Points (1), Second_Points (2))));
end Closest;