use of de.lmu.ifi.dbs.elki.index.tree.spatial.SpatialEntry in project elki by elki-project.
the class XTreeIndex method insertAll.
/**
* Inserts the specified objects into this index. If a bulk load mode is
* implemented, the objects are inserted in one bulk.
*
* @param objects the objects to be inserted
*/
@Override
public final void insertAll(DBIDs ids) {
if (ids.isEmpty() || (ids.size() == 1)) {
return;
}
// Make an example leaf
if (canBulkLoad()) {
List<SpatialEntry> leafs = new ArrayList<>(ids.size());
for (DBIDIter id = ids.iter(); id.valid(); id.advance()) {
leafs.add(createNewLeafEntry(id));
}
bulkLoad(leafs);
} else {
for (DBIDIter id = ids.iter(); id.valid(); id.advance()) {
insert(id);
}
}
doExtraIntegrityChecks();
}
use of de.lmu.ifi.dbs.elki.index.tree.spatial.SpatialEntry in project elki by elki-project.
the class XSplitter method countXingDataEntries.
/**
* Count all data objects under entries and whether they intersect the given
* MBR <code>mbr</code> into <code>numOf</code>.
*
* @param entries
* @param mbr
* @param numOf array of two integers, the first one is to be filled with the
* total number of data objects, the second one with the number of data
* objects intersecting <code>mbr</code>
* @return == the (probably modified) integer array <code>numOf</code>: the
* first field is the total number of data objects, the second the
* number of data objects intersecting <code>mbr</code>
*/
private int[] countXingDataEntries(final Collection<SpatialEntry> entries, final HyperBoundingBox mbr, int[] numOf) {
for (SpatialEntry entry : entries) {
if (entry instanceof LeafEntry) {
numOf[0]++;
if (SpatialUtil.intersects(mbr, entry)) {
numOf[1]++;
}
} else {
N node = tree.getNode(((DirectoryEntry) entry).getPageID());
countXingDataEntries(node.getEntries(), mbr, numOf);
}
}
return numOf;
}
use of de.lmu.ifi.dbs.elki.index.tree.spatial.SpatialEntry in project elki by elki-project.
the class XSplitter method mbr.
/**
* Computes and returns the mbr of the specified nodes, only the nodes between
* from and to index are considered.
*
* @param entries the array of node indices in {@link #entries}
* @param from the start index
* @param to the end index
* @return the mbr of the specified nodes
*/
private HyperBoundingBox mbr(final int[] entries, final int from, final int to) {
SpatialEntry first = this.node.getEntry(entries[from]);
ModifiableHyperBoundingBox mbr = new ModifiableHyperBoundingBox(first);
for (int i = from + 1; i < to; i++) {
mbr.extend(this.node.getEntry(entries[i]));
}
return mbr;
}
use of de.lmu.ifi.dbs.elki.index.tree.spatial.SpatialEntry in project elki by elki-project.
the class AbstractXTree method choosePath.
/**
* Chooses the best path of the specified subtree for insertion of the given
* MBR at the specified level. The selection uses the following criteria:
* <ol>
* <li>Test on containment (<code>mbr</code> <em>is</em> within one of the
* children)</li>
* <li>If there are multiple containing children, the child with the minimum
* volume is chosen.</li>
* <li>Else, if the children point to leaf nodes, chooses the child with the
* minimum multi-overlap increase.</li>
* <li>Else, or the multi-overlap increase leads to ties, the child with the
* minimum volume increase is selected.</li>
* <li>If there are still ties, the child with the minimum volume is
* chosen.</li>
* </ol>
*
* @param subtree the subtree to be tested for insertion
* @param mbr the MBR to be inserted
* @param level the level at which the MBR should be inserted (level 1
* indicates leaf-level)
* @return the path of the appropriate subtree to insert the given
* <code>mbr</code>
*/
@Override
protected IndexTreePath<SpatialEntry> choosePath(IndexTreePath<SpatialEntry> subtree, SpatialComparable mbr, int level, int cur) {
if (getLogger().isDebuggingFiner()) {
getLogger().debugFiner("node " + subtree + ", level " + level);
}
N node = getNode(subtree.getEntry());
if (node == null) {
throw new RuntimeException("Page file did not return node for node id: " + getPageID(subtree.getEntry()));
}
if (node.isLeaf()) {
return subtree;
}
// first test on containment
IndexTreePath<SpatialEntry> newSubtree = containedTest(subtree, node, mbr);
if (newSubtree != null) {
if (height - subtree.getPathCount() == level) {
return newSubtree;
} else {
return choosePath(newSubtree, mbr, level, ++cur);
}
}
int optEntry = -1;
HyperBoundingBox optTestMBR = null;
double optOverlapInc = 0;
// test overlap increase?
boolean isLeafContainer = false;
if ((// also test supernodes
!OMIT_OVERLAP_INCREASE_4_SUPERNODES || // don't
(OMIT_OVERLAP_INCREASE_4_SUPERNODES && !node.isSuperNode())) && getNode(node.getEntry(0)).isLeaf()) {
// children are leafs
// overlap increase is to be tested
optOverlapInc = Double.POSITIVE_INFINITY;
isLeafContainer = true;
}
double optVolume = Double.POSITIVE_INFINITY;
double optVolumeInc = Double.POSITIVE_INFINITY;
double tempVolume, volume;
for (int index = 0; index < node.getNumEntries(); index++) {
SpatialEntry child = node.getEntry(index);
SpatialComparable childMBR = child;
HyperBoundingBox testMBR = SpatialUtil.union(childMBR, mbr);
double pairwiseOverlapInc;
if (isLeafContainer) {
pairwiseOverlapInc = calculateOverlapIncrease(node, child, testMBR);
if (Double.isInfinite(pairwiseOverlapInc) || Double.isNaN(pairwiseOverlapInc)) {
throw new IllegalStateException("an entry's MBR is too large to calculate its overlap increase: " + pairwiseOverlapInc + "; \nplease re-scale your data s.t. it can be dealt with");
}
} else {
// no need to examine overlap increase?
pairwiseOverlapInc = 0;
}
if (pairwiseOverlapInc <= optOverlapInc) {
if (pairwiseOverlapInc == optOverlapInc) {
// If there are multiple entries with the same overlap increase,
// choose the one with the minimum volume increase.
// If there are also multiple entries with the same volume increase
// choose the one with the minimum volume.
volume = SpatialUtil.volume(childMBR);
if (Double.isInfinite(volume) || Double.isNaN(volume)) {
throw new IllegalStateException("an entry's MBR is too large to calculate its volume: " + volume + "; \nplease re-scale your data s.t. it can be dealt with");
}
tempVolume = SpatialUtil.volume(testMBR);
if (Double.isInfinite(tempVolume) || Double.isNaN(tempVolume)) {
throw new IllegalStateException("an entry's MBR is too large to calculate its volume: " + tempVolume + "; \nplease re-scale your data s.t. it can be dealt with");
}
double volumeInc = tempVolume - volume;
if (Double.isNaN(optVolumeInc)) {
// has not yet been calculated
optVolume = SpatialUtil.volume(node.getEntry(optEntry));
optVolumeInc = SpatialUtil.volume(optTestMBR) - optVolume;
}
if (volumeInc < optVolumeInc) {
optVolumeInc = volumeInc;
optVolume = volume;
optEntry = index;
} else if (volumeInc == optVolumeInc && volume < optVolume) {
// TODO: decide whether to remove this option
System.out.println("####\nEQUAL VOLUME INCREASE: HAPPENS!\n####");
optVolumeInc = volumeInc;
optVolume = volume;
optEntry = index;
}
} else {
// already better
optOverlapInc = pairwiseOverlapInc;
optVolume = Double.NaN;
optVolumeInc = Double.NaN;
// for later calculations
optTestMBR = testMBR;
optEntry = index;
}
}
}
assert optEntry >= 0;
newSubtree = new IndexTreePath<>(subtree, node.getEntry(optEntry), optEntry);
if (height - subtree.getPathCount() == level) {
return newSubtree;
} else {
return choosePath(newSubtree, mbr, level, ++cur);
}
}
use of de.lmu.ifi.dbs.elki.index.tree.spatial.SpatialEntry in project elki by elki-project.
the class AbstractXTree method adjustTree.
/**
* Adjusts the tree after insertion of some nodes.
*
* @param subtree the subtree to be adjusted
*/
@Override
protected void adjustTree(IndexTreePath<SpatialEntry> subtree) {
if (getLogger().isDebugging()) {
getLogger().debugFine("Adjust tree " + subtree);
}
// get the root of the subtree
N node = getNode(subtree.getEntry());
// overflow in node
if (hasOverflow(node)) {
if (node.isSuperNode()) {
int new_capacity = node.growSuperNode();
getLogger().finest("Extending supernode to new capacity " + new_capacity);
if (isRoot(node)) {
// is root
node.adjustEntry(getRootEntry());
} else {
N parent = getNode(subtree.getParentPath().getEntry());
SpatialEntry e = parent.getEntry(subtree.getIndex());
HyperBoundingBox mbr = new HyperBoundingBox(e);
node.adjustEntry(e);
if (!SpatialUtil.equals(mbr, e)) {
// MBR has changed
// write changes in parent to file
writeNode(parent);
adjustTree(subtree.getParentPath());
}
}
} else {
int[] splitAxis = { -1 };
// treatment of overflow: reinsertion or split
N split = overflowTreatment(node, subtree, splitAxis);
// node was split
if (split != null) {
// split nodes
if (isRoot(node)) {
IndexTreePath<SpatialEntry> newRootPath = createNewRoot(node, split, splitAxis[0]);
height++;
adjustTree(newRootPath);
} else // node is not root
{
// get the parent and add the new split node
N parent = getNode(subtree.getParentPath().getEntry());
if (getLogger().isDebugging()) {
getLogger().debugFine("parent " + parent);
}
SpatialEntry newEntry = createNewDirectoryEntry(split);
parent.addDirectoryEntry(newEntry);
// The below variant does not work in the persistent version
// E oldEntry = subtree.getEntry();
// [reason: if oldEntry is modified, this must be permanent]
SpatialEntry oldEntry = parent.getEntry(subtree.getIndex());
// adjust split history
SplitHistory sh = ((SplitHistorySpatialEntry) oldEntry).getSplitHistory();
if (sh == null) {
// not yet initialized (dimension not known of this tree)
sh = new SplitHistory(oldEntry.getDimensionality());
sh.setDim(splitAxis[0]);
((SplitHistorySpatialEntry) oldEntry).setSplitHistory(sh);
} else {
((SplitHistorySpatialEntry) oldEntry).addSplitDimension(splitAxis[0]);
}
try {
((SplitHistorySpatialEntry) newEntry).setSplitHistory((SplitHistory) sh.clone());
} catch (CloneNotSupportedException e) {
throw new RuntimeException("Clone of a split history should not throw an Exception", e);
}
// adjust the entry representing the (old) node, that has
// been split
node.adjustEntry(oldEntry);
// write changes in parent to file
writeNode(parent);
adjustTree(subtree.getParentPath());
}
}
}
} else // no overflow, only adjust parameters of the entry representing the
// node
{
if (!isRoot(node)) {
N parent = getNode(subtree.getParentPath().getEntry());
SpatialEntry e = parent.getEntry(subtree.getIndex());
HyperBoundingBox mbr = new HyperBoundingBox(e);
node.adjustEntry(e);
if (// we already know that mbr is extended
node.isLeaf() || !SpatialUtil.equals(mbr, e)) {
// MBR has changed
// write changes in parent to file
writeNode(parent);
adjustTree(subtree.getParentPath());
}
} else // root level is reached
{
node.adjustEntry(getRootEntry());
}
}
}
Aggregations