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 2009/05/02 21:34:52 UTC

svn commit: r770979 - in /commons/proper/math/trunk/src: java/org/apache/commons/math/stat/clustering/ site/xdoc/ test/org/apache/commons/math/stat/clustering/

Author: luc
Date: Sat May  2 19:34:51 2009
New Revision: 770979

URL: http://svn.apache.org/viewvc?rev=770979&view=rev
Log:
added a clustering package with an implementation of k-means++
JIRA: MATH-266

Added:
    commons/proper/math/trunk/src/java/org/apache/commons/math/stat/clustering/
    commons/proper/math/trunk/src/java/org/apache/commons/math/stat/clustering/Cluster.java   (with props)
    commons/proper/math/trunk/src/java/org/apache/commons/math/stat/clustering/Clusterable.java
    commons/proper/math/trunk/src/java/org/apache/commons/math/stat/clustering/EuclideanIntegerPoint.java   (with props)
    commons/proper/math/trunk/src/java/org/apache/commons/math/stat/clustering/KMeansPlusPlusClusterer.java   (with props)
    commons/proper/math/trunk/src/java/org/apache/commons/math/stat/clustering/package.html   (with props)
    commons/proper/math/trunk/src/test/org/apache/commons/math/stat/clustering/
    commons/proper/math/trunk/src/test/org/apache/commons/math/stat/clustering/KMeansPlusPlusClustererTest.java   (with props)
Modified:
    commons/proper/math/trunk/src/site/xdoc/changes.xml

Added: commons/proper/math/trunk/src/java/org/apache/commons/math/stat/clustering/Cluster.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/java/org/apache/commons/math/stat/clustering/Cluster.java?rev=770979&view=auto
==============================================================================
--- commons/proper/math/trunk/src/java/org/apache/commons/math/stat/clustering/Cluster.java (added)
+++ commons/proper/math/trunk/src/java/org/apache/commons/math/stat/clustering/Cluster.java Sat May  2 19:34:51 2009
@@ -0,0 +1,74 @@
+/*
+ * 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.math.stat.clustering;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Cluster holding a set of {@link Clusterable} points.
+ * @param <T> the type of points that can be clustered
+ * @version $Revision$ $Date$
+ * @since 2.0
+ */
+public class Cluster<T extends Clusterable<T>> implements Serializable {
+
+    /** Serializable version identifier. */
+    private static final long serialVersionUID = -1741417096265465690L;
+
+    /** The points contained in this cluster. */
+    final List<T> points;
+
+    /** Center of the cluster. */
+    final T center;
+
+    /**
+     * Build a cluster centered at a specified point.
+     * @param center the point which is to be the center of this cluster
+     */
+    public Cluster(final T center) {
+        this.center = center;
+        points = new ArrayList<T>();
+    }
+
+    /**
+     * Add a point to this cluster.
+     * @param point point to add
+     */
+    public void addPoint(final T point) {
+        points.add(point);
+    }
+
+    /**
+     * Get the points contained in the cluster.
+     * @return points contained in the cluster
+     */
+    public List<T> getPoints() {
+        return points;
+    }
+
+    /**
+     * Get the point chosen to be the center of this cluster.
+     * @return chosen cluster center
+     */
+    public T getCenter() {
+        return center;
+    }
+
+}

