use of de.lmu.ifi.dbs.elki.index.tree.spatial.SpatialEntry in project elki by elki-project.
the class RStarTreeIndex method insertAll.
/**
* Inserts the specified objects into this index. If a bulk load mode is
* implemented, the objects are inserted in one bulk.
*
* @param ids the objects to be inserted
*/
@Override
public 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 iter = ids.iter(); iter.valid(); iter.advance()) {
leafs.add(createNewLeafEntry(iter));
}
bulkLoad(leafs);
} else {
for (DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) {
insert(DBIDUtil.deref(iter));
}
}
doExtraIntegrityChecks();
}
use of de.lmu.ifi.dbs.elki.index.tree.spatial.SpatialEntry in project elki by elki-project.
the class AbstractXTree method createNewRoot.
/**
* Creates a new root node that points to the two specified child nodes and
* return the path to the new root.
*
* @param oldRoot the old root of this RTree
* @param newNode the new split node
* @param splitAxis the split axis used for the split causing this new root
* @return the path to the new root node that points to the two specified
* child nodes
*/
protected IndexTreePath<SpatialEntry> createNewRoot(final N oldRoot, final N newNode, int splitAxis) {
N root = createNewDirectoryNode();
writeNode(root);
// get split history
SplitHistory sh = null;
// TODO: see whether root entry is ALWAYS a directory entry .. it SHOULD!
sh = ((XTreeDirectoryEntry) getRootEntry()).getSplitHistory();
if (sh == null) {
sh = new SplitHistory(getDimensionality());
}
sh.setDim(splitAxis);
// switch the ids
oldRoot.setPageID(root.getPageID());
if (!oldRoot.isLeaf()) {
// TODO: test whether this is neccessary
for (int i = 0; i < oldRoot.getNumEntries(); i++) {
N node = getNode(oldRoot.getEntry(i));
writeNode(node);
}
}
// adjust supernode id
if (oldRoot.isSuperNode()) {
supernodes.remove(new Long(getRootID()));
supernodes.put(new Long(oldRoot.getPageID()), oldRoot);
}
root.setPageID(getRootID());
SpatialEntry oldRootEntry = createNewDirectoryEntry(oldRoot);
SpatialEntry newNodeEntry = createNewDirectoryEntry(newNode);
((SplitHistorySpatialEntry) oldRootEntry).setSplitHistory(sh);
try {
((SplitHistorySpatialEntry) newNodeEntry).setSplitHistory((SplitHistory) sh.clone());
} catch (CloneNotSupportedException e) {
throw new RuntimeException("Clone of a split history should not throw an Exception", e);
}
root.addDirectoryEntry(oldRootEntry);
root.addDirectoryEntry(newNodeEntry);
writeNode(root);
writeNode(oldRoot);
writeNode(newNode);
if (getLogger().isDebugging()) {
getLogger().debugFine(//
new StringBuilder(1000).append("Create new Root: ID=").append(root.getPageID()).append("\nchild1 ").append(oldRoot).append(' ').append(//
new HyperBoundingBox(oldRootEntry)).append("\nchild2 ").append(newNode).append(' ').append(new HyperBoundingBox(newNodeEntry)));
}
// the root entry still needs to be set to the new root node's MBR
return new IndexTreePath<>(null, getRootEntry(), 0);
}
use of de.lmu.ifi.dbs.elki.index.tree.spatial.SpatialEntry in project elki by elki-project.
the class AbstractXTree method toString.
/**
* Returns a string representation of this XTree.
*
* @return a string representation of this XTree
*/
@Override
public String toString() {
long dirNodes = 0;
long superNodes = 0;
long leafNodes = 0;
long objects = 0;
long maxSuperCapacity = -1;
long minSuperCapacity = Long.MAX_VALUE;
BigInteger totalCapacity = BigInteger.ZERO;
int levels = 0;
N node = getRoot();
while (!node.isLeaf()) {
if (node.getNumEntries() > 0) {
SpatialEntry entry = node.getEntry(0);
node = getNode(entry);
levels++;
}
}
BreadthFirstEnumeration<N, SpatialEntry> enumeration = new BreadthFirstEnumeration<>(this, getRootPath());
while (enumeration.hasNext()) {
IndexTreePath<SpatialEntry> indexPath = enumeration.next();
SpatialEntry entry = indexPath.getEntry();
if (entry instanceof LeafEntry) {
objects++;
} else {
node = getNode(entry);
if (node.isLeaf()) {
leafNodes++;
} else {
if (node.isSuperNode()) {
superNodes++;
if (node.getCapacity() > maxSuperCapacity) {
maxSuperCapacity = node.getCapacity();
}
if (node.getCapacity() < minSuperCapacity) {
minSuperCapacity = node.getCapacity();
}
} else {
dirNodes++;
}
}
totalCapacity = totalCapacity.add(BigInteger.valueOf(node.getCapacity()));
}
}
assert objects == num_elements : "objects=" + objects + ", size=" + num_elements;
return //
new StringBuilder(10000).append(getClass().getName()).append(" has ").append((levels + 1)).append(" levels.\n").append(dirNodes).append(" Directory Nodes (max = ").append(dirCapacity - 1).append(", min = ").append(dirMinimum).append(//
")\n").append(superNodes).append(" Supernodes (max = ").append(maxSuperCapacity - 1).append(", min = ").append(minSuperCapacity - 1).append(//
")\n").append(leafNodes).append(" Data Nodes (max = ").append(leafCapacity - 1).append(", min = ").append(leafMinimum).append(//
")\n").append(objects).append(' ').append(dimensionality).append(//
"-dim. points in the tree \n").append("min_fanout = ").append(settings.min_fanout).append(", max_overlap = ").append(settings.max_overlap).append((settings.overlap_type == Overlap.DATA_OVERLAP ? " data overlap" : " volume overlap")).append(//
", \n").append("Storage Quota ").append(BigInteger.valueOf(objects + dirNodes + superNodes + leafNodes).multiply(BigInteger.valueOf(100)).divide(totalCapacity).toString()).append(//
"%\n").toString();
}
use of de.lmu.ifi.dbs.elki.index.tree.spatial.SpatialEntry in project elki by elki-project.
the class AbstractXTree method calculateOverlapIncrease.
/**
* Celebrated by the Profiler as a lot faster than the previous variant: that
* used to calculate all overlaps of the old MBR and the new MBR with all
* other MBRs. Now: The overlaps are only calculated if necessary:<br>
* <ul>
* <li>the new MBR does not have to be tested on overlaps if the current
* dimension has never changed</li>
* <li>the old MBR does not have to be tested if the new MBR shows no overlaps
* </li>
* </ul>
* Furthermore tries to avoid rounding errors arising from large value ranges
* and / or larger dimensions. <br>
* <br>
* However: hardly any difference in real runtime!
*
* @param node Node
* @param ei current entry
* @param testMBR extended MBR of <code>ei</code>
* @return
*/
private double calculateOverlapIncrease(N node, SpatialEntry ei, SpatialComparable testMBR) {
ModifiableHyperBoundingBox eiMBR = new ModifiableHyperBoundingBox(ei);
ModifiableHyperBoundingBox testMBRModifiable = new ModifiableHyperBoundingBox(testMBR);
double[] lb = eiMBR.getMinRef();
double[] ub = eiMBR.getMaxRef();
double[] lbT = testMBRModifiable.getMinRef();
double[] ubT = testMBRModifiable.getMaxRef();
// next tested lower bounds
double[] lbNext = null;
// and upper bounds
double[] ubNext = null;
boolean[] dimensionChanged = new boolean[lb.length];
for (int i = 0; i < dimensionChanged.length; i++) {
if (lb[i] > lbT[i] || ub[i] < ubT[i]) {
dimensionChanged[i] = true;
}
}
double multiOverlapInc = 0, multiOverlapMult = 1, mOOld = 1, mONew = 1;
// dimensional overlap
double ol, olT;
for (int j = 0; j < node.getNumEntries(); j++) {
SpatialEntry ej = node.getEntry(j);
if (getPageID(ej) != getPageID(ei)) {
// is constant for a unchanged dimension
multiOverlapMult = 1;
// overlap for old MBR on changed dimensions
mOOld = 1;
// overlap on new MBR on changed dimension
mONew = 1;
ModifiableHyperBoundingBox ejMBR = new ModifiableHyperBoundingBox(ej);
lbNext = ejMBR.getMinRef();
ubNext = ejMBR.getMaxRef();
for (int i = 0; i < dimensionChanged.length; i++) {
if (dimensionChanged[i]) {
if (lbT[i] > ubNext[i] || ubT[i] < lbNext[i]) {
multiOverlapMult = 0;
// old MBR has no overlap either
break;
}
olT = (ubT[i] > ubNext[i] ? ubNext[i] : ubT[i]) - (lbT[i] < lbNext[i] ? lbNext[i] : lbT[i]);
mONew *= olT;
if (mOOld != 0) {
// else: no use in calculating overlap
ol = (ub[i] > ubNext[i] ? ubNext[i] : ub[i]) - (lb[i] < lbNext[i] ? lbNext[i] : lb[i]);
if (ol < 0) {
ol = 0;
}
mOOld *= ol;
}
} else {
if (lb[i] > ubNext[i] || ub[i] < lbNext[i]) {
multiOverlapMult = 0;
break;
}
ol = (ub[i] > ubNext[i] ? ubNext[i] : ub[i]) - (lb[i] < lbNext[i] ? lbNext[i] : lb[i]);
multiOverlapMult *= ol;
}
}
if (multiOverlapMult != 0) {
multiOverlapInc += multiOverlapMult * (mONew - mOOld);
}
}
}
return multiOverlapInc;
}
use of de.lmu.ifi.dbs.elki.index.tree.spatial.SpatialEntry in project elki by elki-project.
the class AbstractXTreeNode method readExternal.
/**
* Reads the id of this node, the numEntries and the entries array from the
* specified stream. If the {@link #supernode} field is set, <code>this</code>
* cannot be contained in <code>in</code>. Such a node has to be manually
* filled using {@link #readSuperNode(ObjectInput, AbstractXTree)}.
*
* @param in the stream to read data from in order to restore the object
* @throws java.io.IOException if I/O errors occur
* @throws ClassNotFoundException If the class for an object being restored
* cannot be found.
*/
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
setPageID(in.readInt());
isLeaf = in.readBoolean();
supernode = in.readBoolean();
numEntries = in.readInt();
final int capacity = in.readInt();
if (supernode) {
// this node is a supernode and is yet to be filled
capacity_to_be_filled = capacity;
return;
}
// entries = (E[]) java.lang.reflect.Array.newInstance(eclass, capacity);
if (isLeaf()) {
entries = (Entry[]) new SpatialPointLeafEntry[capacity];
} else {
entries = (Entry[]) new XTreeDirectoryEntry[capacity];
}
for (int i = 0; i < numEntries; i++) {
SpatialEntry s = isLeaf() ? new SpatialPointLeafEntry() : new XTreeDirectoryEntry();
s.readExternal(in);
entries[i] = s;
}
}
Aggregations