package me.mcnelis.rudder.ml.unsupervised.clustering;
import java.util.ArrayList;
import java.util.Arrays;
import me.mcnelis.rudder.data.collections.RudderList;
import org.apache.commons.math.stat.descriptive.SynchronizedSummaryStatistics;
/**
* Specialized RecordList for housing and performing operations within a cluster
* (i.e. holding a centroid
*
* @author dmcnelis
*
*/
public class Cluster<T> extends RudderList<T>
{
/**
*
*/
private static final long serialVersionUID = 1L;
protected double[] centroid;
public Cluster()
{
}
public void addRecord(T r)
{
this.add(r);
}
@SuppressWarnings("unchecked")
public void combineClusters(Cluster<?> cluster)
{
for (Object o : cluster.getRecords())
{
if (!this.contains(o))
{
this.add((T) o);
}
}
}
public Cluster<T> getRecords()
{
return this;
}
public double[] getCentroid()
{
if (this.centroid != null)
{
return this.centroid.clone();
}
return this.calculateCentroid();
}
public void setCentroid(double[] d)
{
this.centroid = d.clone();
}
/**
* Cycles through elements in the list to average each element against the
* other records to create a centroid used in some forms of clustering
* algorithms.
*
* @return double array representing centroid
*/
protected synchronized double[] calculateCentroid()
{
this.centroid = new double[this.getUnsupervisedDoubleArray(this.get(0)).length];
ArrayList<SynchronizedSummaryStatistics> stats = new ArrayList<SynchronizedSummaryStatistics>();
for (Object elem : this)
{
double[] arr = this.getUnsupervisedDoubleArray(elem);
for (int i = 0; i < arr.length; i++)
{
SynchronizedSummaryStatistics stat;
try
{
stat = stats.get(i);
}
catch (IndexOutOfBoundsException aiobe)
{
stat = new SynchronizedSummaryStatistics();
stats.add(i, stat);
}
stat.addValue(arr[i]);
}
}
for (int i = 0; i < this.centroid.length; i++)
{
this.centroid[i] = stats.get(i).getMean();
}
return this.centroid;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + Arrays.hashCode(centroid);
result = prime * result;
return result;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
if (obj == null)
{
return false;
}
if (!(obj instanceof Cluster<?>))
{
return false;
}
@SuppressWarnings("unchecked")
Cluster<T> other = (Cluster<T>) obj;
if (!Arrays.equals(centroid, other.centroid))
{
return false;
}
return true;
}
public boolean isAssigned(Object o)
{
// TODO Auto-generated method stub
return false;
}
}