Propchange: commons/proper/math/trunk/src/java/org/apache/commons/math/stat/clustering/Cluster.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/math/trunk/src/java/org/apache/commons/math/stat/clustering/Cluster.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: commons/proper/math/trunk/src/java/org/apache/commons/math/stat/clustering/Clusterable.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/java/org/apache/commons/math/stat/clustering/Clusterable.java?rev=770979&view=auto
==============================================================================
--- commons/proper/math/trunk/src/java/org/apache/commons/math/stat/clustering/Clusterable.java (added)
+++ commons/proper/math/trunk/src/java/org/apache/commons/math/stat/clustering/Clusterable.java Sat May  2 19:34:51 2009
@@ -0,0 +1,47 @@
+/*
+ * 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.math.stat.clustering;
+
+import java.io.Serializable;
+import java.util.Collection;
+
+/**
+ * Interface for points that can be clustered together.
+ * @param <T> the type of point that can be clustered
+ * @version $Revision$ $Date$
+ * @since 2.0
+ */
+public interface Clusterable<T> extends Serializable {
+
+    /**
+     * Returns the distance from the given point.
+     * 
+     * @param p the point to compute the distance from
+     * @return the distance from the given point
+     */
+    double distanceFrom(T p);
+
+    /**
+     * Returns the centroid of the given Collection of points.
+     * 
+     * @param p the Collection of points to compute the centroid of
+     * @return the centroid of the given Collection of Points
+     */
+    T centroidOf(Collection<T> p);
+
+}

