Search in sources :

Example 6 with SpatialComparable

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

the class XSplitter method add2MBR.

/**
 * Adds the minimum and maximum bounds of the MBR of entry
 * <code>entrySorting[index]</code> in {@link #entries} to the dimension-wise
 * upper and lower bounds, <code>ub</code> and <code>lb</code>. Note that if
 * this method is called for <code>ub</code> and <code>lb</code> which are
 * already owned by an MBR, this update operation also updates the MBR defined
 * by those bounds.
 *
 * @param entrySorting a sorting providing the mapping of <code>index</code>
 *        to the entry in {@link #entries} to be added
 * @param ub the upper bound of the MBR to be extended
 * @param lb the lower bound of the MBR to be extended
 * @param index the index in the sorting referencing the entry to be added
 */
private void add2MBR(int[] entrySorting, double[] ub, double[] lb, int index) {
    SpatialComparable currMBR = node.getEntry(entrySorting[index]);
    for (int d = 0; d < currMBR.getDimensionality(); d++) {
        double max = currMBR.getMax(d);
        if (max > ub[d]) {
            ub[d] = max;
        }
        double min = currMBR.getMin(d);
        if (min < lb[d]) {
            lb[d] = min;
        }
    }
}
Also used : SpatialComparable(de.lmu.ifi.dbs.elki.data.spatial.SpatialComparable)

Example 7 with SpatialComparable

use of de.lmu.ifi.dbs.elki.data.spatial.SpatialComparable 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 8 with SpatialComparable

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

the class EvaluateDBCV method evaluateClustering.

/**
 * Evaluate a single clustering.
 *
 * @param db Database
 * @param rel Data relation
 * @param cl Clustering
 *
 * @return dbcv DBCV-index
 */
