You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by lu...@apache.org on 2014/01/29 21:19:20 UTC

svn commit: r1562573 - in /commons/proper/math/trunk/src: main/java/org/apache/commons/math3/geometry/enclosing/ test/java/org/apache/commons/math3/geometry/enclosing/

Author: luc
Date: Wed Jan 29 20:19:20 2014
New Revision: 1562573

URL: http://svn.apache.org/r1562573
Log:
Added tests for 3D smallest ball enclosing.

WARNING! These tests have revealed a bug in our implementation of the
smallest enclosing ball algorithm. So some tests are currently ignored
in order to avoid having lots of messages, but I am already working on
them. The problems should be fixed (and the tests activated) before 3.3
release.

Added:
    commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/enclosing/WelzlEncloser2DTest.java   (contents, props changed)
      - copied, changed from r1562571, commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/enclosing/WelzlEncloserTest.java
    commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/enclosing/WelzlEncloser3DTest.java   (with props)
Removed:
    commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/enclosing/WelzlEncloserTest.java
Modified:
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/enclosing/WelzlEncloser.java

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/enclosing/WelzlEncloser.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/enclosing/WelzlEncloser.java?rev=1562573&r1=1562572&r2=1562573&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/enclosing/WelzlEncloser.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/enclosing/WelzlEncloser.java Wed Jan 29 20:19:20 2014
@@ -19,6 +19,7 @@ package org.apache.commons.math3.geometr
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.commons.math3.exception.MathInternalError;
 import org.apache.commons.math3.geometry.Point;
 import org.apache.commons.math3.geometry.Space;
 
@@ -101,7 +102,12 @@ public class WelzlEncloser<S extends Spa
             // recurse search, restricted to the small subset containing support and farthest point
             support.clear();
             support.add(farthest);
+            EnclosingBall<S, P> savedBall = ball;
             ball = moveToFrontBall(extreme, support);
+            if (ball.getRadius() < savedBall.getRadius()) {
+                // TODO: fix this, it should never happen but it does!
+                throw new MathInternalError();
+            }
 
             // it was an interesting point, move it to the front
             // according to Gärtner's heuristic

Copied: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/enclosing/WelzlEncloser2DTest.java (from r1562571, commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/enclosing/WelzlEncloserTest.java)
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/enclosing/WelzlEncloser2DTest.java?p2=commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/enclosing/WelzlEncloser2DTest.java&p1=commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/enclosing/WelzlEncloserTest.java&r1=1562571&r2=1562573&rev=1562573&view=diff
==============================================================================
--- commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/enclosing/WelzlEncloserTest.java (original)
+++ commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/enclosing/WelzlEncloser2DTest.java Wed Jan 29 20:19:20 2014
@@ -20,20 +20,21 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
-import org.apache.commons.math3.geometry.euclidean.twod.BallGenerator;
+import org.apache.commons.math3.geometry.euclidean.twod.DiskGenerator;
 import org.apache.commons.math3.geometry.euclidean.twod.Euclidean2D;
 import org.apache.commons.math3.geometry.euclidean.twod.Vector2D;
 import org.apache.commons.math3.random.RandomGenerator;
 import org.apache.commons.math3.random.Well1024a;
 import org.junit.Assert;
+import org.junit.Ignore;
 import org.junit.Test;
 
 