Added: commons/proper/math/trunk/src/java/org/apache/commons/math/stat/clustering/EuclideanIntegerPoint.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/java/org/apache/commons/math/stat/clustering/EuclideanIntegerPoint.java?rev=770979&view=auto
==============================================================================
--- commons/proper/math/trunk/src/java/org/apache/commons/math/stat/clustering/EuclideanIntegerPoint.java (added)
+++ commons/proper/math/trunk/src/java/org/apache/commons/math/stat/clustering/EuclideanIntegerPoint.java Sat May  2 19:34:51 2009
@@ -0,0 +1,98 @@
+/*
+ * 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.math.stat.clustering;
+
+import java.util.Collection;
+
+import org.apache.commons.math.util.MathUtils;
+
+/**
+ * A simple implementation of {@link Clusterable} for points with integer coordinates.
+ * @version $Revision$ $Date$
+ * @since 2.0
+ */
+public class EuclideanIntegerPoint implements Clusterable<EuclideanIntegerPoint> {
+
+    /** Serializable version identifier. */
+    private static final long serialVersionUID = 3946024775784901369L;
+
+    /** Point coordinates. */
+    private final int[] point;
+
+    /**
+     * @param point the n-dimensional point in integer space
+     */
+    public EuclideanIntegerPoint(final int[] point) {
+        this.point = point;
+    }
+
+    /**
+     * Returns the n-dimensional point in integer space
+     */
+    public int[] getPoint() {
+        return point;
+    }
+
+    /** {@inheritDoc} */
+    public double distanceFrom(final EuclideanIntegerPoint p) {
+        return MathUtils.distance(point, p.getPoint());
+    }
+
+    /** {@inheritDoc} */
+    public EuclideanIntegerPoint centroidOf(final Collection<EuclideanIntegerPoint> points) {
+        int[] centroid = new int[getPoint().length];
+        for (EuclideanIntegerPoint p : points) {
+            for (int i = 0; i < centroid.length; i++) {
+                centroid[i] += p.getPoint()[i];
+            }
+        }
+        for (int i = 0; i < centroid.length; i++) {
+            centroid[i] /= points.size();
+        }
+        return new EuclideanIntegerPoint(centroid);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(final Object other) {
+        if (!(other instanceof EuclideanIntegerPoint)) {
+            return false;
+        }
+        final int[] otherPoint = ((EuclideanIntegerPoint) other).getPoint();
+        if (point.length != otherPoint.length) {
+            return false;
+        }
+        for (int i = 0; i < point.length; i++) {
+            if (point[i] != otherPoint[i]) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        int hashCode = 0;
+        for (Integer i : point) {
+            hashCode += i.hashCode() * 13 + 7;
+        }
+        return hashCode;
+    }
+
+}

Propchange: commons/proper/math/trunk/src/java/org/apache/commons/math/stat/clustering/EuclideanIntegerPoint.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/math/trunk/src/java/org/apache/commons/math/stat/clustering/EuclideanIntegerPoint.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: commons/proper/math/trunk/src/java/org/apache/commons/math/stat/clustering/KMeansPlusPlusClusterer.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/java/org/apache/commons/math/stat/clustering/KMeansPlusPlusClusterer.java?rev=770979&view=auto
==============================================================================
--- commons/proper/math/trunk/src/java/org/apache/commons/math/stat/clustering/KMeansPlusPlusClusterer.java (added)
+++ commons/proper/math/trunk/src/java/org/apache/commons/math/stat/clustering/KMeansPlusPlusClusterer.java Sat May  2 19:34:51 2009
@@ -0,0 +1,161 @@
+/*
+ * 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.math.stat.clustering;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Random;
+
+/**
+ * Clustering algorithm based on David Arthur and Sergei Vassilvitski k-means++ algorithm.
+ * @see <a href="http://en.wikipedia.org/wiki/K-means%2B%2B">K-means++ (wikipedia)</a>
+ * @version $Revision$ $Date$
+ * @since 2.0
+ */
+public class KMeansPlusPlusClusterer<T extends Clusterable<T>> {
+
+    /** Random generator for choosing initial centers. */
+    private final Random random;
+
+    /** Build a clusterer.
+     * @param random random generator to use for choosing initial centers
+     */
+    public KMeansPlusPlusClusterer(final Random random) {
+        this.random = random;
+    }
+
+    /**
+     * Runs the K-means++ clustering algorithm.
+     * 
+     * @param points the points to cluster
+     * @param k the number of clusters to split the data into
+     * @param maxIterations the maximum number of iterations to run the algorithm
+     *     for.  If negative, no maximum will be used
+     * @return a list of clusters containing the points
+     */
+    public List<Cluster<T>> cluster(final Collection<T> points,
+                                    final int k, final int maxIterations) {
+        // create the initial clusters
+        List<Cluster<T>> clusters = chooseInitialCenters(points, k, random);
+        assignPointsToClusters(clusters, points);
+
+        // iterate through updating the centers until we're done
+        final int max = (maxIterations < 0) ? Integer.MAX_VALUE : maxIterations; 
+        for (int count = 0; count < max; count++) {
+            boolean clusteringChanged = false;
+            List<Cluster<T>> newClusters = new ArrayList<Cluster<T>>();
+            for (final Cluster<T> cluster : clusters) {
+                final T newCenter = cluster.getCenter().centroidOf(cluster.getPoints());
+                if (!newCenter.equals(cluster.getCenter())) {
+                    clusteringChanged = true;
+                }
+                newClusters.add(new Cluster<T>(newCenter));
+            }
+            if (!clusteringChanged) {
+                return clusters;
+            }
+            assignPointsToClusters(newClusters, points);
+            clusters = newClusters;
+        }
+        return clusters;
+    }
+
+    /**
+     * Adds the given points to the closest {@link Cluster}.
+     * 
+     * @param clusters the {@link Cluster}s to add the points to
+     * @param points the points to add to the given {@link Cluster}s
+     */
+    private static <T extends Clusterable<T>> void
+        assignPointsToClusters(final Collection<Cluster<T>> clusters, final Collection<T> points) {
+        for (final T p : points) {
+            Cluster<T> cluster = getNearestCluster(clusters, p);
+            cluster.addPoint(p);
+        }
+    }
+
+    /**
+     * Use K-means++ to choose the initial centers.
+     * 
+     * @param points the points to choose the initial centers from
+     * @param k the number of centers to choose
+     * @param random random generator to use
+     * @return the initial centers
+     */
+    private static <T extends Clusterable<T>> List<Cluster<T>>
+        chooseInitialCenters(final Collection<T> points, final int k, final Random random) {
+
+        final List<T> pointSet = new ArrayList<T>(points);
+        final List<Cluster<T>> resultSet = new ArrayList<Cluster<T>>();
+
+        // Choose one center uniformly at random from among the data points.
+        final T firstPoint = pointSet.remove(random.nextInt(pointSet.size()));
+        resultSet.add(new Cluster<T>(firstPoint));
+
+        final double[] dx2 = new double[pointSet.size()];
+        while (resultSet.size() < k) {
+            // For each data point x, compute D(x), the distance between x and 
+            // the nearest center that has already been chosen.
+            int sum = 0;
+            for (int i = 0; i < pointSet.size(); i++) {
+                final T p = pointSet.get(i);
+                final Cluster<T> nearest = getNearestCluster(resultSet, p);
+                final double d = p.distanceFrom(nearest.getCenter());
+                sum += d * d;
+                dx2[i] = sum;
+            }
+
+            // Add one new data point as a center. Each point x is chosen with
+            // probability proportional to D(x)2
+            final double r = random.nextDouble() * sum;
+            for (int i = 0 ; i < dx2.length; i++) {
+                if (dx2[i] >= r) {
+                    final T p = pointSet.remove(i);
+                    resultSet.add(new Cluster<T>(p));
+                    break;
+                }
+            }
+        }
+
+        return resultSet;
+
+    }
+
+    /**
+     * Returns the nearest {@link Cluster} to the given point
+     * 
+     * @param clusters the {@link Cluster}s to search
+     * @param point the point to find the nearest {@link Cluster} for
+     * @return the nearest {@link Cluster} to the given point
+     */
+    private static <T extends Clusterable<T>> Cluster<T>
+        getNearestCluster(final Collection<Cluster<T>> clusters, final T point) {
+        double minDistance = Double.MAX_VALUE;
+        Cluster<T> minCluster = null;
+        for (final Cluster<T> c : clusters) {
+            final double distance = point.distanceFrom(c.getCenter());
+            if (distance < minDistance) {
+                minDistance = distance;
+                minCluster = c;
+            }
+        }
+        return minCluster;
+    }
+
+}

Propchange: commons/proper/math/trunk/src/java/org/apache/commons/math/stat/clustering/KMeansPlusPlusClusterer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/math/trunk/src/java/org/apache/commons/math/stat/clustering/KMeansPlusPlusClusterer.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: commons/proper/math/trunk/src/java/org/apache/commons/math/stat/clustering/package.html
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/java/org/apache/commons/math/stat/clustering/package.html?rev=770979&view=auto
==============================================================================
--- commons/proper/math/trunk/src/java/org/apache/commons/math/stat/clustering/package.html (added)
+++ commons/proper/math/trunk/src/java/org/apache/commons/math/stat/clustering/package.html Sat May  2 19:34:51 2009
@@ -0,0 +1,20 @@
+<html>
+<!--
+   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.
+  -->
+    <!-- $Revision$ $Date$ -->
+    <body>Clustering algorithms</body>
+</html>

Propchange: commons/proper/math/trunk/src/java/org/apache/commons/math/stat/clustering/package.html
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/math/trunk/src/java/org/apache/commons/math/stat/clustering/package.html
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Modified: commons/proper/math/trunk/src/site/xdoc/changes.xml
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/site/xdoc/changes.xml?rev=770979&r1=770978&r2=770979&view=diff
==============================================================================
--- commons/proper/math/trunk/src/site/xdoc/changes.xml (original)
+++ commons/proper/math/trunk/src/site/xdoc/changes.xml Sat May  2 19:34:51 2009
@@ -39,6 +39,9 @@
   </properties>
   <body>
     <release version="2.0" date="TBD" description="TBD">
+      <action dev="luc" type="add" issue="MATH-266" due-to="Benjamin McCann">
+        Added a clustering package with an implementation of the k-means++ algorithm
+      </action>
       <action dev="luc" type="fix" issue="MATH-265" due-to="Benjamin McCann">
         Added distance1, distance and distanceInf utility methods for double and
         int arrays in MathUtils

Added: commons/proper/math/trunk/src/test/org/apache/commons/math/stat/clustering/KMeansPlusPlusClustererTest.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/org/apache/commons/math/stat/clustering/KMeansPlusPlusClustererTest.java?rev=770979&view=auto
==============================================================================
--- commons/proper/math/trunk/src/test/org/apache/commons/math/stat/clustering/KMeansPlusPlusClustererTest.java (added)
+++ commons/proper/math/trunk/src/test/org/apache/commons/math/stat/clustering/KMeansPlusPlusClustererTest.java Sat May  2 19:34:51 2009
@@ -0,0 +1,97 @@
+/*
+ * 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.math.stat.clustering;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+
+import org.junit.Test;
+
+public class KMeansPlusPlusClustererTest {
+
+    @Test
+    public void dimension2() {
+        KMeansPlusPlusClusterer<EuclideanIntegerPoint> transformer =
+            new KMeansPlusPlusClusterer<EuclideanIntegerPoint>(new Random(1746432956321l));
+        EuclideanIntegerPoint[] points = new EuclideanIntegerPoint[] {
+
+                // first expected cluster
+                new EuclideanIntegerPoint(new int[] { -15,  3 }),
+                new EuclideanIntegerPoint(new int[] { -15,  4 }),
+                new EuclideanIntegerPoint(new int[] { -15,  5 }),
+                new EuclideanIntegerPoint(new int[] { -14,  3 }),
+                new EuclideanIntegerPoint(new int[] { -14,  5 }),
+                new EuclideanIntegerPoint(new int[] { -13,  3 }),
+                new EuclideanIntegerPoint(new int[] { -13,  4 }),
+                new EuclideanIntegerPoint(new int[] { -13,  5 }),
+
+                // second expected cluster
+                new EuclideanIntegerPoint(new int[] { -1,  0 }),
+                new EuclideanIntegerPoint(new int[] { -1, -1 }),
+                new EuclideanIntegerPoint(new int[] {  0, -1 }),
+                new EuclideanIntegerPoint(new int[] {  1, -1 }),
+                new EuclideanIntegerPoint(new int[] {  1, -2 }),
+
+                // third expected cluster
+                new EuclideanIntegerPoint(new int[] { 13,  3 }),
+                new EuclideanIntegerPoint(new int[] { 13,  4 }),
+                new EuclideanIntegerPoint(new int[] { 14,  4 }),
+                new EuclideanIntegerPoint(new int[] { 14,  7 }),
+                new EuclideanIntegerPoint(new int[] { 16,  5 }),
+                new EuclideanIntegerPoint(new int[] { 16,  6 }),
+                new EuclideanIntegerPoint(new int[] { 17,  4 }),
+                new EuclideanIntegerPoint(new int[] { 17,  7 })
+
+        };
+        List<Cluster<EuclideanIntegerPoint>> clusters =
+            transformer.cluster(Arrays.asList(points), 3, 10);
+
+        assertEquals(3, clusters.size());
+        boolean cluster1Found = false;
+        boolean cluster2Found = false;
+        boolean cluster3Found = false;
+        for (Cluster<EuclideanIntegerPoint> cluster : clusters) {
+            int[] center = cluster.getCenter().getPoint();
+            if (center[0] < 0) {
+                cluster1Found = true;
+                assertEquals(8, cluster.getPoints().size());
+                assertEquals(-14, center[0]);
+                assertEquals( 4, center[1]);
+            } else if (center[1] < 0) {
+                cluster2Found = true;
+                assertEquals(5, cluster.getPoints().size());
+                assertEquals( 0, center[0]);
+                assertEquals(-1, center[1]);
+            } else {
+                cluster3Found = true;
+                assertEquals(8, cluster.getPoints().size());
+                assertEquals(15, center[0]);
+                assertEquals(5, center[1]);
+            }
+        }
+        assertTrue(cluster1Found);
+        assertTrue(cluster2Found);
+        assertTrue(cluster3Found);
+
+    }
+
+}

Propchange: commons/proper/math/trunk/src/test/org/apache/commons/math/stat/clustering/KMeansPlusPlusClustererTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/math/trunk/src/test/org/apache/commons/math/stat/clustering/KMeansPlusPlusClustererTest.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision