}
public ClusterOrderResult<D> run(Database database, Relation<NV> relation) {
Collection<DeLiCluTreeIndex<NV>> indexes = ResultUtil.filterResults(database, DeLiCluTreeIndex.class);
if(indexes.size() != 1) {
throw new AbortException("DeLiClu found " + indexes.size() + " DeLiCluTree indexes, expected exactly one.");
}
DeLiCluTreeIndex<NV> index = indexes.iterator().next();
// FIXME: check that the index matches the relation!
if(!(getDistanceFunction() instanceof SpatialPrimitiveDistanceFunction<?, ?>)) {
throw new IllegalArgumentException("Distance Function must be an instance of " + SpatialPrimitiveDistanceFunction.class.getName());
}
@SuppressWarnings("unchecked")
SpatialPrimitiveDistanceFunction<NV, D> distFunction = (SpatialPrimitiveDistanceFunction<NV, D>) getDistanceFunction();
// first do the knn-Join
if(logger.isVerbose()) {
logger.verbose("knnJoin...");
}
DataStore<KNNList<D>> knns = knnJoin.run(database, relation);
FiniteProgress progress = logger.isVerbose() ? new FiniteProgress("DeLiClu", relation.size(), logger) : null;
final int size = relation.size();
ClusterOrderResult<D> clusterOrder = new ClusterOrderResult<D>("DeLiClu Clustering", "deliclu-clustering");
heap = new UpdatableHeap<SpatialObjectPair>();
// add start object to cluster order and (root, root) to priority queue
DBID startID = getStartObject(relation);
clusterOrder.add(startID, null, distFunction.getDistanceFactory().infiniteDistance());
int numHandled = 1;
index.setHandled(startID, relation.get(startID));
SpatialDirectoryEntry rootEntry = (SpatialDirectoryEntry) index.getRootEntry();
SpatialObjectPair spatialObjectPair = new SpatialObjectPair(distFunction.getDistanceFactory().nullDistance(), rootEntry, rootEntry, true);
heap.add(spatialObjectPair);
while(numHandled < size) {
if(heap.isEmpty()) {
throw new AbortException("DeLiClu heap was empty when it shouldn't have been.");
}
SpatialObjectPair dataPair = heap.poll();
// pair of nodes
if(dataPair.isExpandable) {