-public class WelzlEncloserTest {
+public class WelzlEncloser2DTest {
 
     @Test
     public void testNullList() {
-        BallGenerator generator = new BallGenerator();
+        DiskGenerator generator = new DiskGenerator();
         WelzlEncloser<Euclidean2D, Vector2D> encloser =
                 new WelzlEncloser<Euclidean2D, Vector2D>(1.0e-10, 2, generator);
         EnclosingBall<Euclidean2D, Vector2D> ball = encloser.enclose(null);
@@ -42,7 +43,7 @@ public class WelzlEncloserTest {
 
     @Test
     public void testNoPoints() {
-        BallGenerator generator = new BallGenerator();
+        DiskGenerator generator = new DiskGenerator();
         WelzlEncloser<Euclidean2D, Vector2D> encloser =
                 new WelzlEncloser<Euclidean2D, Vector2D>(1.0e-10, 2, generator);
         EnclosingBall<Euclidean2D, Vector2D> ball = encloser.enclose(new ArrayList<Vector2D>());
@@ -52,16 +53,28 @@ public class WelzlEncloserTest {
     @Test
     public void testRegularPoints() {
         List<Vector2D> list = buildList(22, 26, 30, 38, 64, 28,  8, 54, 11, 15);
-        checkBall(list, Arrays.asList(list.get(2), list.get(3), list.get(4)));
+        checkDisk(list, Arrays.asList(list.get(2), list.get(3), list.get(4)));
     }
 
     @Test
     public void testSolutionOnDiameter() {
         List<Vector2D> list = buildList(22, 26, 30, 38, 64, 28,  8, 54);
-        checkBall(list, Arrays.asList(list.get(2), list.get(3)));
+        checkDisk(list, Arrays.asList(list.get(2), list.get(3)));
     }
 
     @Test
+    @Ignore // this test currently fails, it generate a ball that reduces at one iteration
+    public void testReducingBall() {
+        List<Vector2D> list = buildList(0.05380958511396061, 0.57332359658700000,
+                                        0.99348810731127870, 0.02056421361521466,
+                                        0.01203950647796437, 0.99779675042261860,
+                                        0.00810189987706078, 0.00589246003827815,
+                                        0.00465180821202149, 0.99219972923046940);
+        checkDisk(list, Arrays.asList(list.get(1), list.get(3), list.get(4)));
+    }
+
+    @Test
+    @Ignore // this test currently fails, it generate balls that reduce at some iterations
     public void testLargeSamples() {
         RandomGenerator random = new Well1024a(0xa2a63cad12c01fb2l);
         for (int k = 0; k < 100; ++k) {
@@ -72,7 +85,7 @@ public class WelzlEncloserTest {
                 double y = random.nextDouble();
                 points.add(new Vector2D(x, y));
             }
-            checkBall(points);
+            checkDisk(points);
         }
     }
 
@@ -84,19 +97,19 @@ public class WelzlEncloserTest {
         return list;
     }
 
-    private void checkBall(List<Vector2D> points, List<Vector2D> refSupport) {
+    private void checkDisk(List<Vector2D> points, List<Vector2D> refSupport) {
 
-        EnclosingBall<Euclidean2D, Vector2D> ball = checkBall(points);
+        EnclosingBall<Euclidean2D, Vector2D> disk = checkDisk(points);
 
-        // compare computed ball with expected ball
-        BallGenerator generator = new BallGenerator();
+        // compare computed disk with expected disk
+        DiskGenerator generator = new DiskGenerator();
         EnclosingBall<Euclidean2D, Vector2D> expected = generator.ballOnSupport(refSupport);
-        Assert.assertEquals(refSupport.size(), ball.getSupportSize());
-        Assert.assertEquals(expected.getRadius(),        ball.getRadius(),        1.0e-10);
-        Assert.assertEquals(expected.getCenter().getX(), ball.getCenter().getX(), 1.0e-10);
-        Assert.assertEquals(expected.getCenter().getY(), ball.getCenter().getY(), 1.0e-10);
+        Assert.assertEquals(refSupport.size(), disk.getSupportSize());
+        Assert.assertEquals(expected.getRadius(),        disk.getRadius(),        1.0e-10);
+        Assert.assertEquals(expected.getCenter().getX(), disk.getCenter().getX(), 1.0e-10);
+        Assert.assertEquals(expected.getCenter().getY(), disk.getCenter().getY(), 1.0e-10);
 
-        for (Vector2D s : ball.getSupport()) {
+        for (Vector2D s : disk.getSupport()) {
             boolean found = false;
             for (Vector2D rs : refSupport) {
                 if (s == rs) {
@@ -106,19 +119,19 @@ public class WelzlEncloserTest {
             Assert.assertTrue(found);
         }
 
-        // check removing any point of the support ball fails to enclose the point
-        for (int i = 0; i < ball.getSupportSize(); ++i) {
+        // check removing any point of the support disk fails to enclose the point
+        for (int i = 0; i < disk.getSupportSize(); ++i) {
             List<Vector2D> reducedSupport = new ArrayList<Vector2D>();
             int count = 0;
-            for (Vector2D s : ball.getSupport()) {
+            for (Vector2D s : disk.getSupport()) {
                 if (count++ != i) {
                     reducedSupport.add(s);
                 }
             }
-            EnclosingBall<Euclidean2D, Vector2D> reducedBall = generator.ballOnSupport(reducedSupport);
+            EnclosingBall<Euclidean2D, Vector2D> reducedDisk = generator.ballOnSupport(reducedSupport);
             boolean foundOutside = false;
             for (int j = 0; j < points.size() && !foundOutside; ++j) {
-                if (!reducedBall.contains(points.get(j), 1.0e-10)) {
+                if (!reducedDisk.contains(points.get(j), 1.0e-10)) {
                     foundOutside = true;
                 }
             }
@@ -127,31 +140,31 @@ public class WelzlEncloserTest {
 
     }
 
-    private EnclosingBall<Euclidean2D, Vector2D> checkBall(List<Vector2D> points) {
+    private EnclosingBall<Euclidean2D, Vector2D> checkDisk(List<Vector2D> points) {
 
         WelzlEncloser<Euclidean2D, Vector2D> encloser =
-                new WelzlEncloser<Euclidean2D, Vector2D>(1.0e-10, 2, new BallGenerator());
-        EnclosingBall<Euclidean2D, Vector2D> ball = encloser.enclose(points);
+                new WelzlEncloser<Euclidean2D, Vector2D>(1.0e-10, 2, new DiskGenerator());
+        EnclosingBall<Euclidean2D, Vector2D> disk = encloser.enclose(points);
 
         // all points are enclosed
         for (Vector2D v : points) {
-            Assert.assertTrue(ball.contains(v, 1.0e-10));
+            Assert.assertTrue(disk.contains(v, 1.0e-10));
         }
 
         for (Vector2D v : points) {
             boolean inSupport = false;
-            for (Vector2D s : ball.getSupport()) {
+            for (Vector2D s : disk.getSupport()) {
                 if (v == s) {
                     inSupport = true;
                 }
             }
             if (inSupport) {
                 // points on the support should be outside of reduced ball
-                Assert.assertFalse(ball.contains(v, -0.001));
+                Assert.assertFalse(disk.contains(v, -0.001));
             }
         }
 
-        return ball;
+        return disk;
 
     }
 

Propchange: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/enclosing/WelzlEncloser2DTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/enclosing/WelzlEncloser2DTest.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/enclosing/WelzlEncloser3DTest.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/enclosing/WelzlEncloser3DTest.java?rev=1562573&view=auto
==============================================================================
--- commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/enclosing/WelzlEncloser3DTest.java (added)
+++ commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/enclosing/WelzlEncloser3DTest.java Wed Jan 29 20:19:20 2014
@@ -0,0 +1,192 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.math3.geometry.enclosing;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.commons.math3.geometry.euclidean.threed.Euclidean3D;
+import org.apache.commons.math3.geometry.euclidean.threed.SphereGenerator;
+import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
+import org.apache.commons.math3.random.RandomGenerator;
+import org.apache.commons.math3.random.UnitSphereRandomVectorGenerator;
+import org.apache.commons.math3.random.Well1024a;
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+
+
+public class WelzlEncloser3DTest {
+
+    @Test
+    public void testNullList() {
+        SphereGenerator generator = new SphereGenerator();
+        WelzlEncloser<Euclidean3D, Vector3D> encloser =
+                new WelzlEncloser<Euclidean3D, Vector3D>(1.0e-10, 2, generator);
+        EnclosingBall<Euclidean3D, Vector3D> ball = encloser.enclose(null);
+        Assert.assertTrue(ball.getRadius() < 0);
+    }
+
+    @Test
+    public void testNoPoints() {
+        SphereGenerator generator = new SphereGenerator();
+        WelzlEncloser<Euclidean3D, Vector3D> encloser =
+                new WelzlEncloser<Euclidean3D, Vector3D>(1.0e-10, 2, generator);
+        EnclosingBall<Euclidean3D, Vector3D> ball = encloser.enclose(new ArrayList<Vector3D>());
+        Assert.assertTrue(ball.getRadius() < 0);
+    }
+
+    @Test
+    @Ignore // this test currently fails, it generates an infinite loop
+    public void testInfiniteLoop() {
+        // this test used to generate an infinite loop
+        List<Vector3D> list =
+                Arrays.asList(new Vector3D( -0.89227075512164380,  -2.89317694645713900,  14.84572323743355500),
+                              new Vector3D( -0.92099498940693580,  -2.31086108263908940,  12.92071026467688300),
+                              new Vector3D( -0.85227999411005200,  -3.06314731441320730,  15.40163831651287000),
+                              new Vector3D( -1.77399413020785970,  -3.65630391378114260,  14.13190097751873400),
+                              new Vector3D(  0.33157833272465354,  -2.22813591757792160,  14.21225234159008200),
+                              new Vector3D( -1.53065579165484400,  -1.65692084770139570,  14.61483055714788500),
+                              new Vector3D( -1.08457093941217140,  -1.96100325935602980,  13.09265170575555000),
+                              new Vector3D(  0.30029469589708850,  -3.05470831395667370,  14.56352400426342600),
+                              new Vector3D( -0.95007443938638460,  -1.86810946486118360,  15.14491234340057000),
+                              new Vector3D( -1.89661503804130830,  -2.17004080885185860,  14.81235128513927000),
+                              new Vector3D( -0.72193328761607530,  -1.44513142833618270,  14.52355724218561800),
+                              new Vector3D( -0.26895980939606550,  -3.69512371522084140,  14.72272846327652000),
+                              new Vector3D( -1.53501693431786170,  -3.25055166611021900,  15.15509062584274800),
+                              new Vector3D( -0.71727553535519410,  -3.62284279460799100,  13.26256700929380700),
+                              new Vector3D( -0.30220950676137365,  -3.25410412500779070,  13.13682612771606000),
+                              new Vector3D( -0.04543996608267075,  -1.93081853923797750,  14.79497997883171400),
+                              new Vector3D( -1.53348892951571640,  -3.66688919703524900,  14.73095600812074200),
+                              new Vector3D( -0.98034899533935820,  -3.34004481162763960,  13.03245014017556800));
+
+        WelzlEncloser<Euclidean3D, Vector3D> encloser =
+                new WelzlEncloser<Euclidean3D, Vector3D>(1.0e-10, 2, new SphereGenerator());
+        EnclosingBall<Euclidean3D, Vector3D> ball = encloser.enclose(list);
+        Assert.assertTrue(ball.getRadius() > 0);
+    }
+
+    @Test
+    @Ignore // this test currently fails, it generates an infinite loop
+    public void testLargeSamples() {
+        RandomGenerator random = new Well1024a(0x35ddecfc78131e1dl);
+        final UnitSphereRandomVectorGenerator sr = new UnitSphereRandomVectorGenerator(3, random);
+        for (int k = 0; k < 100; ++k) {
+
+            // define the reference sphere we want to compute
+            double d = 25 * random.nextDouble();
+            double refRadius = 10 * random.nextDouble();
+            Vector3D refCenter = new Vector3D(d, new Vector3D(sr.nextVector()));
+            List<Vector3D> support = new ArrayList<Vector3D>();
+            for (int i = 0; i < 4; ++i) {
+                support.add(new Vector3D(1.0, refCenter, refRadius, new Vector3D(sr.nextVector())));
+            }
+
+            // set up a large sample inside the reference sphere
+            int nbPoints = random.nextInt(10000);
+            System.out.println(nbPoints);
+            List<Vector3D> points = new ArrayList<Vector3D>();
+            for (int i = 0; i < nbPoints; ++i) {
+                double r = refRadius * random.nextDouble();
+                points.add(new Vector3D(1.0, refCenter, r, new Vector3D(sr.nextVector())));
+            }
+
+            // hide the support point belonging to sphere boundary in the sample
+            points.add(random.nextInt(nbPoints), support.get(0));
+            points.add(random.nextInt(nbPoints), support.get(1));
+            points.add(random.nextInt(nbPoints), support.get(2));
+            points.add(random.nextInt(nbPoints), support.get(3));
+
+            // test we find our sphere again
+            checkSphere(points, support);
+
+        }
+    }
+
+    private void checkSphere(List<Vector3D> points, List<Vector3D> refSupport) {
+
+        EnclosingBall<Euclidean3D, Vector3D> Sphere = checkSphere(points);
+
+        // compare computed Sphere with expected Sphere
+        SphereGenerator generator = new SphereGenerator();
+        EnclosingBall<Euclidean3D, Vector3D> expected = generator.ballOnSupport(refSupport);
+        Assert.assertEquals(refSupport.size(), Sphere.getSupportSize());
+        Assert.assertEquals(expected.getRadius(),        Sphere.getRadius(),        1.0e-10);
+        Assert.assertEquals(expected.getCenter().getX(), Sphere.getCenter().getX(), 1.0e-10);
+        Assert.assertEquals(expected.getCenter().getY(), Sphere.getCenter().getY(), 1.0e-10);
+
+        for (Vector3D s : Sphere.getSupport()) {
+            boolean found = false;
+            for (Vector3D rs : refSupport) {
+                if (s == rs) {
+                    found = true;
+                }
+            }
+            Assert.assertTrue(found);
+        }
+
+        // check removing any point of the support Sphere fails to enclose the point
+        for (int i = 0; i < Sphere.getSupportSize(); ++i) {
+            List<Vector3D> reducedSupport = new ArrayList<Vector3D>();
+            int count = 0;
+            for (Vector3D s : Sphere.getSupport()) {
+                if (count++ != i) {
+                    reducedSupport.add(s);
+                }
+            }
+            EnclosingBall<Euclidean3D, Vector3D> reducedSphere = generator.ballOnSupport(reducedSupport);
+            boolean foundOutside = false;
+            for (int j = 0; j < points.size() && !foundOutside; ++j) {
+                if (!reducedSphere.contains(points.get(j), 1.0e-10)) {
+                    foundOutside = true;
+                }
+            }
+            Assert.assertTrue(foundOutside);
+        }
+
+    }
+
+    private EnclosingBall<Euclidean3D, Vector3D> checkSphere(List<Vector3D> points) {
+
+        WelzlEncloser<Euclidean3D, Vector3D> encloser =
+                new WelzlEncloser<Euclidean3D, Vector3D>(1.0e-10, 2, new SphereGenerator());
+        EnclosingBall<Euclidean3D, Vector3D> Sphere = encloser.enclose(points);
+
+        // all points are enclosed
+        for (Vector3D v : points) {
+            Assert.assertTrue(Sphere.contains(v, 1.0e-10));
+        }
+
+        for (Vector3D v : points) {
+            boolean inSupport = false;
+            for (Vector3D s : Sphere.getSupport()) {
+                if (v == s) {
+                    inSupport = true;
+                }
+            }
+            if (inSupport) {
+                // points on the support should be outside of reduced ball
+                Assert.assertFalse(Sphere.contains(v, -0.001));
+            }
+        }
+
+        return Sphere;
+
+    }
+
+}

Propchange: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/enclosing/WelzlEncloser3DTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/enclosing/WelzlEncloser3DTest.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"