/*
* File: NormalizedCentroidClusterCreator.java
* Authors: Natasha Singh-Miller
* Company: Sandia National Laboratories
* Project: Cognitive Foundry
*
* Copyright 2011, Sandia Corporation. Under the terms of Contract
* DE-AC04-94AL85000, there is a non-exclusive license for use of this work by
* or on behalf of the U.S. Government. Export of this program may require a
* license from the United States Government. See CopyrightHistory.txt for
* complete details.
*/
package gov.sandia.cognition.learning.algorithm.clustering.cluster;
import gov.sandia.cognition.math.matrix.Vector;
import gov.sandia.cognition.math.matrix.Vectorizable;
import gov.sandia.cognition.util.AbstractCloneableSerializable;
import java.util.Collection;
import java.util.ArrayList;
/**
* A cluster creator for {@link NormalizedCentroidCluster}s which are clusters
* that have a normalized centroid in addition to the usual centroid. The
* normalized centroid is the centroid formed from normalizing each member of
* the cluster to have unit length.
*
* @author nsingh
*/
public class NormalizedCentroidClusterCreator
extends AbstractCloneableSerializable
implements
IncrementalClusterCreator<NormalizedCentroidCluster<Vectorizable>, Vectorizable>
{
/**
* Creates a new instance of VectorizableCentroidClusterCreator()
*/
public NormalizedCentroidClusterCreator()
{
super();
}
@Override
public NormalizedCentroidCluster<Vectorizable> createCluster()
{
return new NormalizedCentroidCluster<>(null, null, new ArrayList<>());
}
@Override
public NormalizedCentroidCluster<Vectorizable> createCluster(
final Collection<? extends Vectorizable> members)
{
if (members.isEmpty())
{
// No members to create the cluster from.
return new NormalizedCentroidCluster<>(null, null, members);
}
// We are going to create the centroid of the cluster.
Vectorizable centroid = null;
Vector data = null;
Vectorizable normalizedCentroid = null;
Vector normalizedData = null;
for (Vectorizable member : members)
{
Vector memberVector = member.convertToVector();
if (data == null)
{
centroid = member.clone();
data = memberVector.clone();
normalizedCentroid = member.clone();
normalizedData = memberVector.norm2() != 0.0
? memberVector.scale(1.0 / memberVector.norm2())
: memberVector;
}
else
{
data.plusEquals(memberVector);
if (memberVector.norm2() != 0.0)
{
normalizedData.plusEquals(memberVector.scale(1.0
/ memberVector.norm2()));
}
}
}
data.scaleEquals(1.0 / (double) members.size());
normalizedData.scaleEquals(1.0 / (double) members.size());
centroid.convertFromVector(data);
normalizedCentroid.convertFromVector(normalizedData);
return new NormalizedCentroidCluster<>(centroid,
normalizedCentroid, members);
}
@Override
public void addClusterMember(
final NormalizedCentroidCluster<Vectorizable> cluster,
final Vectorizable member)
{
Vectorizable centroid = cluster.getCentroid();
//add first member of cluster
if (centroid == null)
{
//set centroid
centroid = member.clone();
cluster.setCentroid(centroid);
//set normalized centroid
Vectorizable normalizedCentroid = member.clone();
Vector normalizedData = normalizedCentroid.convertToVector();
if (normalizedData.norm2() != 0.0)
{
normalizedData.scaleEquals(1.0 / normalizedData.norm2());
}
normalizedCentroid.convertFromVector(normalizedData);
cluster.setNormalizedCentroid(normalizedCentroid);
}
else
{
final int oldSize = cluster.getMembers().size();
final int newSize = oldSize + 1;
//set centroid
Vector data = centroid.convertToVector();
data.scaleEquals(oldSize);
data.plusEquals(member.convertToVector());
data.scaleEquals(1.0 / newSize);
centroid.convertFromVector(data);
cluster.setCentroid(centroid);
//set normalized centroid
Vectorizable normalizedCentroid = cluster.getNormalizedCentroid();
Vector normalizedData = normalizedCentroid.convertToVector();
normalizedData.scaleEquals(oldSize);
Vector normalizedMember = member.convertToVector().scale(1.0
/ member.convertToVector().norm2());
if (member.convertToVector().norm2() != 0.0)
{
normalizedData.plusEquals(normalizedMember);
}
normalizedData.scaleEquals(1.0 / newSize);
normalizedCentroid.convertFromVector(normalizedData);
cluster.setNormalizedCentroid(normalizedCentroid);
}
cluster.getMembers().add(member);
}
@Override
public boolean removeClusterMember(
final NormalizedCentroidCluster<Vectorizable> cluster,
final Vectorizable member)
{
if (cluster.getMembers().remove(member))
{
final int newSize = cluster.getMembers().size();
final int oldSize = newSize + 1;
if (newSize == 0)
{
cluster.setCentroid(null);
cluster.setNormalizedCentroid(null);
return true;
}
//reset centroid
Vectorizable centroid = cluster.getCentroid();
Vector data = centroid.convertToVector();
data.scaleEquals(oldSize);
data.minusEquals(member.convertToVector());
data.scaleEquals(1.0 / newSize);
centroid.convertFromVector(data);
cluster.setCentroid(centroid);
//reset normalized centroid
Vectorizable normalizedCentroid = cluster.getNormalizedCentroid();
Vector normalizedData = normalizedCentroid.convertToVector();
normalizedData.scaleEquals(oldSize);
if (member.convertToVector().norm2() != 0.0)
{
normalizedData.minusEquals(member.convertToVector().scale(1.0
/ member.convertToVector().norm2()));
}
normalizedData.scaleEquals(1.0 / newSize);
normalizedCentroid.convertFromVector(normalizedData);
cluster.setNormalizedCentroid(normalizedCentroid);
return true;
}
else
{
return false;
}
}
}