diff --git a/java/Point.java b/java/Point.java new file mode 100644 index 0000000..786bad7 --- /dev/null +++ b/java/Point.java @@ -0,0 +1,94 @@ +package patterns; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author pouyllau + * + */ +public class Point { + + public double x; + public double y; + + public Point(double x, double y) { + super(); + this.x = x; + this.y = y; + } + + public static double distance(Point u, Point v) { + return Math.sqrt( (u.x - v.x)*(u.x - v.x) + (u.y - v.y)*(u.y - v.y)); + } + + + + /** + * Compute and set the coordinates of the neighbors of the given point, + * according to grid parameters and directions. Directions are supposed to + * be given in a specific order (in this project, the transit_in_simplex + * functions will necessitate clockwise order). + * + * @param step + * Length of an orthogonal edge of the grid. + * @param pMin + * Corner point of the grid, with minimal coordinates. + * @param pMax + * Corner point of the grid, with maximal coordinates. + * @param directions + * The given direction + */ + public static List neighbors_grid(Point p, double step, Point pMin, Point pMax, List directions) { + + List neighbors = new ArrayList(directions.size()); + for (Point d : directions) { + double nx = p.x + d.x * step; + double ny = p.y + d.y * step; + if ( pMin.x <= nx && nx <= pMax.x && pMin.y <= ny && ny <= pMax.y) { + neighbors.add(new Point(nx, ny)); + } + } + assert (neighbors.size() >= 2); + + return neighbors; + + } + + @Override + public int hashCode() { + final int prime = 7919; + int result = 1; + long temp; + temp = Double.doubleToLongBits(x); + result = prime * result + (int) (temp ^ (temp >>> 7920)); + temp = Double.doubleToLongBits(y); + result = prime * result + (int) (temp ^ (temp >>> 7920)); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Point other = (Point) obj; + if (Double.doubleToLongBits(x) != Double.doubleToLongBits(other.x)) + return false; + if (Double.doubleToLongBits(y) != Double.doubleToLongBits(other.y)) + return false; + return true; + } + + @Override + public String toString() { + return "Point [x=" + x + ", y=" + y+ "]"; + } + + + +} diff --git a/java/crtp/Algo.java b/java/crtp/Algo.java new file mode 100644 index 0000000..be6b097 --- /dev/null +++ b/java/crtp/Algo.java @@ -0,0 +1,170 @@ +package patterns.crtp; + +import java.text.DecimalFormat; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.PriorityQueue; + +import patterns.Point; +/** + * + * @author pouyllau + * + */ +public class Algo { + + private static boolean DEBUG = false; + + public static Map run(Point seed, int iterations, Neighborhood neighborhood, Transit transit) { + Map costs = new HashMap(); + + PriorityQueue front = new PriorityQueue(new Comparator() { + public int compare(Point lhs, Point rhs) { + if (costs.get(lhs) >= costs.get(rhs)) + return +1; + if (costs.get(lhs) < costs.get(rhs)) + return -1; + return 0; + } + }); + + costs.put(seed, 0.); + front.add(seed); + + for (int i = 0; i < iterations && !front.isEmpty(); i++) { + if (DEBUG) + System.out.println(i + "/" + iterations); + + // Accept the node with the min cost and update neighbors. + // Accept the considered node with the min cost. + Point accepted = front.poll(); + + // Consider neighbors of the accepted node. + List around = neighborhood.get(accepted); + assert (around.size() > 0); + + for (Point n : around) { + // If no cost has been computed (i.e. the node is "open"). + if (!Transit.hasCost(n, costs)) { + + double ncost = transit.transit(n, neighborhood.get(n), costs); + if (DEBUG) + System.out.println(n + " cost=" + ncost); + costs.put(n, ncost); + front.add(n); + } + } + } + return costs; + } + + public static void printGrid(Map grid, Point pMin, Point pMax, double step, String sep) { + if (sep == null) + sep = "\t"; + String width = " "; + System.out.print(" x:"+sep); + + for (double px = pMin.x; px <= pMax.x; px += step) { + System.out.print(sep + (int)px+ " "+ width ); + } + + System.out.print("\n"); + System.out.print(" y\n"); + + for (double py = pMax.y; py >= pMin.y; py -= step) { + System.out.print(sep + (int)py + ":"); + for (double px = pMin.x; px <= pMax.x; px += step) { + Point p = new Point(px, py); + if (Transit.hasCost(p, grid)) { + System.out.format(sep + "%.2f" + width, grid.get(p)); + } else { + System.out.print(sep + " . " + width); + } + } + System.out.print("\n"); + } + System.out.print("\n"); + } + + public static void performEvaluations(Point seed, int iterations, Neighborhood neighborhood, Transit transit, int T) { + double mean = 0; + double m2 = 0; + for (int t = 0; t < T; t++) { + long startTime = System.nanoTime(); + run(seed, iterations, neighborhood, transit); + startTime = System.nanoTime() - startTime; + double delta = (double)startTime - mean; + mean += delta / (double) T; + m2 += delta * delta; + } + m2 = m2 / (double)(T-1.); + m2 = Math.sqrt(m2); + System.out.println("Mean time : " + new DecimalFormat("#.##########").format((mean / 1000000000)) + " s" + + " sd : " + new DecimalFormat("#.##########").format((m2 / 1000000000))); + } + + public static void main(String[] args) { + Locale.setDefault(Locale.US); + Point seed = new Point(0, 0); + Point pMin = new Point(-5, -5); + Point pMax = new Point(15, 15); + double step = 1.; + int maxit = 300; + double eps = 1. / 100.0; + int eval = 100; + + Neighborhood quad= new QuadGrid(step, pMin, pMax); + Neighborhood octo = new OctoGrid(step, pMin, pMax); + + Transit graph = new TransitOnEdge(); + Transit mesh = new TransitInSimplex(eps); + + + System.out.println("Dijkstra, 4 neighbors"); + performEvaluations(seed, maxit, quad, graph, eval); + System.out.println("Dijkstra, 8 neighbors"); + performEvaluations(seed, maxit, octo, graph, eval); + System.out.println("Fast marching, 4 neighbors"); + performEvaluations(seed, maxit, quad, mesh, eval); + System.out.println("Fast marching, 8 neighbors"); + performEvaluations(seed, maxit, octo, mesh, eval); + + /*System.out.println("Dijkstra, 4 neighbors"); + long startTime = System.nanoTime(); + Map dijkstra4 = run(seed, maxit, quad, graph); + startTime = System.nanoTime() - startTime; + double duration = ((double)startTime / 1000000000); + System.out.println("solution Time : " + new DecimalFormat("#.##########").format(duration) + " Seconds"); + printGrid(dijkstra4, pMin, pMax, step, null); + + System.out.println("Dijkstra, 8 neighbors"); + startTime = System.nanoTime(); + Map dijkstra8 = run(seed, maxit, octo, graph); + startTime = System.nanoTime() - startTime; + duration = ((double)startTime / 1000000000); + System.out.println("solution Time : " + new DecimalFormat("#.##########").format(duration) + " Seconds"); + printGrid(dijkstra8, pMin, pMax, step, null); + + System.out.println("Fast marching, 4 neighbors"); + startTime = System.nanoTime(); + Map fast_marching4 = run(seed, maxit, quad, mesh); + startTime = System.nanoTime() - startTime; + duration = ((double)startTime / 1000000000); + System.out.println("solution Time : " + new DecimalFormat("#.##########").format(duration) + " Seconds"); + printGrid(fast_marching4, pMin, pMax, step, null); + + + System.out.println("Fast marching, 8 neighbors"); + startTime = System.nanoTime(); + Map fast_marching8 = run(seed, maxit, octo, mesh); + startTime = System.nanoTime() - startTime; + duration = ((double)startTime / 1000000000); + System.out.println("solution Time : " + new DecimalFormat("#.##########").format(duration) + " Seconds"); + printGrid(fast_marching8, pMin, pMax, step, null);*/ + + + } +} diff --git a/java/crtp/Neighborhood.java b/java/crtp/Neighborhood.java new file mode 100644 index 0000000..7020adf --- /dev/null +++ b/java/crtp/Neighborhood.java @@ -0,0 +1,35 @@ +package patterns.crtp; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.function.Function; + +import patterns.Point; +/** + * + * @author pouyllau + * + * @param + */ +public class Neighborhood> { + + protected static double step; + protected static Point pMin; + protected static Point pMax; + T t; + + public Neighborhood(double step, Point pMin, Point pMax) { + super(); + this.step = step; + this.pMin = pMin; + this.pMax = pMax; + } + + public List get(Point p) { + return t.get(p); + } + + + +} diff --git a/java/crtp/OctoGrid.java b/java/crtp/OctoGrid.java new file mode 100644 index 0000000..d15c01b --- /dev/null +++ b/java/crtp/OctoGrid.java @@ -0,0 +1,25 @@ +package patterns.crtp; + +import java.util.Arrays; +import java.util.List; + +import patterns.Point; +/** + * + * @author pouyllau + * + */ +public class OctoGrid extends Neighborhood { + + public OctoGrid(double step, Point pMin, Point pMax) { + super(step, pMin, pMax); + this.t = this; + } + + public List get(Point p) { + return Point.neighbors_grid(p, step, pMin, pMax, + Arrays.asList(new Point(1, 0), new Point(1, -1), new Point(0, -1), new Point(-1, -1), new Point(-1, 0), + new Point(-1, 1), new Point(0, 1), new Point(1, 1))); + } + +} diff --git a/java/crtp/QuadGrid.java b/java/crtp/QuadGrid.java new file mode 100644 index 0000000..93dd087 --- /dev/null +++ b/java/crtp/QuadGrid.java @@ -0,0 +1,25 @@ +package patterns.crtp; + +import java.util.Arrays; +import java.util.List; + +import patterns.Point; +/** + * + * @author pouyllau + * + */ +public class QuadGrid extends Neighborhood { + + public QuadGrid(double step, Point pMin, Point pMax) { + super(step, pMin, pMax); + this.t = this; + } + + public List get(Point p) { + return Point.neighbors_grid(p, step, pMin, pMax, + Arrays.asList(new Point(1, 0), new Point(0, -1), new Point(-1, 0), new Point(0, 1))); + } + + +} diff --git a/java/crtp/Transit.java b/java/crtp/Transit.java new file mode 100644 index 0000000..3aec71a --- /dev/null +++ b/java/crtp/Transit.java @@ -0,0 +1,25 @@ +package patterns.crtp; + +import java.util.List; +import java.util.Map; + +import patterns.Point; +/** + * + * @author pouyllau + * + * @param + */ +public class Transit> { + + T t; + + + public double transit(Point p, List neighbors, Map costs) { + return t.transit(p, neighbors, costs); + } + + public static boolean hasCost(Point p ,Map costs) { + return (costs.get(p) != null && costs.get(p) != Double.POSITIVE_INFINITY); + } +} diff --git a/java/crtp/TransitInSimplex.java b/java/crtp/TransitInSimplex.java new file mode 100644 index 0000000..6648285 --- /dev/null +++ b/java/crtp/TransitInSimplex.java @@ -0,0 +1,83 @@ +package patterns.crtp; + +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import patterns.Point; + +/** + * Find the transit in minimal cost within the given simplexes. + * + * That is, find the minimal distance between the given point and one of the + * edges formed by the sequence of pairs of neighbors. Neighbors should thus be + * given in clockwise order. The minimal transit is searched across 1/eps + * distances, regularly spaced on each edge. + * + * @author pouyllau + * + */ +public class TransitInSimplex extends Transit { + + protected double eps; + + + public TransitInSimplex(double eps) { + super(); + this.t = this; + this.eps = eps; + } + + @Override + public double transit(Point p, List neighbors, Map costs) { + + double mincost = Double.MAX_VALUE; + List list = neighbors.stream().filter(n -> hasCost(n, costs)).collect(Collectors.toList()); + int k = list.size(); + if (k == 1) { + mincost = costs.get(list.get(0))+ Point.distance(list.get(0), p); + } else { + for (int i = 0; i < neighbors.size(); i++) { + Point pj = neighbors.get(i); + Point pk = (i+1 < neighbors.size() ? neighbors.get(i+1) : neighbors.get(0)); + double c = 0; + + if (hasCost(pj, costs) && hasCost(pk, costs)) { + // Cost of the transition from/to p from/to edge e. + // This is the simplest way to minimize the transit, even if + // not the most efficient. + for (double z = 0; z <= 1; z += eps) { + double zx = z * pj.x + (1 - z) * pk.x; + double zy = z * pj.y + (1 - z) * pk.y; + + // Linear interpolation of costs. + c = z *costs.get(pj) + (1 - z) * costs.get(pk)+ Point.distance(p, new Point(zx, zy)); + if (c < mincost) { + mincost = c; + } + } // for z + + // If the front is reached on a single point. + } else if (hasCost(pj, costs) && !hasCost(pk, costs)) { + c = costs.get(pj)+ Point.distance(p, pj); + if (c < mincost) { + mincost = c; + } + } else if (!hasCost(pj, costs) && hasCost(pk, costs)) { + c = costs.get(pk) + Point.distance(p, pk); + if (c < mincost) { + mincost = c; + } + } + + + } + + } + assert (mincost < Double.POSITIVE_INFINITY); + return mincost; + } + + +} diff --git a/java/crtp/TransitOnEdge.java b/java/crtp/TransitOnEdge.java new file mode 100644 index 0000000..210836e --- /dev/null +++ b/java/crtp/TransitOnEdge.java @@ -0,0 +1,35 @@ +package patterns.crtp; + +import java.util.List; +import java.util.Map; + +import patterns.Point; + +/** Find the transit of minimal cost among the given edges. + +Edges are given as the considered point and the sequence of neighbors points. +* @author pouyllau +* +* */ +public class TransitOnEdge extends Transit{ + + public TransitOnEdge() { + super(); + this.t = this; + } + + public double transit(Point p, List neighbors, Map costs) { + double mincost = Double.POSITIVE_INFINITY; + + for (Point n : neighbors) { + if (hasCost(n, costs)) { + double c = costs.get(n) + Point.distance(p, n); + if (c < mincost) { + mincost = c; + } + } + } + assert (mincost != Double.POSITIVE_INFINITY); + return mincost; + } +} diff --git a/java/functionnal/Algo.java b/java/functionnal/Algo.java new file mode 100644 index 0000000..0cf214e --- /dev/null +++ b/java/functionnal/Algo.java @@ -0,0 +1,171 @@ +package patterns.functionnal; + +import java.text.DecimalFormat; +import java.text.SimpleDateFormat; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.PriorityQueue; + +import patterns.Point; +/** + * + * @author pouyllau + * + */ +public class Algo { + + private static boolean DEBUG = false; + + public static Map run(Point seed, int iterations, Neighborhood neighborhood, Transit transit) { + Map costs = new HashMap(); + + PriorityQueue front = new PriorityQueue(new Comparator() { + public int compare(Point lhs, Point rhs) { + if (costs.get(lhs) >= costs.get(rhs)) + return +1; + if (costs.get(lhs) < costs.get(rhs)) + return -1; + return 0; + } + }); + + costs.put(seed, 0.); + front.add(seed); + + for (int i = 0; i < iterations && !front.isEmpty(); i++) { + if (DEBUG) + System.out.println(i + "/" + iterations); + + // Accept the node with the min cost and update neighbors. + // Accept the considered node with the min cost. + Point accepted = front.poll(); + + // Consider neighbors of the accepted node. + List around = neighborhood.get(accepted); + assert (around.size() > 0); + + for (Point n : around) { + // If no cost has been computed (i.e. the node is "open"). + if (!Transit.hasCost(n, costs)) { + + double ncost = transit.transit(n, neighborhood.get(n), costs); + if (DEBUG) + System.out.println(n + " cost=" + ncost); + costs.put(n, ncost); + front.add(n); + } + } + } + return costs; + } + + public static void printGrid(Map grid, Point pMin, Point pMax, double step, String sep) { + if (sep == null) + sep = "\t"; + String width = " "; + System.out.print(" x:"+sep); + + for (double px = pMin.x; px <= pMax.x; px += step) { + System.out.print(sep + (int)px+ " "+ width ); + } + + System.out.print("\n"); + System.out.print(" y\n"); + + for (double py = pMax.y; py >= pMin.y; py -= step) { + System.out.print(sep + (int)py + ":"); + for (double px = pMin.x; px <= pMax.x; px += step) { + Point p = new Point(px, py); + if (Transit.hasCost(p, grid)) { + System.out.format(sep + "%.2f" + width, grid.get(p)); + } else { + System.out.print(sep + " . " + width); + } + } + System.out.print("\n"); + } + System.out.print("\n"); + } + + public static void performEvaluations(Point seed, int iterations, Neighborhood neighborhood, Transit transit, int T) { + double mean = 0; + double m2 = 0; + for (int t = 0; t < T; t++) { + long startTime = System.nanoTime(); + run(seed, iterations, neighborhood, transit); + startTime = System.nanoTime() - startTime; + double delta = (double)startTime - mean; + mean += delta / (double) T; + m2 += delta * delta; + } + m2 = m2 / (double)(T-1.); + m2 = Math.sqrt(m2); + System.out.println("Mean time : " + new DecimalFormat("#.##########").format((mean / 1000000000)) + " s" + + " sd : " + new DecimalFormat("#.##########").format((m2 / 1000000000))); + } + + public static void main(String[] args) { + Locale.setDefault(Locale.US); + Point seed = new Point(0, 0); + Point pMin = new Point(-5, -5); + Point pMax = new Point(15, 15); + double step = 1.; + int maxit = 300; + double eps = 1. / 100.0; + int eval = 100; + + Neighborhood quad= new Neighborhood(Neighborhood.quad(), step, pMin, pMax); + Neighborhood octo = new Neighborhood(Neighborhood.octo(), step, pMin, pMax); + + Transit graph = new Transit(Transit.edge()); + Transit mesh = new Transit(Transit.simplex(eps)); + + + System.out.println("Dijkstra, 4 neighbors"); + performEvaluations(seed, maxit, quad, graph, eval); + System.out.println("Dijkstra, 8 neighbors"); + performEvaluations(seed, maxit, octo, graph, eval); + System.out.println("Fast marching, 4 neighbors"); + performEvaluations(seed, maxit, quad, mesh, eval); + System.out.println("Fast marching, 8 neighbors"); + performEvaluations(seed, maxit, octo, mesh, eval); + /* + System.out.println("Dijkstra, 4 neighbors"); + long startTime = System.nanoTime(); + Map dijkstra4 = run(seed, maxit, quadCrtp, graph); + startTime = System.nanoTime() - startTime; + double duration = ((double)startTime / 1000000000); + System.out.println("solution Time : " + new DecimalFormat("#.##########").format(duration) + " Seconds"); + printGrid(dijkstra4, pMin, pMax, step, null); + + System.out.println("Dijkstra, 8 neighbors"); + startTime = System.nanoTime(); + Map dijkstra8 = run(seed, maxit, octoCrtp, graph); + startTime = System.nanoTime() - startTime; + duration = ((double)startTime / 1000000000); + System.out.println("solution Time : " + new DecimalFormat("#.##########").format(duration) + " Seconds"); + printGrid(dijkstra8, pMin, pMax, step, null); + + System.out.println("Fast marching, 4 neighbors"); + startTime = System.nanoTime(); + Map fast_marching4 = run(seed, maxit, quadCrtp, mesh); + startTime = System.nanoTime() - startTime; + duration = ((double)startTime / 1000000000); + System.out.println("solution Time : " + new DecimalFormat("#.##########").format(duration) + " Seconds"); + printGrid(fast_marching4, pMin, pMax, step, null); + + + System.out.println("Fast marching, 8 neighbors"); + startTime = System.nanoTime(); + Map fast_marching8 = run(seed, maxit, octoCrtp, mesh); + startTime = System.nanoTime() - startTime; + duration = ((double)startTime / 1000000000); + System.out.println("solution Time : " + new DecimalFormat("#.##########").format(duration) + " Seconds"); + printGrid(fast_marching8, pMin, pMax, step, null);*/ + + + } +} diff --git a/java/functionnal/Neighborhood.java b/java/functionnal/Neighborhood.java new file mode 100644 index 0000000..233eb7c --- /dev/null +++ b/java/functionnal/Neighborhood.java @@ -0,0 +1,43 @@ +package patterns.functionnal; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.function.Function; + +import patterns.Point; +/** + * + * @author pouyllau + * + */ +public class Neighborhood { + + protected static double step; + protected static Point pMin; + protected static Point pMax; + Function> f; + + public Neighborhood(Function> f,double step, Point pMin, Point pMax) { + super(); + this.f = f; + this.step = step; + this.pMin = pMin; + this.pMax = pMax; + } + + public List get( Point p) { + return f.apply(p); + } + + public static Function> quad() { + return x -> Point.neighbors_grid(x, step, pMin, pMax, + Arrays.asList(new Point(1, 0), new Point(0, -1), new Point(-1, 0), new Point(0, 1))); + } + + public static Function> octo() { + return x -> Point.neighbors_grid(x, step, pMin, pMax,Arrays.asList(new Point(1, 0), new Point(1, -1), new Point(0, -1), new Point(-1, -1), + new Point(-1, 0), new Point(-1, 1), new Point(0, 1), new Point(1, 1))); + } + +} diff --git a/java/functionnal/Transit.java b/java/functionnal/Transit.java new file mode 100644 index 0000000..fa34980 --- /dev/null +++ b/java/functionnal/Transit.java @@ -0,0 +1,104 @@ +package patterns.functionnal; + +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +import patterns.Point; +/** + * + * @author pouyllau + * + */ +public class Transit { + + public static boolean hasCost(Point p ,Map costs) { + return (costs.get(p) != null && costs.get(p) != Double.POSITIVE_INFINITY); + } + + TriFunction, Map, Double> f; + + + public Transit(TriFunction, Map, Double> f) { + super(); + this.f = f; + } + + public double transit(Point p, List neighbors, Map costs) { + return f.apply(p,neighbors,costs); + } + + public static TriFunction, Map, Double> simplex(double eps) { + return (x, y, z) -> transitInSimplex(x,y,z, eps); + } + + public static TriFunction, Map, Double> edge() { + return (x, y, z) -> transitOnEdge(x,y,z); + } + + public static double transitOnEdge(Point p, List neighbors, Map costs) { + double mincost = Double.POSITIVE_INFINITY; + + for (Point n : neighbors) { + if (hasCost(n, costs)) { + double c = costs.get(n) + Point.distance(p, n); + if (c < mincost) { + mincost = c; + } + } + } + assert (mincost != Double.POSITIVE_INFINITY); + return mincost; + } + + public static double transitInSimplex(Point p, List neighbors, Map costs, double eps) { + + double mincost = Double.MAX_VALUE; + List list = neighbors.stream().filter(n -> hasCost(n, costs)).collect(Collectors.toList()); + int k = list.size(); + if (k == 1) { + mincost = costs.get(list.get(0))+ Point.distance(list.get(0), p); + } else { + for (int i = 0; i < neighbors.size(); i++) { + Point pj = neighbors.get(i); + Point pk = (i+1 < neighbors.size() ? neighbors.get(i+1) : neighbors.get(0)); + double c = 0; + + if (hasCost(pj, costs) && hasCost(pk, costs)) { + // Cost of the transition from/to p from/to edge e. + // This is the simplest way to minimize the transit, even if + // not the most efficient. + for (double z = 0; z <= 1; z += eps) { + double zx = z * pj.x + (1 - z) * pk.x; + double zy = z * pj.y + (1 - z) * pk.y; + + // Linear interpolation of costs. + c = z *costs.get(pj) + (1 - z) * costs.get(pk)+ Point.distance(p, new Point(zx, zy)); + if (c < mincost) { + mincost = c; + } + } // for z + + // If the front is reached on a single point. + } else if (hasCost(pj, costs) && !hasCost(pk, costs)) { + c = costs.get(pj)+ Point.distance(p, pj); + if (c < mincost) { + mincost = c; + } + } else if (!hasCost(pj, costs) && hasCost(pk, costs)) { + c = costs.get(pk) + Point.distance(p, pk); + if (c < mincost) { + mincost = c; + } + } + + + } + + } + assert (mincost < Double.POSITIVE_INFINITY); + return mincost; + } + +} diff --git a/java/functionnal/TriFunction.java b/java/functionnal/TriFunction.java new file mode 100644 index 0000000..8368788 --- /dev/null +++ b/java/functionnal/TriFunction.java @@ -0,0 +1,20 @@ +package patterns.functionnal; + +import java.util.Objects; +import java.util.function.Function; +/** + * + * @author pouyllau + * + */ +@FunctionalInterface +public interface TriFunction { + + R apply(A a, B b, C c); + + default TriFunction andThen( + Function after) { + Objects.requireNonNull(after); + return (A a, B b, C c) -> after.apply(apply(a, b, c)); + } +} diff --git a/java/strategy/Algo.java b/java/strategy/Algo.java new file mode 100644 index 0000000..d36fa6b --- /dev/null +++ b/java/strategy/Algo.java @@ -0,0 +1,172 @@ +package patterns.strategy; + +import java.io.StreamTokenizer; +import java.text.DecimalFormat; +import java.text.SimpleDateFormat; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.PriorityQueue; + +import patterns.Point; +/** + * + * @author pouyllau + * + */ +public class Algo { + + private static boolean DEBUG = false; + + public static Map run(Point seed, int iterations, Neighborhood neighborhood, Transit transit) { + Map costs = new HashMap(); + + PriorityQueue front = new PriorityQueue(new Comparator() { + public int compare(Point lhs, Point rhs) { + if (costs.get(lhs) >= costs.get(rhs)) + return +1; + if (costs.get(lhs) < costs.get(rhs)) + return -1; + return 0; + } + }); + + costs.put(seed, 0.); + front.add(seed); + + for (int i = 0; i < iterations && !front.isEmpty(); i++) { + if (DEBUG) + System.out.println(i + "/" + iterations); + + // Accept the node with the min cost and update neighbors. + // Accept the considered node with the min cost. + Point accepted = front.poll(); + + // Consider neighbors of the accepted node. + List around = neighborhood.get(accepted); + assert (around.size() > 0); + + for (Point n : around) { + // If no cost has been computed (i.e. the node is "open"). + if (!Transit.hasCost(n, costs)) { + + double ncost = transit.transit(n, neighborhood.get(n), costs); + if (DEBUG) + System.out.println(n + " cost=" + ncost); + costs.put(n, ncost); + front.add(n); + } + } + } + return costs; + } + + public static void printGrid(Map grid, Point pMin, Point pMax, double step, String sep) { + if (sep == null) + sep = "\t"; + String width = " "; + System.out.print(" x:" + sep); + + for (double px = pMin.x; px <= pMax.x; px += step) { + System.out.print(sep + (int) px + " " + width); + } + + System.out.print("\n"); + System.out.print(" y\n"); + + for (double py = pMax.y; py >= pMin.y; py -= step) { + System.out.print(sep + (int) py + ":"); + for (double px = pMin.x; px <= pMax.x; px += step) { + Point p = new Point(px, py); + if (Transit.hasCost(p, grid)) { + System.out.format(sep + "%.2f" + width, grid.get(p)); + } else { + System.out.print(sep + " . " + width); + } + } + System.out.print("\n"); + } + System.out.print("\n"); + } + + public static void performEvaluations(Point seed, int iterations, Neighborhood neighborhood, Transit transit, + int T) { + double mean = 0; + double m2 = 0; + for (int t = 0; t < T; t++) { + long startTime = System.nanoTime(); + run(seed, iterations, neighborhood, transit); + startTime = System.nanoTime() - startTime; + double delta = (double)startTime - mean; + mean += delta / (double) T; + m2 += delta * delta; + } + m2 = m2 / (double)(T-1.); + m2 = Math.sqrt(m2); + System.out.println("Mean time : " + new DecimalFormat("#.##########").format((mean / 1000000000)) + " s" + + " sd : " + new DecimalFormat("#.##########").format((m2 / 1000000000))); + } + + public static void main(String[] args) { + Locale.setDefault(Locale.US); + Point seed = new Point(0, 0); + Point pMin = new Point(-5, -5); + Point pMax = new Point(15, 15); + double step = 1.; + int maxit = 300; + double eps = 1. / 100.0; + int eval = 100; + + Neighborhood quad = new patterns.strategy.QuadGrid(step, pMin, pMax); + Neighborhood octo = new patterns.strategy.OctoGrid(step, pMin, pMax); + + Transit graph = new TransitOnEdge(); + Transit mesh = new TransitInSimplex(eps); + + System.out.println("Dijkstra, 4 neighbors"); + performEvaluations(seed, maxit, quad, graph, eval); + System.out.println("Dijkstra, 8 neighbors"); + performEvaluations(seed, maxit, octo, graph, eval); + System.out.println("Fast marching, 4 neighbors"); + performEvaluations(seed, maxit, quad, mesh, eval); + System.out.println("Fast marching, 8 neighbors"); + performEvaluations(seed, maxit, octo, mesh, eval); + /* + System.out.println("Dijkstra, 4 neighbors"); + long startTime = System.nanoTime(); + Map dijkstra4 = run(seed, maxit, quad, graph); + startTime = System.nanoTime() - startTime; + double duration = ((double)startTime / 1000000000); + System.out.println("solution Time : " + new DecimalFormat("#.##########").format(duration) + " Seconds"); + printGrid(dijkstra4, pMin, pMax, step, null); + + System.out.println("Dijkstra, 8 neighbors"); + startTime = System.nanoTime(); + Map dijkstra8 = run(seed, maxit, octo, graph); + startTime = System.nanoTime() - startTime; + duration = ((double)startTime / 1000000000); + System.out.println("solution Time : " + new DecimalFormat("#.##########").format(duration) + " Seconds"); + printGrid(dijkstra8, pMin, pMax, step, null); + + System.out.println("Fast marching, 4 neighbors"); + startTime = System.nanoTime(); + Map fast_marching4 = run(seed, maxit, quad, mesh); + startTime = System.nanoTime() - startTime; + duration = ((double)startTime / 1000000000); + System.out.println("solution Time : " + new DecimalFormat("#.##########").format(duration) + " Seconds"); + printGrid(fast_marching4, pMin, pMax, step, null); + + + System.out.println("Fast marching, 8 neighbors"); + startTime = System.nanoTime(); + Map fast_marching8 = run(seed, maxit, octo, mesh); + startTime = System.nanoTime() - startTime; + duration = ((double)startTime / 1000000000); + System.out.println("solution Time : " + new DecimalFormat("#.##########").format(duration) + " Seconds"); + printGrid(fast_marching8, pMin, pMax, step, null); + */ + + } +} diff --git a/java/strategy/Neighborhood.java b/java/strategy/Neighborhood.java new file mode 100644 index 0000000..aea5bfe --- /dev/null +++ b/java/strategy/Neighborhood.java @@ -0,0 +1,27 @@ +package patterns.strategy; + +import java.util.List; + +import patterns.Point; +/** + * + * @author pouyllau + * + */ +public abstract class Neighborhood { + protected double step; + protected Point pMin; + protected Point pMax; + protected List directions; + + + public Neighborhood(double step, Point pMin, Point pMax) { + super(); + this.step = step; + this.pMin = pMin; + this.pMax = pMax; + } + + public abstract List get(Point p); + +} diff --git a/java/strategy/OctoGrid.java b/java/strategy/OctoGrid.java new file mode 100644 index 0000000..12c4c58 --- /dev/null +++ b/java/strategy/OctoGrid.java @@ -0,0 +1,24 @@ +package patterns.strategy; + +import java.util.Arrays; +import java.util.List; + +import patterns.Point; +/** + * + * @author pouyllau + * + */ +public class OctoGrid extends Neighborhood { + + public OctoGrid(double step, Point pMin, Point pMax) { + super(step, pMin, pMax); + this.directions = Arrays.asList(new Point(1, 0), new Point(1, -1), new Point(0, -1), new Point(-1, -1), + new Point(-1, 0), new Point(-1, 1), new Point(0, 1), new Point(1, 1)); + } + + public List get(Point p) { + + return Point.neighbors_grid(p, step,pMin, pMax, directions); + } +} diff --git a/java/strategy/QuadGrid.java b/java/strategy/QuadGrid.java new file mode 100644 index 0000000..784a8ac --- /dev/null +++ b/java/strategy/QuadGrid.java @@ -0,0 +1,24 @@ +package patterns.strategy; + +import java.util.Arrays; +import java.util.List; + +import patterns.Point; +/** + * + * @author pouyllau + * + */ +public class QuadGrid extends Neighborhood { + + public QuadGrid(double step, Point pMin, Point pMax) { + super(step, pMin, pMax); + this.directions = Arrays.asList(new Point(1,0), new Point (0,-1), new Point(-1,0), new Point(0,1)); + } + + public List get(Point p) { + return Point.neighbors_grid(p, step,pMin, pMax, directions); + } + + +} diff --git a/java/strategy/Transit.java b/java/strategy/Transit.java new file mode 100644 index 0000000..94e243e --- /dev/null +++ b/java/strategy/Transit.java @@ -0,0 +1,19 @@ +package patterns.strategy; + +import java.util.List; +import java.util.Map; + +import patterns.Point; +/** + * + * @author pouyllau + * + */ +public abstract class Transit { + + public abstract double transit(Point p, List neighbors, Map costs); + + public static boolean hasCost(Point p ,Map costs) { + return (costs.get(p) != null && costs.get(p) != Double.POSITIVE_INFINITY); + } +} diff --git a/java/strategy/TransitInSimplex.java b/java/strategy/TransitInSimplex.java new file mode 100644 index 0000000..a425e09 --- /dev/null +++ b/java/strategy/TransitInSimplex.java @@ -0,0 +1,80 @@ +package patterns.strategy; + +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import patterns.Point; + +/** + * Find the transit in minimal cost within the given simplexes. + * + * That is, find the minimal distance between the given point and one of the + * edges formed by the sequence of pairs of neighbors. Neighbors should thus be + * given in clockwise order. The minimal transit is searched across 1/eps + * distances, regularly spaced on each edge. + * @author pouyllau + */ +public class TransitInSimplex extends Transit { + + protected double eps; + + + public TransitInSimplex(double eps) { + super(); + this.eps = eps; + } + + + public double transit(Point p, List neighbors, Map costs) { + + double mincost = Double.MAX_VALUE; + List list = neighbors.stream().filter(n -> hasCost(n, costs)).collect(Collectors.toList()); + int k = list.size(); + if (k == 1) { + mincost = costs.get(list.get(0))+ Point.distance(list.get(0), p); + } else { + for (int i = 0; i < neighbors.size(); i++) { + Point pj = neighbors.get(i); + Point pk = (i+1 < neighbors.size() ? neighbors.get(i+1) : neighbors.get(0)); + double c = 0; + + if (hasCost(pj, costs) && hasCost(pk, costs)) { + // Cost of the transition from/to p from/to edge e. + // This is the simplest way to minimize the transit, even if + // not the most efficient. + for (double z = 0; z <= 1; z += eps) { + double zx = z * pj.x + (1 - z) * pk.x; + double zy = z * pj.y + (1 - z) * pk.y; + + // Linear interpolation of costs. + c = z *costs.get(pj) + (1 - z) * costs.get(pk)+ Point.distance(p, new Point(zx, zy)); + if (c < mincost) { + mincost = c; + } + } // for z + + // If the front is reached on a single point. + } else if (hasCost(pj, costs) && !hasCost(pk, costs)) { + c = costs.get(pj)+ Point.distance(p, pj); + if (c < mincost) { + mincost = c; + } + } else if (!hasCost(pj, costs) && hasCost(pk, costs)) { + c = costs.get(pk) + Point.distance(p, pk); + if (c < mincost) { + mincost = c; + } + } + + + } + + } + assert (mincost < Double.POSITIVE_INFINITY); + return mincost; + } + + +} diff --git a/java/strategy/TransitOnEdge.java b/java/strategy/TransitOnEdge.java new file mode 100644 index 0000000..f51d8df --- /dev/null +++ b/java/strategy/TransitOnEdge.java @@ -0,0 +1,32 @@ +package patterns.strategy; + +import java.util.List; +import java.util.Map; + +import patterns.Point; +/** + * Find the transit of minimal cost among the given edges. + +Edges are given as the considered point and the sequence of neighbors points. + + * @author pouyllau + */ + + +public class TransitOnEdge extends Transit { + + public double transit(Point p, List neighbors, Map costs) { + double mincost = Double.POSITIVE_INFINITY; + + for (Point n : neighbors) { + if (hasCost(n, costs)) { + double c = costs.get(n) + Point.distance(p, n); + if (c < mincost) { + mincost = c; + } + } + } + assert (mincost != Double.POSITIVE_INFINITY); + return mincost; + } +}