/**
* Parallel quadtree construction
* @author Robert L. Bocchino Jr.
* @since October 2008, revised January 2013
*/
import DPJRuntime.*;
public class Quadtree extends Harness {
public abstract class Node<region R> {
public abstract <region R1>Node<R1> copy() pure;
}
private static arrayclass Children<region R> {
Node<R:[index]> in R:[index];
}
public class InnerNode<region R> extends Node<R> {
final Children<R> children = new Children<R>(4);
final Box box;
public InnerNode(Box box)
pure
{
this.box = box;
}
public <region R1>Node<R1> copy()
pure
{
return new InnerNode<R1>(this.box);
}
}
public class Body<region R> extends Node<R> {
public static final int MAX_COORD = 1000000000;
final int x in R, y in R;
public Body(int x, int y)
pure
{
this.x = x;
this.y = y;
}
public <region R1>Node<R1> copy()
pure
{
return new Body<R1>(x,y);
}
public String toString() {
return "Body (" + x + "," + y + ")";
}
@Override
public boolean equals(Object o) {
if (!(o instanceof Body<*>)) return false;
Body<*> body = (Body<*>) o;
return this.x == body.x && this.y == body.y;
}
@Override
public int hashCode() {
return x | y;
}
}
public int randomCoord()
pure
{
return (int) (Math.random() * Body.MAX_COORD);
}
public Body randomBody()
pure
{
return new Body(randomCoord(), randomCoord());
}
public class Box {
final int left, right, top, bottom;
final int horizontalMid;
final int verticalMid;
public Box(int left, int right, int top, int bottom)
pure
{
this.left = left;
this.right = right;
this.top = top;
this.bottom = bottom;
this.horizontalMid = (right + left) / 2;
this.verticalMid = (bottom + top) / 2;
}
public Box makeQuadrant(int quadrant)
pure
{
int myBottom = (quadrant < 2) ? (bottom + top) / 2 : bottom;
int myTop = (quadrant < 2) ? top : (bottom + top) / 2;
int myLeft = (quadrant % 2 == 0) ? left : (right + left) / 2;
int myRight = (quadrant % 2 == 0) ? (right + left) / 2 : right;
return new Box(myLeft, myRight, myTop, myBottom);
}
public <region R>int quadrant(Body<R> b) pure {
int vertical = (b.y < verticalMid) ? 0 : 2;
int horizontal = (b.x < horizontalMid) ? 0 : 1;
return vertical + horizontal;
}
public String toString()
pure
{
return "Box (left=" + left + ", "
+ "right=" + right + ", "
+ "top=" + top + ", "
+ "bottom=" + bottom + ")";
}
}
private static arrayclass Quadrants<region R1,R2,R3> {
SequentialHashSet<Body<R1>,R2:[index]> in R3:[index];
}
public <region R1,R2>Node<R2>
makeTree(SequentialHashSet<Body<R1>,R2> S, Box box, int level)
writes R2:*
{
// Nothing to add
if (S.size() == 0) return null;
// Only one thing
if (S.size() == 1) return S.iterator().next().<region R2>copy();
// More than one: Make a new inner node and fill it
// recursively
Quadrants<R1,R2,Local> quadrants =
(Quadrants<R1,R2,Local>)
((Object) new SequentialHashSet[4]);
foreach (int i in 0, 4)
quadrants[i] =
new SequentialHashSet<Body<R1>,R2:[i]>();
for (Body<R1> b : S) {
int quadrant = box.quadrant(b);
quadrants[quadrant].add(b);
}
InnerNode<R2> node = new InnerNode<R2>(box);
foreach (int i in 0, 4) {
node.children[i] =
this.<region R1, R2:[i]>makeTree(quadrants[i],
box.makeQuadrant(i), level+1);
}
return node;
}
public Quadtree(String[] args) {
super("Quadtree", args);
}
SequentialHashSet<Body> bodies = new SequentialHashSet<Body>();
Node root;
@Override
public void initialize() {
for (int i = 0; i < size; ++i) {
// Should really protect against duplicates here
bodies.add(randomBody());
}
}
@Override
public void runTest() {
SequentialSet<Body> myBodies = new SequentialHashSet<Body>();
this.<region Root,Root>checkTree(root, myBodies);
for (Body b : bodies)
assert(myBodies.contains(b));
}
// For now, just check that we inserted everything
private <region R1,R2>void checkTree(Node<R1> subroot,
SequentialSet<Body<R2>> myBodies)
{
if (subroot == null) return;
else if (subroot instanceof Body<R2>) {
myBodies.add((Body<R2>) subroot);
} else {
Children<R1> children = ((InnerNode<R1>) subroot).children;
for (int i = 0; i < children.length; ++i) {
final int j = i;
Node<R1:[j]> child = children[j];
this.<region R1:[j],R2>checkTree(child, myBodies);
}
}
}
@Override
public void runWork() {
root = this.<region Root,Root>makeTree(bodies,
new Box(0, Body.MAX_COORD,
0, Body.MAX_COORD), 0);
}
public static void main(String[] args) {
Quadtree qt = new Quadtree(args);
qt.run();
}
}