Search in sources :

Example 11 with SpatialEntry

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();
}
Also used : ArrayList(java.util.ArrayList) SpatialEntry(de.lmu.ifi.dbs.elki.index.tree.spatial.SpatialEntry) DBIDIter(de.lmu.ifi.dbs.elki.database.ids.DBIDIter)

Example 12 with SpatialEntry

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;
}
Also used : LeafEntry(de.lmu.ifi.dbs.elki.index.tree.LeafEntry) SpatialEntry(de.lmu.ifi.dbs.elki.index.tree.spatial.SpatialEntry)

Example 13 with SpatialEntry

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;
}
Also used : ModifiableHyperBoundingBox(de.lmu.ifi.dbs.elki.data.ModifiableHyperBoundingBox) SpatialEntry(de.lmu.ifi.dbs.elki.index.tree.spatial.SpatialEntry)

Example 14 with SpatialEntry

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);
    }
}
Also used : SpatialComparable(de.lmu.ifi.dbs.elki.data.spatial.SpatialComparable) ModifiableHyperBoundingBox(de.lmu.ifi.dbs.elki.data.ModifiableHyperBoundingBox) HyperBoundingBox(de.lmu.ifi.dbs.elki.data.HyperBoundingBox) SpatialEntry(de.lmu.ifi.dbs.elki.index.tree.spatial.SpatialEntry)

Example 15 with SpatialEntry

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());
        }
    }
}
Also used : ModifiableHyperBoundingBox(de.lmu.ifi.dbs.elki.data.ModifiableHyperBoundingBox) HyperBoundingBox(de.lmu.ifi.dbs.elki.data.HyperBoundingBox) SpatialEntry(de.lmu.ifi.dbs.elki.index.tree.spatial.SpatialEntry) SplitHistory(de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.xtree.util.SplitHistory)

Aggregations

SpatialEntry (de.lmu.ifi.dbs.elki.index.tree.spatial.SpatialEntry)21 ModifiableHyperBoundingBox (de.lmu.ifi.dbs.elki.data.ModifiableHyperBoundingBox)5 ArrayList (java.util.ArrayList)5 HyperBoundingBox (de.lmu.ifi.dbs.elki.data.HyperBoundingBox)4 DBIDIter (de.lmu.ifi.dbs.elki.database.ids.DBIDIter)4 LeafEntry (de.lmu.ifi.dbs.elki.index.tree.LeafEntry)4 SpatialPointLeafEntry (de.lmu.ifi.dbs.elki.index.tree.spatial.SpatialPointLeafEntry)4 SpatialDirectoryEntry (de.lmu.ifi.dbs.elki.index.tree.spatial.SpatialDirectoryEntry)3 Database (de.lmu.ifi.dbs.elki.database.Database)2 SplitHistory (de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.xtree.util.SplitHistory)2 MeanVariance (de.lmu.ifi.dbs.elki.math.MeanVariance)2 DoubleVector (de.lmu.ifi.dbs.elki.data.DoubleVector)1 NumberVector (de.lmu.ifi.dbs.elki.data.NumberVector)1 SpatialComparable (de.lmu.ifi.dbs.elki.data.spatial.SpatialComparable)1 StaticArrayDatabase (de.lmu.ifi.dbs.elki.database.StaticArrayDatabase)1 DBID (de.lmu.ifi.dbs.elki.database.ids.DBID)1 Relation (de.lmu.ifi.dbs.elki.database.relation.Relation)1 BreadthFirstEnumeration (de.lmu.ifi.dbs.elki.index.tree.BreadthFirstEnumeration)1 Entry (de.lmu.ifi.dbs.elki.index.tree.Entry)1 IndexTreePath (de.lmu.ifi.dbs.elki.index.tree.IndexTreePath)1