Search in sources :

Example 1 with ModifiableHyperBoundingBox

use of de.lmu.ifi.dbs.elki.data.ModifiableHyperBoundingBox in project elki by elki-project.

the class SpatialDirectoryEntry method readExternal.

/**
 * Calls the super method and reads the MBR object of this entry from the
 * specified input stream.
 *
 * @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 {
    this.id = in.readInt();
    this.mbr = new ModifiableHyperBoundingBox();
    this.mbr.readExternal(in);
}
Also used : ModifiableHyperBoundingBox(de.lmu.ifi.dbs.elki.data.ModifiableHyperBoundingBox)

Example 2 with ModifiableHyperBoundingBox

use of de.lmu.ifi.dbs.elki.data.ModifiableHyperBoundingBox in project elki by elki-project.

the class RTreeLinearSplit method split.

@Override
public <E extends SpatialComparable, A> long[] split(A entries, ArrayAdapter<E, A> getter, int minEntries) {
    final int num = getter.size(entries);
    // Object assignment, and processed objects
    long[] assignment = BitsUtil.zero(num);
    long[] assigned = BitsUtil.zero(num);
    // MBRs and Areas of current assignments
    ModifiableHyperBoundingBox mbr1, mbr2;
    double area1 = 0, area2 = 0;
    // LinearPickSeeds - find worst pair
    {
        final int dim = getter.get(entries, 0).getDimensionality();
        // Best candidates
        double bestsep = Double.NEGATIVE_INFINITY;
        int w1 = -1, w2 = -1;
        // LPS1: find extreme rectangles
        for (int d = 0; d < dim; d++) {
            // We need to find two candidates each, in case of el==eh!
            double minlow = Double.POSITIVE_INFINITY;
            double maxlow = Double.NEGATIVE_INFINITY, maxlow2 = Double.NEGATIVE_INFINITY;
            double minhig = Double.POSITIVE_INFINITY, minhig2 = Double.POSITIVE_INFINITY;
            double maxhig = Double.NEGATIVE_INFINITY;
            int el = -1, el2 = -1;
            int eh = -1, eh2 = -1;
            for (int i = 0; i < num; i++) {
                E ei = getter.get(entries, i);
                final double low = ei.getMin(d);
                final double hig = ei.getMax(d);
                minlow = Math.min(minlow, low);
                maxhig = Math.max(maxhig, hig);
                if (low >= maxlow) {
                    maxlow2 = maxlow;
                    maxlow = low;
                    el2 = el;
                    el = i;
                } else if (low > maxlow2) {
                    maxlow2 = low;
                    el2 = i;
                }
                if (hig <= minhig) {
                    minhig2 = minhig;
                    minhig = hig;
                    eh2 = eh;
                    eh = i;
                } else if (hig < minhig2) {
                    minhig2 = hig;
                    eh2 = i;
                }
            }
            // Compute normalized separation
            final double normsep;
            if (el != eh) {
                normsep = minhig - maxlow / (maxhig - minlow);
            } else {
                // Resolve tie.
                double normsep1 = minhig - maxlow2 / (maxhig - minlow);
                double normsep2 = minhig2 - maxlow / (maxhig - minlow);
                if (normsep1 > normsep2) {
                    el = el2;
                    normsep = normsep1;
                } else {
                    eh = eh2;
                    normsep = normsep2;
                }
            }
            assert (eh != -1 && el != -1 && (eh != el));
            if (normsep > bestsep) {
                bestsep = normsep;
                w1 = el;
                w2 = eh;
            }
        }
        // Data to keep
        // Mark both as used
        BitsUtil.setI(assigned, w1);
        BitsUtil.setI(assigned, w2);
        // Assign second to second set
        BitsUtil.setI(assignment, w2);
        // Initial mbrs and areas
        final E w1i = getter.get(entries, w1);
        final E w2i = getter.get(entries, w2);
        area1 = SpatialUtil.volume(w1i);
        area2 = SpatialUtil.volume(w2i);
        mbr1 = new ModifiableHyperBoundingBox(w1i);
        mbr2 = new ModifiableHyperBoundingBox(w2i);
    }
    // Second phase, QS2+QS3
    {
        int in1 = 1, in2 = 1;
        int remaining = num - 2;
        // Choose any element, for example the next.
        for (int next = BitsUtil.nextClearBit(assigned, 0); remaining > 0 && next < num; next = BitsUtil.nextClearBit(assigned, next + 1)) {
            // Shortcut when minEntries must be fulfilled
            if (in1 + remaining <= minEntries) {
                // No need to updated assigned, no changes to assignment.
                break;
            }
            if (in2 + remaining <= minEntries) {
                // Don't bother to update assigned, though
                for (; next < num; next = BitsUtil.nextClearBit(assigned, next + 1)) {
                    BitsUtil.setI(assignment, next);
                }
                break;
            }
            // PickNext
            boolean preferSecond = false;
            // Cost of putting object into both mbrs
            final E next_i = getter.get(entries, next);
            final double d1 = SpatialUtil.volumeUnion(mbr1, next_i) - area1;
            final double d2 = SpatialUtil.volumeUnion(mbr2, next_i) - area2;
            // Prefer smaller increase
            preferSecond = (d2 < d1);
            // QS3: tie handling
            if (d1 == d2) {
                // Prefer smaller area
                if (area1 != area2) {
                    preferSecond = (area2 < area1);
                } else {
                    // Prefer smaller group size
                    preferSecond = (in2 < in1);
                }
            }
            // Mark as used.
            BitsUtil.setI(assigned, next);
            remaining--;
            // Assign
            if (!preferSecond) {
                in1++;
                mbr1.extend(next_i);
                area1 = SpatialUtil.volume(mbr1);
            } else {
                in2++;
                BitsUtil.setI(assignment, next);
                mbr2.extend(next_i);
                area2 = SpatialUtil.volume(mbr2);
            }
        // Loop from QS2
        }
    // Note: "assigned" and "remaining" likely not updated!
    }
    return assignment;
}
Also used : ModifiableHyperBoundingBox(de.lmu.ifi.dbs.elki.data.ModifiableHyperBoundingBox)

Example 3 with ModifiableHyperBoundingBox

use of de.lmu.ifi.dbs.elki.data.ModifiableHyperBoundingBox in project elki by elki-project.

the class AbstractRStarTreeNode method computeMBR.

/**
 * Recomputing the MBR is rather expensive.
 *
 * @return MBR
 */