public double evaluateClustering(Database db, Relation<O> rel, Clustering<?> cl) {
    final DistanceQuery<O> dq = rel.getDistanceQuery(distanceFunction);
    List<? extends Cluster<?>> clusters = cl.getAllClusters();
    final int numc = clusters.size();
    // DBCV needs a "dimensionality".
    @SuppressWarnings("unchecked") final Relation<? extends SpatialComparable> vrel = (Relation<? extends SpatialComparable>) rel;
    final int dim = RelationUtil.dimensionality(vrel);
    // precompute all core distances
    ArrayDBIDs[] cids = new ArrayDBIDs[numc];
    double[][] coreDists = new double[numc][];
    for (int c = 0; c < numc; c++) {
        Cluster<?> cluster = clusters.get(c);
        // Singletons are considered as Noise, because they have no sparseness
        if (cluster.isNoise() || cluster.size() < 2) {
            coreDists[c] = null;
            continue;
        }
        // Store for use below:
        ArrayDBIDs ids = cids[c] = DBIDUtil.ensureArray(cluster.getIDs());
        double[] clusterCoreDists = coreDists[c] = new double[ids.size()];
        for (DBIDArrayIter it = ids.iter(), it2 = ids.iter(); it.valid(); it.advance()) {
            double currentCoreDist = 0;
            int neighbors = 0;
            for (it2.seek(0); it2.valid(); it2.advance()) {
                if (DBIDUtil.equal(it, it2)) {
                    continue;
                }
                double dist = dq.distance(it, it2);
                // We ignore such objects.
                if (dist > 0) {
                    currentCoreDist += MathUtil.powi(1. / dist, dim);
                    ++neighbors;
                }
            }
            // Average, and undo power.
            clusterCoreDists[it.getOffset()] = FastMath.pow(currentCoreDist / neighbors, -1. / dim);
        }
    }
    // compute density sparseness of all clusters
    int[][] clusterDegrees = new int[numc][];
    double[] clusterDscMax = new double[numc];
    // describes if a cluster contains any internal edges
    boolean[] internalEdges = new boolean[numc];
    for (int c = 0; c < numc; c++) {
        Cluster<?> cluster = clusters.get(c);
        if (cluster.isNoise() || cluster.size() < 2) {
            clusterDegrees[c] = null;
            clusterDscMax[c] = Double.NaN;
            continue;
        }
        double[] clusterCoreDists = coreDists[c];
        ArrayDBIDs ids = cids[c];
        // Density Sparseness of the Cluster
        double dscMax = 0;
        double[][] distances = new double[cluster.size()][cluster.size()];
        // create mutability distance matrix for Minimum Spanning Tree
        for (DBIDArrayIter it = ids.iter(), it2 = ids.iter(); it.valid(); it.advance()) {
            double currentCoreDist = clusterCoreDists[it.getOffset()];
            for (it2.seek(it.getOffset() + 1); it2.valid(); it2.advance()) {
                double mutualReachDist = MathUtil.max(currentCoreDist, clusterCoreDists[it2.getOffset()], dq.distance(it, it2));
                distances[it.getOffset()][it2.getOffset()] = mutualReachDist;
                distances[it2.getOffset()][it.getOffset()] = mutualReachDist;
            }
        }
        // generate Minimum Spanning Tree
        int[] nodes = PrimsMinimumSpanningTree.processDense(distances);
        // get degree of all nodes in the spanning tree
        int[] degree = new int[cluster.size()];
        for (int i = 0; i < nodes.length; i++) {
            degree[nodes[i]]++;
        }
        // check if cluster contains any internal edges
        for (int i = 0; i < nodes.length; i += 2) {
            if (degree[nodes[i]] > 1 && degree[nodes[i + 1]] > 1) {
                internalEdges[c] = true;
            }
        }
        clusterDegrees[c] = degree;
        // find maximum sparseness in the Minimum Spanning Tree
        for (int i = 0; i < nodes.length; i = i + 2) {
            final int n1 = nodes[i], n2 = nodes[i + 1];
            // If a cluster has no internal nodes we consider all edges.
            if (distances[n1][n2] > dscMax && (!internalEdges[c] || (degree[n1] > 1 && degree[n2] > 1))) {
                dscMax = distances[n1][n2];
            }
        }
        clusterDscMax[c] = dscMax;
    }
    // compute density separation of all clusters
    double dbcv = 0;
    for (int c = 0; c < numc; c++) {
        Cluster<?> cluster = clusters.get(c);
        if (cluster.isNoise() || cluster.size() < 2) {
            continue;
        }
        double currentDscMax = clusterDscMax[c];
        double[] clusterCoreDists = coreDists[c];
        int[] currentDegree = clusterDegrees[c];
        // minimal Density Separation of the Cluster
        double dspcMin = Double.POSITIVE_INFINITY;
        for (DBIDArrayIter it = cids[c].iter(); it.valid(); it.advance()) {
            // nodes.
            if (currentDegree[it.getOffset()] < 2 && internalEdges[c]) {
                continue;
            }
            double currentCoreDist = clusterCoreDists[it.getOffset()];
            for (int oc = 0; oc < numc; oc++) {
                Cluster<?> ocluster = clusters.get(oc);
                if (ocluster.isNoise() || ocluster.size() < 2 || cluster == ocluster) {
                    continue;
                }
                int[] oDegree = clusterDegrees[oc];
                double[] oclusterCoreDists = coreDists[oc];
                for (DBIDArrayIter it2 = cids[oc].iter(); it2.valid(); it2.advance()) {
                    if (oDegree[it2.getOffset()] < 2 && internalEdges[oc]) {
                        continue;
                    }
                    double mutualReachDist = MathUtil.max(currentCoreDist, oclusterCoreDists[it2.getOffset()], dq.distance(it, it2));
                    dspcMin = mutualReachDist < dspcMin ? mutualReachDist : dspcMin;
                }
            }
        }
        // compute DBCV
        double vc = (dspcMin - currentDscMax) / MathUtil.max(dspcMin, currentDscMax);
        double weight = cluster.size() / (double) rel.size();
        dbcv += weight * vc;
    }
    EvaluationResult ev = EvaluationResult.findOrCreate(db.getHierarchy(), cl, "Internal Clustering Evaluation", "internal evaluation");
    MeasurementGroup g = ev.findOrCreateGroup("Distance-based Evaluation");
    g.addMeasure("Density Based Clustering Validation", dbcv, 0., Double.POSITIVE_INFINITY, 0., true);
    db.getHierarchy().resultChanged(ev);
    return dbcv;
}
Also used : DBIDArrayIter(de.lmu.ifi.dbs.elki.database.ids.DBIDArrayIter) MeasurementGroup(de.lmu.ifi.dbs.elki.result.EvaluationResult.MeasurementGroup) EvaluationResult(de.lmu.ifi.dbs.elki.result.EvaluationResult) Relation(de.lmu.ifi.dbs.elki.database.relation.Relation) SpatialComparable(de.lmu.ifi.dbs.elki.data.spatial.SpatialComparable) ArrayDBIDs(de.lmu.ifi.dbs.elki.database.ids.ArrayDBIDs)

Example 9 with SpatialComparable

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

the class LeastEnlargementWithAreaInsertionStrategy method choose.

@Override
public <A> int choose(A options, ArrayAdapter<? extends SpatialComparable, A> getter, SpatialComparable obj, int height, int depth) {
    final int size = getter.size(options);
    assert (size > 0) : "Choose from empty set?";
    // As in R-Tree, with a slight modification for ties
    double leastEnlargement = Double.POSITIVE_INFINITY;
    double minArea = -1;
    int best = -1;
    for (int i = 0; i < size; i++) {
        SpatialComparable entry = getter.get(options, i);
        double enlargement = SpatialUtil.enlargement(entry, obj);
        if (enlargement < leastEnlargement) {
            leastEnlargement = enlargement;
            best = i;
            minArea = SpatialUtil.volume(entry);
        } else if (enlargement == leastEnlargement) {
            final double area = SpatialUtil.volume(entry);
            if (area < minArea) {
                // Tie handling proposed by R*:
                best = i;
                minArea = area;
            }
        }
    }
    assert (best > -1);
    return best;
}
Also used : SpatialComparable(de.lmu.ifi.dbs.elki.data.spatial.SpatialComparable)

Example 10 with SpatialComparable

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

the class MaxExtensionBulkSplit method chooseMaximalExtendedSplitAxis.

/**
 * Computes and returns the best split axis. The best split axis is the split
 * axes with the maximal extension.
 *
 * @param objects the spatial objects to be split
 * @return the best split axis
 */
private int chooseMaximalExtendedSplitAxis(List<? extends SpatialComparable> objects) {
    // maximum and minimum value for the extension
    int dimension = objects.get(0).getDimensionality();
    double[] maxExtension = new double[dimension];
    double[] minExtension = new double[dimension];
    Arrays.fill(minExtension, Double.MAX_VALUE);
    // compute min and max value in each dimension
    for (SpatialComparable object : objects) {
        for (int d = 0; d < dimension; d++) {
            double min, max;
            min = object.getMin(d);
            max = object.getMax(d);
            if (maxExtension[d] < max) {
                maxExtension[d] = max;
            }
            if (minExtension[d] > min) {
                minExtension[d] = min;
            }
        }
    }
    // set split axis to dim with maximal extension
    int splitAxis = -1;
    double max = 0;
    for (int d = 0; d < dimension; d++) {
        double currentExtension = maxExtension[d] - minExtension[d];
        if (max < currentExtension) {
            max = currentExtension;
            splitAxis = d;
        }
    }
    return splitAxis;
}
Also used : SpatialComparable(de.lmu.ifi.dbs.elki.data.spatial.SpatialComparable)

Aggregations

SpatialComparable (de.lmu.ifi.dbs.elki.data.spatial.SpatialComparable)12 HyperBoundingBox (de.lmu.ifi.dbs.elki.data.HyperBoundingBox)3 DoubleIntPair (de.lmu.ifi.dbs.elki.utilities.pairs.DoubleIntPair)2 ModifiableHyperBoundingBox (de.lmu.ifi.dbs.elki.data.ModifiableHyperBoundingBox)1 NumberVector (de.lmu.ifi.dbs.elki.data.NumberVector)1 ArrayDBIDs (de.lmu.ifi.dbs.elki.database.ids.ArrayDBIDs)1 DBIDArrayIter (de.lmu.ifi.dbs.elki.database.ids.DBIDArrayIter)1 DBIDIter (de.lmu.ifi.dbs.elki.database.ids.DBIDIter)1 Relation (de.lmu.ifi.dbs.elki.database.relation.Relation)1 SpatialEntry (de.lmu.ifi.dbs.elki.index.tree.spatial.SpatialEntry)1 DoubleMinMax (de.lmu.ifi.dbs.elki.math.DoubleMinMax)1 EvaluationResult (de.lmu.ifi.dbs.elki.result.EvaluationResult)1 MeasurementGroup (de.lmu.ifi.dbs.elki.result.EvaluationResult.MeasurementGroup)1 TopBoundedHeap (de.lmu.ifi.dbs.elki.utilities.datastructures.heap.TopBoundedHeap)1 ArrayList (java.util.ArrayList)1 List (java.util.List)1