use of de.lmu.ifi.dbs.elki.index.tree.LeafEntry in project elki by elki-project.
the class XSplitter method minimumOverlapSplit.
/**
* Perform an minimum overlap split. The
* {@link #chooseMinimumOverlapSplit(int, int, int, boolean) minimum overlap
* split} calculates the partition for the split dimension determined by
* {@link #chooseSplitAxis(Iterable, int, int) chooseSplitAxis}
* <code>(common split
* history, minFanout, maxEntries - minFanout + 1)</code> with the minimum
* overlap. This range may have been tested before (by the
* {@link #topologicalSplit()}), but for the minimum overlap test we need to
* test that anew. Note that this method returns <code>null</code>, if the
* minimum overlap split has a volume which is larger than the allowed
* <code>maxOverlap</code> ratio or if the tree's minimum fanout is not larger
* than the minimum directory size.
*
* @return distribution resulting from the minimum overlap split
*/
public SplitSorting minimumOverlapSplit() {
if (node.getEntry(0) instanceof LeafEntry) {
throw new IllegalArgumentException("The minimum overlap split will only be performed on directory nodes");
}
if (node.getNumEntries() < 2) {
throw new IllegalArgumentException("Splitting less than two entries is pointless.");
}
int maxEntries = tree.getDirCapacity() - 1;
int minFanout = tree.get_min_fanout();
if (node.getNumEntries() < maxEntries) {
throw new IllegalArgumentException("This entry list has not yet reached the maximum limit: " + node.getNumEntries() + "<=" + maxEntries);
}
assert !(node.getEntry(0) instanceof LeafEntry);
if (minFanout >= tree.getDirMinimum()) {
// minFanout not set for allowing underflowing nodes
return null;
}
IntIterator dimensionListing;
if (node.getEntry(0) instanceof XTreeDirectoryEntry) {
// filter common split dimensions
dimensionListing = getCommonSplitDimensions(node);
if (!dimensionListing.hasNext()) {
// no common dimensions
return null;
}
} else {
// test all dimensions
dimensionListing = new IntegerRangeIterator(0, node.getEntry(0).getDimensionality());
}
int formerSplitAxis = this.splitAxis;
// = maximum left-hand size
maxEntries = maxEntries + 1 - minFanout;
chooseSplitAxis(dimensionListing, minFanout, maxEntries);
// find the best split point
if (formerSplitAxis == this.splitAxis && tree.getDirMinimum() > minFanout) {
// remember: this follows an unsuccessful topological split
// avoid duplicate computations of {minEntries, ..., maxEntries}
double minOverlap = pastOverlap;
// test {minFanout, ..., minEntries - 1}
SplitSorting ret1 = chooseMinimumOverlapSplit(this.splitAxis, minFanout, tree.getDirMinimum() - 1, false);
if (ret1 != null && pastOverlap < minOverlap) {
// this is a valid choice
minOverlap = pastOverlap;
}
// test {maxEntries - minEntries + 2, ..., maxEntries - minFanout + 1}
SplitSorting ret2 = chooseMinimumOverlapSplit(this.splitAxis, minFanout, tree.getDirMinimum() - 1, true);
if (ret2 == null) {
// accept first range regardless of whether or not there is one
pastOverlap = minOverlap;
return ret1;
}
if (pastOverlap < minOverlap) {
// the second range is better
return ret2;
}
// the first range is better
pastOverlap = minOverlap;
return ret1;
} else {
return chooseMinimumOverlapSplit(this.splitAxis, minFanout, maxEntries, false);
}
}
use of de.lmu.ifi.dbs.elki.index.tree.LeafEntry in project elki by elki-project.
the class RdKNNTree method adjustKNNDistance.
/**
* Adjusts the knn distance in the subtree of the specified root entry.
*
* @param entry the root entry of the current subtree
* @param ids <em>Sorted</em> list of IDs
* @param knnLists a map of knn lists for each leaf entry
*/
private void adjustKNNDistance(RdKNNEntry entry, ArrayDBIDs ids, List<? extends KNNList> knnLists) {
RdKNNNode node = getNode(entry);
double knnDist_node = 0.;
if (node.isLeaf()) {
for (int i = 0; i < node.getNumEntries(); i++) {
RdKNNEntry leafEntry = node.getEntry(i);
DBID id = ((LeafEntry) leafEntry).getDBID();
int pos = ids.binarySearch(id);
if (pos >= 0) {
leafEntry.setKnnDistance(knnLists.get(pos).getKNNDistance());
}
knnDist_node = Math.max(knnDist_node, leafEntry.getKnnDistance());
}
} else {
for (int i = 0; i < node.getNumEntries(); i++) {
RdKNNEntry dirEntry = node.getEntry(i);
adjustKNNDistance(dirEntry, ids, knnLists);
knnDist_node = Math.max(knnDist_node, dirEntry.getKnnDistance());
}
}
entry.setKnnDistance(knnDist_node);
}
use of de.lmu.ifi.dbs.elki.index.tree.LeafEntry in project elki by elki-project.
the class RStarTreeKNNQuery method batchNN.
/**
* Performs a batch knn query.
*
* @param node the node for which the query should be performed
* @param knnLists a map containing the knn lists for each query objects
*/
protected void batchNN(AbstractRStarTreeNode<?, ?> node, Map<DBID, KNNHeap> knnLists) {
if (node.isLeaf()) {
for (int i = 0; i < node.getNumEntries(); i++) {
SpatialEntry p = node.getEntry(i);
for (Entry<DBID, KNNHeap> ent : knnLists.entrySet()) {
final DBID q = ent.getKey();
final KNNHeap knns_q = ent.getValue();
double knn_q_maxDist = knns_q.getKNNDistance();
DBID pid = ((LeafEntry) p).getDBID();
// FIXME: objects are NOT accessible by DBID in a plain R-tree
// context!
double dist_pq = distanceFunction.distance(relation.get(pid), relation.get(q));
tree.statistics.countDistanceCalculation();
if (dist_pq <= knn_q_maxDist) {
knns_q.insert(dist_pq, pid);
}
}
}
} else {
ModifiableDBIDs ids = DBIDUtil.newArray(knnLists.size());
for (DBID id : knnLists.keySet()) {
ids.add(id);
}
List<DoubleDistanceEntry> entries = getSortedEntries(node, ids);
for (DoubleDistanceEntry distEntry : entries) {
double minDist = distEntry.distance;
for (Entry<DBID, KNNHeap> ent : knnLists.entrySet()) {
final KNNHeap knns_q = ent.getValue();
double knn_q_maxDist = knns_q.getKNNDistance();
if (minDist <= knn_q_maxDist) {
SpatialEntry entry = distEntry.entry;
AbstractRStarTreeNode<?, ?> child = tree.getNode(((DirectoryEntry) entry).getPageID());
batchNN(child, knnLists);
break;
}
}
}
}
}
Aggregations