public ModifiableHyperBoundingBox computeMBR() {
    E firstEntry = getEntry(0);
    if (firstEntry == null) {
        return null;
    }
    // Note: we deliberately get a cloned copy here, since we will modify it.
    ModifiableHyperBoundingBox mbr = new ModifiableHyperBoundingBox(firstEntry);
    for (int i = 1; i < numEntries; i++) {
        mbr.extend(getEntry(i));
    }
    return mbr;
}
Also used : ModifiableHyperBoundingBox(de.lmu.ifi.dbs.elki.data.ModifiableHyperBoundingBox)

Example 4 with ModifiableHyperBoundingBox

use of de.lmu.ifi.dbs.elki.data.ModifiableHyperBoundingBox in project elki by elki-project.

the class AbstractXTree method initializeCapacities.

@Override
protected void initializeCapacities(SpatialEntry exampleLeaf) {
    /* Simulate the creation of a leaf page to get the page capacity */
    try {
        int cap = 0;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        SpatialPointLeafEntry sl = new SpatialPointLeafEntry(DBIDUtil.importInteger(0), new double[exampleLeaf.getDimensionality()]);
        while (baos.size() <= getPageSize()) {
            sl.writeExternal(oos);
            oos.flush();
            cap++;
        }
        // the last one caused the page to overflow.
        leafCapacity = cap - 1;
    } catch (IOException e) {
        throw new AbortException("Error determining page sizes.", e);
    }
    /* Simulate the creation of a directory page to get the capacity */
    try {
        int cap = 0;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        ModifiableHyperBoundingBox hb = new ModifiableHyperBoundingBox(new double[exampleLeaf.getDimensionality()], new double[exampleLeaf.getDimensionality()]);
        XTreeDirectoryEntry xl = new XTreeDirectoryEntry(0, hb);
        while (baos.size() <= getPageSize()) {
            xl.writeExternal(oos);
            oos.flush();
            cap++;
        }
        dirCapacity = cap - 1;
    } catch (IOException e) {
        throw new AbortException("Error determining page sizes.", e);
    }
    if (dirCapacity <= 1) {
        throw new IllegalArgumentException("Node size of " + getPageSize() + " Bytes is chosen too small!");
    }
    if (dirCapacity < 10) {
        getLogger().warning("Page size is choosen very small! Maximum number of entries " + "in a directory node = " + (dirCapacity - 1));
    }
    // minimum entries per directory node
    dirMinimum = (int) Math.round((dirCapacity - 1) * settings.relativeMinEntries);
    if (dirMinimum < 2) {
        dirMinimum = 2;
    }
    // minimum entries per directory node
    settings.min_fanout = (int) Math.round((dirCapacity - 1) * settings.relativeMinFanout);
    if (settings.min_fanout < 2) {
        settings.min_fanout = 2;
    }
    if (leafCapacity <= 1) {
        throw new IllegalArgumentException("Node size of " + getPageSize() + " Bytes is chosen too small!");
    }
    if (leafCapacity < 10) {
        getLogger().warning("Page size is choosen very small! Maximum number of entries " + "in a leaf node = " + (leafCapacity - 1));
    }
    // minimum entries per leaf node
    leafMinimum = (int) Math.round((leafCapacity - 1) * settings.relativeMinEntries);
    if (leafMinimum < 2) {
        leafMinimum = 2;
    }
    dimensionality = exampleLeaf.getDimensionality();
    if (getLogger().isVerbose()) {
        getLogger().verbose("Directory Capacity:  " + (dirCapacity - 1) + "\nDirectory minimum: " + dirMinimum + "\nLeaf Capacity:     " + (leafCapacity - 1) + "\nLeaf Minimum:      " + leafMinimum + "\nminimum fanout: " + settings.min_fanout);
    }
}
Also used : SpatialPointLeafEntry(de.lmu.ifi.dbs.elki.index.tree.spatial.SpatialPointLeafEntry) ModifiableHyperBoundingBox(de.lmu.ifi.dbs.elki.data.ModifiableHyperBoundingBox) AbortException(de.lmu.ifi.dbs.elki.utilities.exceptions.AbortException)

Example 5 with ModifiableHyperBoundingBox

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

Aggregations

ModifiableHyperBoundingBox (de.lmu.ifi.dbs.elki.data.ModifiableHyperBoundingBox)17 DoubleVector (de.lmu.ifi.dbs.elki.data.DoubleVector)3 SpatialDirectoryEntry (de.lmu.ifi.dbs.elki.index.tree.spatial.SpatialDirectoryEntry)3 ArrayList (java.util.ArrayList)3 Random (java.util.Random)3 NumberVector (de.lmu.ifi.dbs.elki.data.NumberVector)2 LPNormDistanceFunction (de.lmu.ifi.dbs.elki.distance.distancefunction.minkowski.LPNormDistanceFunction)2 SpatialEntry (de.lmu.ifi.dbs.elki.index.tree.spatial.SpatialEntry)2 SpatialPointLeafEntry (de.lmu.ifi.dbs.elki.index.tree.spatial.SpatialPointLeafEntry)2 AbortException (de.lmu.ifi.dbs.elki.utilities.exceptions.AbortException)2 DoubleIntPair (de.lmu.ifi.dbs.elki.utilities.pairs.DoubleIntPair)2 IOException (java.io.IOException)2 Test (org.junit.Test)2 HyperBoundingBox (de.lmu.ifi.dbs.elki.data.HyperBoundingBox)1 Logging (de.lmu.ifi.dbs.elki.logging.Logging)1 FiniteProgress (de.lmu.ifi.dbs.elki.logging.progress.FiniteProgress)1 Heap (de.lmu.ifi.dbs.elki.utilities.datastructures.heap.Heap)1 TopBoundedHeap (de.lmu.ifi.dbs.elki.utilities.datastructures.heap.TopBoundedHeap)1 BufferedImage (java.awt.image.BufferedImage)1 ByteArrayOutputStream (java.io.ByteArrayOutputStream)1