From 4e8d97a11f3e848194876f26d4a66c1e3271eec8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Caba=C3=B1as?= Date: Mon, 8 Feb 2021 15:19:37 +0100 Subject: [PATCH] reduced hull --- examples/CredalInferenceExample.java | 4 + .../idsia/crema/utility/ProbabilityUtil.java | 30 +++++ .../idsia/crema/utility/hull/ConvexHull.java | 40 ++++-- .../crema/utility/hull/LPConvexHull.java | 2 +- .../idsia/crema/utility/hull/ReducedHull.java | 119 ++++++++++++++++++ 5 files changed, 186 insertions(+), 9 deletions(-) create mode 100644 src/main/java/ch/idsia/crema/utility/ProbabilityUtil.java create mode 100644 src/main/java/ch/idsia/crema/utility/hull/ReducedHull.java diff --git a/examples/CredalInferenceExample.java b/examples/CredalInferenceExample.java index 7df02e65..65648cc1 100644 --- a/examples/CredalInferenceExample.java +++ b/examples/CredalInferenceExample.java @@ -14,8 +14,10 @@ import java.util.Arrays; public class CredalInferenceExample { + public static void main(String[] args) throws InterruptedException { + double p = 0.2; double eps = 0.0001; @@ -150,3 +152,5 @@ public static void main(String[] args) throws InterruptedException { } } + + diff --git a/src/main/java/ch/idsia/crema/utility/ProbabilityUtil.java b/src/main/java/ch/idsia/crema/utility/ProbabilityUtil.java new file mode 100644 index 00000000..a2b1b16c --- /dev/null +++ b/src/main/java/ch/idsia/crema/utility/ProbabilityUtil.java @@ -0,0 +1,30 @@ +package ch.idsia.crema.utility; + +public class ProbabilityUtil { + + + // Compute the symmetrized KL distance between v1 and v2 + public static double KLsymmetrized(double[] p, double[] q, boolean... zeroSafe){ + return KL(p,q,zeroSafe) + KL(q,p,zeroSafe); + } + + // Compute the symmetrized KL distance between v1 and v2 + public static double KL(double[] p, double[] q, boolean... zeroSafe){ + + if(zeroSafe.length>1) throw new IllegalArgumentException("Wrong number of arguments,"); + if(p.length != q.length) throw new IllegalArgumentException("Arrays of different sizes."); + + double distance = 0; + int n = p.length; + for(int i=0; i> constructors = new HashMap(); + + static { + constructors.put(LP_CONVEX_HULL, LPConvexHull::new); + constructors.put(QUICK_HULL, QuickHull::new); + constructors.put(REDUCED_HULL, ReducedHull::new); + } + } + + + /** + * Method that applies the given convex hull method to a list of vertices. + * @param vertices: 2D array of doubles where the first dimension is the number of points and the second + * is the dimensionality of the points. + * @return Array of vertices after applying the convex hull method. + */ double[][] apply(double[][] vertices); - // todo: also to use an enum as well. - static ConvexHull method(String methodName){ - if(methodName=="lp") - return new LPConvexHull(); - else if (methodName=="quick") - return new QuickHull(); - else - throw new IllegalArgumentException("Unknown convex hull method"); + /** + * Method that allows to instantiate any of the implemented methods for convex hull + * @param method + * @return + */ + static ConvexHull as(Method method){ + return Method.constructors.get(method).get(); } diff --git a/src/main/java/ch/idsia/crema/utility/hull/LPConvexHull.java b/src/main/java/ch/idsia/crema/utility/hull/LPConvexHull.java index bbad51a6..4a751573 100644 --- a/src/main/java/ch/idsia/crema/utility/hull/LPConvexHull.java +++ b/src/main/java/ch/idsia/crema/utility/hull/LPConvexHull.java @@ -13,7 +13,7 @@ public class LPConvexHull implements ConvexHull { - private static double[][] add(double[][] current, double[] newpoint) { + public static double[][] add(double[][] current, double[] newpoint) { ArrayList newPoints = new ArrayList<>(Arrays.asList(current)); newPoints.add(newpoint); diff --git a/src/main/java/ch/idsia/crema/utility/hull/ReducedHull.java b/src/main/java/ch/idsia/crema/utility/hull/ReducedHull.java new file mode 100644 index 00000000..8008a7e6 --- /dev/null +++ b/src/main/java/ch/idsia/crema/utility/hull/ReducedHull.java @@ -0,0 +1,119 @@ +package ch.idsia.crema.utility.hull; + + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.IntStream; + +import static ch.idsia.crema.utility.ProbabilityUtil.infoLoss; + +public class ReducedHull implements ConvexHull{ + + private int numPoints = -1; + ArrayList vertices; + HashMap> dist; + HashMap> repl; + + + private void init(double[][] vertices){ + + // Get list structures: points, distances, midpoint + this.dist = new HashMap> (); + this.repl = new HashMap> (); + this.vertices = new ArrayList<>(); + + for(int i=0; id){ + minDist = d; + p1 = vertices.get(i); + p2 = vertices.get(j); + } + } + } + + // get the replacement + q = repl.get(p1).get(p2); + + // remove the existing information + removeInfoPoint(p1); + removeInfoPoint(p2); + + // add new point and update distances + addInfoPoint(q); + } + + + private void removeInfoPoint(double[] p){ + vertices.remove(p); + repl.remove(p); + dist.remove(p); + for(double[] pi : vertices){ + repl.get(pi).remove(p); + dist.get(pi).remove(p); + } + } + + + private void addInfoPoint(double[] p){ + dist.put(p, new HashMap()); + repl.put(p, new HashMap()); + + for(double[] pi : vertices) { + // Compute replacement point + double q[] = IntStream.range(0,pi.length).mapToDouble(k -> 0.5*(p[k] + pi[k])).toArray(); + double d = infoLoss(p, pi, q, true); + dist.get(p).put(pi, d); + dist.get(pi).put(p, d); + repl.get(p).put(pi, q); + repl.get(pi).put(p, q); + + } + vertices.add(p); + } + + + /** + * Set the number of points + * @param numPoints + * @return + */ + public ReducedHull setNumPoints(int numPoints) { + this.numPoints = numPoints; + return this; + } + + /** + * Method that applies the given convex hull method to a list of vertices. + * @param vertices: 2D array of doubles where the first dimension is the number of points and the second + * is the dimensionality of the points. + * @return Array of vertices after applying the convex hull method. + */ + @Override + public double[][] apply(double[][] vertices) { + double[][] hull = ConvexHull.as(Method.LP_CONVEX_HULL).apply(vertices); + int m = numPoints; + if(m<0) m = hull.length-1; + init(vertices); + while(this.vertices.size()>m) + removeNeighbour(); + return this.vertices.toArray(double[][]::new); + } + +}