All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jgrasstools.gears.utils.clustering.GvmCluster Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2007 Tom Gibara
 * 
 * Licensed 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.jgrasstools.gears.utils.clustering;

/**
 * A cluster of points.
 * 
 * @author Tom Gibara
 *
 * @param  the key type
 */

public class GvmCluster {

	/**
	 * The set of clusters to which this cluster belongs
	 */
	
	final GvmClusters clusters;
	
	/**
	 * The pairings of this cluster with all other clusters.
	 */
	
	final GvmClusterPair[] pairs;

	/**
	 * Whether this cluster is in the process of being removed.
	 */
	
	boolean removed;
	
	/**
	 * The number of points in this cluster.
	 */
	
	int count;
	
	/**
	 * The total mass of this cluster.
	 */
	
	double m0;
	
	/**
	 * The mass-weighted coordinate sum.
	 */
	
	final Object m1;
	
	/**
	 * The mass-weighted coordinate-square sum.
	 */
	
	final Object m2;
	
	/**
	 * The computed variance of this cluster
	 */
	
	double var;
	
	/**
	 * The key associated with this cluster.
	 */
	
	K key;
	
	// constructors
	
	@SuppressWarnings("unchecked")
	GvmCluster(GvmClusters clusters) {
		this.clusters = clusters;
		removed = false;
		count = 0;
		m0 = 0.0;
		m1 = clusters.space.newOrigin();
		m2 = clusters.space.newOrigin();
		pairs = new GvmClusterPair[clusters.capacity];
		update();
	}
	
	// public accessors
	
	/**
	 * The total mass of the cluster.
	 */

	public double getMass() {
		return m0;
	}
	
	/**
	 * The number of points in the cluster.
	 */
	
	public int getCount() {
		return count;
	}
	
	/**
	 * The computed variance of the cluster
	 */

	public double getVariance() {
		return var;
	}
	
	/**
	 * The key associated with the cluster, may be null.
	 */

	public K getKey() {
		return key;
	}

	// package methods

	/**
	 * Completely clears this cluster. All points and their associated mass is
	 * removed along with any key that was assigned to the cluster,
	 */
	
	void clear() {
		count = 0;
		m0 = 0.0;
		clusters.space.setToOrigin(m1);
		clusters.space.setToOrigin(m2);
		var = 0.0;
		key = null;
	}

	/**
	 * Sets this cluster equal to a single point.
	 * 
	 * @param m
	 *            the mass of the point
	 * @param pt
	 *            the coordinates of the point
	 */

	void set(final double m, final Object pt) {
		if (m == 0.0) {
			if (count != 0) {
				clusters.space.setToOrigin(m1);
				clusters.space.setToOrigin(m2);
			}
		} else {
			clusters.space.setToScaled(m1, m, pt);
			clusters.space.setToScaledSqr(m2, m, pt);
		}
		count = 1;
		m0 = m;
		var = 0.0;
	}
	
	/**
	 * Adds a point to the cluster.
	 * 
	 * @param m
	 *            the mass of the point
	 * @param pt
	 *            the coordinates of the point
	 */
	
	void add(final double m, final Object pt) {
		if (count == 0) {
			set(m, pt);
		} else {
			count += 1;
			
			if (m != 0.0) {
				m0 += m;
				clusters.space.addScaled(m1, m, pt);
				clusters.space.addScaledSqr(m2, m, pt);
				update();
			}
		}
	}
	
	/**
	 * Sets this cluster equal to the specified cluster
	 * 
	 * @param cluster a cluster, not this or null
	 */
	
	void set(GvmCluster cluster) {
		if (cluster == this) throw new IllegalArgumentException("cannot set cluster to itself");
		
		m0 = cluster.m0;
		clusters.space.setTo(m1, cluster.m1);
		clusters.space.setTo(m2, cluster.m2);
		var = cluster.var;
	}
	
	/**
	 * Adds the specified cluster to this cluster.
	 * 
	 * @param cluster the cluster to be added
	 */
	
	void add(GvmCluster cluster) {
		if (cluster == this) throw new IllegalArgumentException();
		if (cluster.count == 0) return; //nothing to do
		
		if (count == 0) {
			set(cluster);
		} else {
			count += cluster.count;
			//TODO accelerate add
			m0 += cluster.m0;
            clusters.space.add(m1, cluster.m1);
            clusters.space.add(m2, cluster.m2);
			update();
		}
	}
	
	/**
	 * Computes this clusters variance if it were to have a new point added to it.
	 * 
	 * @param m the mass of the point
	 * @param pt the coordinates of the point
	 * @return the variance of this cluster inclusive of the point
	 */
	
	double test(double m, Object pt) {
		return m0 == 0.0 && m == 0.0 ? 0.0 : clusters.space.variance(m0, m1, m2, m, pt) - var;
	}

	/**
	 * Computes the variance of a cluster that aggregated this cluster with the
	 * supplied cluster.
	 * 
	 * @param cluster
	 *            another cluster
	 * @return the combined variance
	 */

	//TODO: change for consistency with other test method : return increase in variance
	double test(GvmCluster cluster) {
		return m0 == 0.0 && cluster.m0 == 0.0 ? 0.0 : clusters.space.variance(m0, m1, m2, cluster.m0, cluster.m1, cluster.m2);
	}

	// private utility methods
	
	/**
	 * Recompute this cluster's variance.
	 */
	
	private void update() {
		var = m0 == 0.0 ? 0.0 : clusters.space.variance(m0, m1, m2);
	}
	
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy