summaryrefslogtreecommitdiff
path: root/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants
diff options
context:
space:
mode:
Diffstat (limited to 'src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants')
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/AbstractMTree.java373
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/AbstractMTreeFactory.java107
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/AbstractMTreeNode.java82
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/MTreeDirectoryEntry.java44
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/MTreeEntry.java14
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/MTreeLeafEntry.java48
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/MTreeSettings.java56
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/AbstractMkTree.java44
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/AbstractMkTreeUnified.java36
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/AbstractMkTreeUnifiedFactory.java58
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/MkTreeHeader.java6
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/MkTreeSettings.java46
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppDirectoryEntry.java11
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppEntry.java7
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppLeafEntry.java9
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppTree.java215
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppTreeFactory.java77
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppTreeIndex.java111
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppTreeNode.java14
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppTreeSettings.java47
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/PolynomialApproximation.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/ApproximationLine.java24
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/ConvexHull.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCoPDirectoryEntry.java29
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCoPEntry.java13
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCoPLeafEntry.java37
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCoPTree.java335
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCoPTreeIndex.java112
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCoPTreeNode.java18
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCopTreeFactory.java43
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxDirectoryEntry.java34
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxEntry.java22
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxLeafEntry.java30
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxTree.java230
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxTreeFactory.java37
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxTreeIndex.java100
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxTreeNode.java35
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabDirectoryEntry.java60
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabEntry.java37
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabLeafEntry.java63
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabTree.java146
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabTreeFactory.java33
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabTreeIndex.java136
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabTreeNode.java44
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mtree/MTree.java90
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mtree/MTreeFactory.java34
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mtree/MTreeIndex.java144
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mtree/MTreeNode.java6
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mtree/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/DoubleDistanceMetricalIndexKNNQuery.java48
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/DoubleDistanceMetricalIndexRangeQuery.java42
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/MTreeQueryUtil.java24
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/MetricalIndexKNNQuery.java83
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/MetricalIndexRangeQuery.java56
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/MkTreeRKNNQuery.java21
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/split/MTreeSplit.java138
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/split/package-info.java26
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/insert/MTreeInsert.java50
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/insert/MinimumEnlargementInsert.java117
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/insert/package-info.java26
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/package-info.java26
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/Assignments.java (renamed from src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/split/Assignments.java)39
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/DistanceEntry.java123
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/MLBDistSplit.java (renamed from src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/split/MLBDistSplit.java)63
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/MMRadSplit.java88
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/MRadSplit.java (renamed from src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/split/MRadSplit.java)54
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/MTreeSplit.java223
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/RandomSplit.java136
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/package-info.java26
76 files changed, 2598 insertions, 2128 deletions
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/AbstractMTree.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/AbstractMTree.java
index a7a063bd..61ca9116 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/AbstractMTree.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/AbstractMTree.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -28,73 +28,67 @@ import java.util.Collections;
import java.util.List;
import de.lmu.ifi.dbs.elki.database.ids.DBID;
-import de.lmu.ifi.dbs.elki.database.ids.DBIDIter;
-import de.lmu.ifi.dbs.elki.database.ids.DBIDs;
-import de.lmu.ifi.dbs.elki.database.query.distance.DistanceQuery;
-import de.lmu.ifi.dbs.elki.distance.DistanceUtil;
+import de.lmu.ifi.dbs.elki.database.ids.DBIDRef;
import de.lmu.ifi.dbs.elki.distance.distancefunction.DistanceFunction;
-import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
+import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
import de.lmu.ifi.dbs.elki.index.tree.BreadthFirstEnumeration;
-import de.lmu.ifi.dbs.elki.index.tree.DistanceEntry;
import de.lmu.ifi.dbs.elki.index.tree.IndexTreePath;
import de.lmu.ifi.dbs.elki.index.tree.TreeIndexPathComponent;
import de.lmu.ifi.dbs.elki.index.tree.metrical.MetricalIndexTree;
-import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.split.Assignments;
-import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.split.MLBDistSplit;
-import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.split.MTreeSplit;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.strategies.split.Assignments;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.strategies.split.DistanceEntry;
+import de.lmu.ifi.dbs.elki.logging.Logging;
+import de.lmu.ifi.dbs.elki.logging.statistics.Counter;
+import de.lmu.ifi.dbs.elki.logging.statistics.LongStatistic;
import de.lmu.ifi.dbs.elki.persistent.PageFile;
-import de.lmu.ifi.dbs.elki.persistent.PageFileUtil;
+import de.lmu.ifi.dbs.elki.utilities.pairs.DoubleIntPair;
/**
* Abstract super class for all M-Tree variants.
*
* @author Elke Achtert
*
- * @apiviz.has SplitResult oneway - - computes
+ * @apiviz.composedOf MTreeSettings
+ * @apiviz.composedOf Statistics
* @apiviz.has AbstractMTreeNode oneway - - contains
+ * @apiviz.excludeSubtypes
*
* @param <O> the type of DatabaseObject to be stored in the metrical index
* @param <D> the type of Distance used in the metrical index
* @param <N> the type of MetricalNode used in the metrical index
* @param <E> the type of MetricalEntry used in the metrical index
+ * @param <S> the type to store settings in.
*/
-public abstract class AbstractMTree<O, D extends Distance<D>, N extends AbstractMTreeNode<O, D, N, E>, E extends MTreeEntry<D>> extends MetricalIndexTree<O, D, N, E> {
+public abstract class AbstractMTree<O, D extends NumberDistance<D, ?>, N extends AbstractMTreeNode<O, D, N, E>, E extends MTreeEntry, S extends MTreeSettings<O, D, N, E>> extends MetricalIndexTree<O, D, N, E> {
/**
* Debugging flag: do extra integrity checks.
*/
protected static final boolean EXTRA_INTEGRITY_CHECKS = false;
/**
- * Holds the instance of the trees distance function.
+ * Tree settings.
*/
- protected DistanceFunction<O, D> distanceFunction;
+ protected S settings;
/**
- * The distance query.
+ * For counting the number of distance computations.
*/
- protected DistanceQuery<O, D> distanceQuery;
+ public Statistics statistics = new Statistics();
/**
* Constructor.
*
* @param pagefile Page file
- * @param distanceQuery Distance query
- * @param distanceFunction Distance function
+ * @param settings Tree settings
*/
- public AbstractMTree(PageFile<N> pagefile, DistanceQuery<O, D> distanceQuery, DistanceFunction<O, D> distanceFunction) {
+ public AbstractMTree(PageFile<N> pagefile, S settings) {
super(pagefile);
- this.distanceQuery = distanceQuery;
- this.distanceFunction = distanceFunction;
+ this.settings = settings;
}
@Override
- public final DistanceFunction<O, D> getDistanceFunction() {
- return distanceFunction;
- }
-
- @Override
- public final DistanceQuery<O, D> getDistanceQuery() {
- return distanceQuery;
+ public final DistanceFunction<? super O, D> getDistanceFunction() {
+ return settings.distanceFunction;
}
/**
@@ -103,7 +97,7 @@ public abstract class AbstractMTree<O, D extends Distance<D>, N extends Abstract
* @return the distance factory used
*/
public final D getDistanceFactory() {
- return distanceFunction.getDistanceFactory();
+ return settings.distanceFunction.getDistanceFactory();
}
/**
@@ -131,7 +125,7 @@ public abstract class AbstractMTree<O, D extends Distance<D>, N extends Abstract
}
}
- BreadthFirstEnumeration<N, E> enumeration = new BreadthFirstEnumeration<N, E>(this, getRootPath());
+ BreadthFirstEnumeration<N, E> enumeration = new BreadthFirstEnumeration<>(this, getRootPath());
while (enumeration.hasMoreElements()) {
IndexTreePath<E> path = enumeration.nextElement();
E entry = path.getLastPathComponent().getEntry();
@@ -158,7 +152,7 @@ public abstract class AbstractMTree<O, D extends Distance<D>, N extends Abstract
result.append(leafNodes).append(" Leaf Nodes \n");
result.append(objects).append(" Objects \n");
- PageFileUtil.appendPageFileStatistics(result, getPageFileStatistics());
+ // PageFileUtil.appendPageFileStatistics(result, getPageFileStatistics());
return result.toString();
}
@@ -180,14 +174,14 @@ public abstract class AbstractMTree<O, D extends Distance<D>, N extends Abstract
}
// choose subtree for insertion
- IndexTreePath<E> subtree = choosePath(entry, getRootPath());
+ IndexTreePath<E> subtree = settings.insertStrategy.choosePath(this, entry);
if (getLogger().isDebugging()) {
getLogger().debugFine("insertion-subtree " + subtree + "\n");
}
// determine parent distance
E parentEntry = subtree.getLastPathComponent().getEntry();
- D parentDistance = distance(parentEntry.getRoutingObjectID(), entry.getRoutingObjectID());
+ double parentDistance = distance(parentEntry.getRoutingObjectID(), entry.getRoutingObjectID()).doubleValue();
entry.setParentDistance(parentDistance);
// create leaf entry and do pre insert
@@ -232,63 +226,6 @@ public abstract class AbstractMTree<O, D extends Distance<D>, N extends Abstract
}
/**
- * Chooses the best path of the specified subtree for insertion of the given
- * object.
- *
- * @param object the entry to search
- * @param subtree the subtree to be tested for insertion
- * @return the path of the appropriate subtree to insert the given object
- */
- private IndexTreePath<E> choosePath(E object, IndexTreePath<E> subtree) {
- N node = getNode(subtree.getLastPathComponent().getEntry());
-
- // leaf
- if (node.isLeaf()) {
- return subtree;
- }
-
- DistanceEntry<D, E> bestCandidate;
- D enlarge; // Track best enlargement - null for no enlargement needed.
- // Initialize from first:
- {
- E entry = node.getEntry(0);
- D distance = distance(object.getRoutingObjectID(), entry.getRoutingObjectID());
- bestCandidate = new DistanceEntry<D, E>(entry, distance, 0);
- if (distance.compareTo(entry.getCoveringRadius()) <= 0) {
- enlarge = null;
- } else {
- enlarge = distance.minus(entry.getCoveringRadius());
- }
- }
-
- // Iterate over remaining
- for (int i = 1; i < node.getNumEntries(); i++) {
- E entry = node.getEntry(i);
- D distance = distance(object.getRoutingObjectID(), entry.getRoutingObjectID());
-
- if (distance.compareTo(entry.getCoveringRadius()) <= 0) {
- if (enlarge != null || distance.compareTo(bestCandidate.getDistance()) < 0) {
- bestCandidate = new DistanceEntry<D, E>(entry, distance, i);
- enlarge = null;
- }
- } else if (enlarge != null) {
- D enlrg = distance.minus(entry.getCoveringRadius());
- if (enlrg.compareTo(enlarge) < 0) {
- bestCandidate = new DistanceEntry<D, E>(entry, distance, i);
- enlarge = enlrg;
- }
- }
- }
-
- // Apply enlargement
- if (enlarge != null) {
- bestCandidate.getEntry().setCoveringRadius(enlarge);
- }
-
- return choosePath(object, subtree.pathByAddingChild(new TreeIndexPathComponent<E>(bestCandidate.getEntry(), bestCandidate.getIndex())));
- }
-
- /**
* Sorts the entries of the specified node according to their minimum distance
* to the specified object.
*
@@ -296,44 +233,16 @@ public abstract class AbstractMTree<O, D extends Distance<D>, N extends Abstract
* @param q the id of the object
* @return a list of the sorted entries
*/
- protected final List<DistanceEntry<D, E>> getSortedEntries(N node, DBID q) {
- List<DistanceEntry<D, E>> result = new ArrayList<DistanceEntry<D, E>>();
-
- for (int i = 0; i < node.getNumEntries(); i++) {
- E entry = node.getEntry(i);
- D distance = distance(entry.getRoutingObjectID(), q);
- D radius = entry.getCoveringRadius();
- D minDist = radius.compareTo(distance) > 0 ? getDistanceFactory().nullDistance() : distance.minus(radius);
-
- result.add(new DistanceEntry<D, E>(entry, minDist, i));
- }
-
- Collections.sort(result);
- return result;
- }
-
- /**
- * Sorts the entries of the specified node according to their minimum distance
- * to the specified objects.
- *
- * @param node the node
- * @param ids the ids of the objects
- * @return a list of the sorted entries
- */
- protected final List<DistanceEntry<D, E>> getSortedEntries(N node, DBIDs ids) {
- List<DistanceEntry<D, E>> result = new ArrayList<DistanceEntry<D, E>>();
+ protected final List<DoubleIntPair> getSortedEntries(N node, DBID q) {
+ List<DoubleIntPair> result = new ArrayList<>();
for (int i = 0; i < node.getNumEntries(); i++) {
E entry = node.getEntry(i);
- D radius = entry.getCoveringRadius();
+ double distance = distance(entry.getRoutingObjectID(), q).doubleValue();
+ double radius = entry.getCoveringRadius();
+ double minDist = (radius > distance) ? 0.0 : distance - radius;
- D minMinDist = getDistanceFactory().infiniteDistance();
- for (DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) {
- D distance = distanceQuery.distance(entry.getRoutingObjectID(), iter);
- D minDist = radius.compareTo(distance) > 0 ? getDistanceFactory().nullDistance() : distance.minus(radius);
- minMinDist = DistanceUtil.min(minMinDist, minDist);
- }
- result.add(new DistanceEntry<D, E>(entry, minMinDist, i));
+ result.add(new DoubleIntPair(minDist, i));
}
Collections.sort(result);
@@ -347,11 +256,17 @@ public abstract class AbstractMTree<O, D extends Distance<D>, N extends Abstract
* @param id2 the second id
* @return the distance between the two specified ids
*/
- protected final D distance(DBID id1, DBID id2) {
- if (id1 == null || id2 == null) {
- return getDistanceFactory().undefinedDistance();
- }
- return distanceQuery.distance(id1, id2);
+ public abstract D distance(DBIDRef id1, DBIDRef id2);
+
+ /**
+ * Returns the distance between the routing object of two entries.
+ *
+ * @param e1 First entry
+ * @param e2 Second entry
+ * @return the distance between the two routing objects
+ */
+ public final D distance(E e1, E e2) {
+ return distance(e1.getRoutingObjectID(), e2.getRoutingObjectID());
}
/**
@@ -363,38 +278,7 @@ public abstract class AbstractMTree<O, D extends Distance<D>, N extends Abstract
* the routing object of the parent node
* @return the newly created directory entry
*/
- protected abstract E createNewDirectoryEntry(N node, DBID routingObjectID, D parentDistance);
-
- /**
- * Splits the specified node and returns the split result.
- *
- * @param node the node to be split
- * @return the split result
- */
- private SplitResult split(N node) {
- // do the split
- // todo split stratgey
- MTreeSplit<O, D, N, E> split = new MLBDistSplit<O, D, N, E>(node, distanceQuery);
- Assignments<D, E> assignments = split.getAssignments();
- final N newNode;
- if (node.isLeaf()) {
- newNode = createNewLeafNode();
- } else {
- newNode = createNewDirectoryNode();
- }
- node.splitTo(newNode, assignments.getFirstAssignments(), assignments.getSecondAssignments());
-
- // write changes to file
- writeNode(node);
- writeNode(newNode);
-
- if (getLogger().isDebugging()) {
- String msg = "Split Node " + node.getPageID() + " (" + this.getClass() + ")\n" + " newNode " + newNode.getPageID() + "\n" + " firstPromoted " + assignments.getFirstRoutingObject() + "\n" + " firstAssignments(" + node.getPageID() + ") " + assignments.getFirstAssignments() + "\n" + " firstCR " + assignments.getFirstCoveringRadius() + "\n" + " secondPromoted " + assignments.getSecondRoutingObject() + "\n" + " secondAssignments(" + newNode.getPageID() + ") " + assignments.getSecondAssignments() + "\n" + " secondCR " + assignments.getSecondCoveringRadius() + "\n";
- getLogger().debugFine(msg);
- }
-
- return new SplitResult(split, newNode);
- }
+ protected abstract E createNewDirectoryEntry(N node, DBID routingObjectID, double parentDistance);
/**
* Adjusts the tree after insertion of some nodes.
@@ -412,15 +296,39 @@ public abstract class AbstractMTree<O, D extends Distance<D>, N extends Abstract
// overflow in node; split the node
if (hasOverflow(node)) {
- SplitResult splitResult = split(node);
- N splitNode = splitResult.newNode;
- Assignments<D, E> assignments = splitResult.split.getAssignments();
+ // do the split
+ Assignments<E> assignments = settings.splitStrategy.split(this, node);
+ final N newNode = node.isLeaf() ? createNewLeafNode() : createNewDirectoryNode();
+
+ List<E> entries1 = new ArrayList<>(assignments.getFirstAssignments().size());
+ List<E> entries2 = new ArrayList<>(assignments.getSecondAssignments().size());
+ // Store final parent distances:
+ for (DistanceEntry<E> ent : assignments.getFirstAssignments()) {
+ final E e = ent.getEntry();
+ e.setParentDistance(ent.getDistance());
+ entries1.add(e);
+ }
+ for (DistanceEntry<E> ent : assignments.getSecondAssignments()) {
+ final E e = ent.getEntry();
+ e.setParentDistance(ent.getDistance());
+ entries2.add(e);
+ }
+ node.splitTo(newNode, entries1, entries2);
+
+ // write changes to file
+ writeNode(node);
+ writeNode(newNode);
+
+ if (getLogger().isDebugging()) {
+ String msg = "Split Node " + node.getPageID() + " (" + this.getClass() + ")\n" + " newNode " + newNode.getPageID() + "\n" + " firstPromoted " + assignments.getFirstRoutingObject() + "\n" + " firstAssignments(" + node.getPageID() + ") " + assignments.getFirstAssignments() + "\n" + " firstCR " + assignments.getFirstCoveringRadius() + "\n" + " secondPromoted " + assignments.getSecondRoutingObject() + "\n" + " secondAssignments(" + newNode.getPageID() + ") " + assignments.getSecondAssignments() + "\n" + " secondCR " + assignments.getSecondCoveringRadius() + "\n";
+ getLogger().debugFine(msg);
+ }
// if root was split: create a new root that points the two split
// nodes
if (isRoot(node)) {
// FIXME: stimmen die parentDistance der Kinder in node & splitNode?
- IndexTreePath<E> newRootPath = createNewRoot(node, splitNode, assignments.getFirstRoutingObject(), assignments.getSecondRoutingObject());
+ IndexTreePath<E> newRootPath = createNewRoot(node, newNode, assignments.getFirstRoutingObject(), assignments.getSecondRoutingObject());
adjustTree(newRootPath);
}
// node is not root
@@ -431,13 +339,13 @@ public abstract class AbstractMTree<O, D extends Distance<D>, N extends Abstract
if (getLogger().isDebugging()) {
getLogger().debugFine("parent " + parent);
}
- D parentDistance2 = distance(parentEntry.getRoutingObjectID(), assignments.getSecondRoutingObject());
+ double parentDistance2 = distance(parentEntry.getRoutingObjectID(), assignments.getSecondRoutingObject()).doubleValue();
// logger.warning("parent: "+parent.toString()+" split: " +
// splitNode.toString()+ " dist:"+parentDistance2);
- parent.addDirectoryEntry(createNewDirectoryEntry(splitNode, assignments.getSecondRoutingObject(), parentDistance2));
+ parent.addDirectoryEntry(createNewDirectoryEntry(newNode, assignments.getSecondRoutingObject(), parentDistance2));
// adjust the entry representing the (old) node, that has been split
- D parentDistance1 = distance(parentEntry.getRoutingObjectID(), assignments.getFirstRoutingObject());
+ double parentDistance1 = distance(parentEntry.getRoutingObjectID(), assignments.getFirstRoutingObject()).doubleValue();
// logger.warning("parent: "+parent.toString()+" node: " +
// node.toString()+ " dist:"+parentDistance1);
node.adjustEntry(parent.getEntry(nodeIndex), assignments.getFirstRoutingObject(), parentDistance1, this);
@@ -517,8 +425,8 @@ public abstract class AbstractMTree<O, D extends Distance<D>, N extends Abstract
// firstRoutingObjectID);
// D parentDistance2 = distance(getRootEntry().getRoutingObjectID(),
// secondRoutingObjectID);
- E oldRootEntry = createNewDirectoryEntry(oldRoot, firstRoutingObjectID, null);
- E newRootEntry = createNewDirectoryEntry(newNode, secondRoutingObjectID, null);
+ E oldRootEntry = createNewDirectoryEntry(oldRoot, firstRoutingObjectID, 0.);
+ E newRootEntry = createNewDirectoryEntry(newNode, secondRoutingObjectID, 0.);
root.addDirectoryEntry(oldRootEntry);
root.addDirectoryEntry(newRootEntry);
@@ -536,41 +444,13 @@ public abstract class AbstractMTree<O, D extends Distance<D>, N extends Abstract
getLogger().debugFine(msg);
}
- return new IndexTreePath<E>(new TreeIndexPathComponent<E>(getRootEntry(), null));
- }
-
- /**
- * Encapsulates a split object and the newly created node.
- *
- * @apiviz.composedOf MTreeSplit
- */
- private class SplitResult {
- /**
- * Split used
- */
- protected MTreeSplit<O, D, N, E> split;
-
- /**
- * New sibling
- */
- protected N newNode;
-
- /**
- * Constructor.
- *
- * @param split Split that was used
- * @param newNode New sibling
- */
- public SplitResult(MTreeSplit<O, D, N, E> split, N newNode) {
- this.split = split;
- this.newNode = newNode;
- }
+ return new IndexTreePath<>(new TreeIndexPathComponent<>(getRootEntry(), null));
}
@Override
public List<E> getLeaves() {
- List<E> result = new ArrayList<E>();
- BreadthFirstEnumeration<N, E> enumeration = new BreadthFirstEnumeration<N, E>(this, getRootPath());
+ List<E> result = new ArrayList<>();
+ BreadthFirstEnumeration<N, E> enumeration = new BreadthFirstEnumeration<>(this, getRootPath());
while (enumeration.hasMoreElements()) {
IndexTreePath<E> path = enumeration.nextElement();
E entry = path.getLastPathComponent().getEntry();
@@ -603,4 +483,93 @@ public abstract class AbstractMTree<O, D extends Distance<D>, N extends Abstract
}
return levels;
}
+
+ @Override
+ public void logStatistics() {
+ super.logStatistics();
+ Logging log = getLogger();
+ if (log.isStatistics()) {
+ log.statistics(new LongStatistic(this.getClass().getName() + ".height", getHeight()));
+ statistics.logStatistics();
+ }
+ }
+
+ /**
+ * Class for tracking some statistics.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.composedOf Counter
+ */
+ public class Statistics {
+ /**
+ * For counting the number of distance computations.
+ */
+ protected final Counter distanceCalcs;
+
+ /**
+ * For counting the number of knn queries answered.
+ */
+ protected final Counter knnQueries;
+
+ /**
+ * For counting the number of range queries answered.
+ */
+ protected final Counter rangeQueries;
+
+ /**
+ * Constructor.
+ */
+ public Statistics() {
+ super();
+ Logging log = getLogger();
+ distanceCalcs = log.isStatistics() ? log.newCounter(this.getClass().getName() + ".distancecalcs") : null;
+ knnQueries = log.isStatistics() ? log.newCounter(this.getClass().getName() + ".knnqueries") : null;
+ rangeQueries = log.isStatistics() ? log.newCounter(this.getClass().getName() + ".rangequeries") : null;
+ }
+
+ /**
+ * Count a distance computation.
+ */
+ public void countDistanceCalculation() {
+ if (distanceCalcs != null) {
+ distanceCalcs.increment();
+ }
+ }
+
+ /**
+ * Count a knn query invocation.
+ */
+ public void countKNNQuery() {
+ if (knnQueries != null) {
+ knnQueries.increment();
+ }
+ }
+
+ /**
+ * Count a range query invocation.
+ */
+ public void countRangeQuery() {
+ if (rangeQueries != null) {
+ rangeQueries.increment();
+ }
+ }
+
+ /**
+ * Log the statistics.
+ */
+ public void logStatistics() {
+ Logging log = getLogger();
+ if (statistics.distanceCalcs != null) {
+ log.statistics(statistics.distanceCalcs);
+ }
+ if (statistics.knnQueries != null) {
+ log.statistics(statistics.knnQueries);
+ }
+ if (statistics.rangeQueries != null) {
+ log.statistics(statistics.rangeQueries);
+ }
+ }
+ }
+
}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/AbstractMTreeFactory.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/AbstractMTreeFactory.java
index 3769a562..7a0baa8a 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/AbstractMTreeFactory.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/AbstractMTreeFactory.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -25,10 +25,15 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants;
import de.lmu.ifi.dbs.elki.data.type.TypeInformation;
import de.lmu.ifi.dbs.elki.distance.distancefunction.DistanceFunction;
-import de.lmu.ifi.dbs.elki.distance.distancefunction.EuclideanDistanceFunction;
-import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
+import de.lmu.ifi.dbs.elki.distance.distancefunction.minkowski.EuclideanDistanceFunction;
+import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
import de.lmu.ifi.dbs.elki.index.Index;
-import de.lmu.ifi.dbs.elki.index.tree.TreeIndexFactory;
+import de.lmu.ifi.dbs.elki.index.PagedIndexFactory;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.strategies.insert.MTreeInsert;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.strategies.insert.MinimumEnlargementInsert;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.strategies.split.MMRadSplit;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.strategies.split.MTreeSplit;
+import de.lmu.ifi.dbs.elki.persistent.PageFileFactory;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.ObjectParameter;
@@ -40,6 +45,7 @@ import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.ObjectParameter;
*
* @apiviz.stereotype factory
* @apiviz.uses AbstractMTree oneway - - «create»
+ * @apiviz.excludeSubtypes
*
* @param <O> Object type
* @param <D> Distance type
@@ -47,43 +53,26 @@ import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.ObjectParameter;
* @param <E> Entry type
* @param <I> Index type
*/
-public abstract class AbstractMTreeFactory<O, D extends Distance<D>, N extends AbstractMTreeNode<O, D, N, E>, E extends MTreeEntry<D>, I extends AbstractMTree<O, D, N, E> & Index> extends TreeIndexFactory<O, I> {
+public abstract class AbstractMTreeFactory<O, D extends NumberDistance<D, ?>, N extends AbstractMTreeNode<O, D, N, E>, E extends MTreeEntry, I extends AbstractMTree<O, D, N, E, S> & Index, S extends MTreeSettings<O, D, N, E>> extends PagedIndexFactory<O, I> {
/**
- * Parameter to specify the distance function to determine the distance
- * between database objects, must extend
- * {@link de.lmu.ifi.dbs.elki.distance.distancefunction.DistanceFunction}.
- * <p>
- * Key: {@code -mtree.distancefunction}
- * </p>
- * <p>
- * Default value:
- * {@link de.lmu.ifi.dbs.elki.distance.distancefunction.EuclideanDistanceFunction}
- * </p>
+ * Tree settings.
*/
- public static final OptionID DISTANCE_FUNCTION_ID = new OptionID("mtree.distancefunction", "Distance function to determine the distance between database objects.");
-
- /**
- * Holds the instance of the distance function specified by
- * {@link #DISTANCE_FUNCTION_ID}.
- */
- protected DistanceFunction<O, D> distanceFunction;
+ protected S settings;
/**
* Constructor.
*
- * @param fileName
- * @param pageSize
- * @param cacheSize
- * @param distanceFunction
+ * @param pageFileFactory Data storage
+ * @param settings Tree settings
*/
- public AbstractMTreeFactory(String fileName, int pageSize, long cacheSize, DistanceFunction<O, D> distanceFunction) {
- super(fileName, pageSize, cacheSize);
- this.distanceFunction = distanceFunction;
+ public AbstractMTreeFactory(PageFileFactory<?> pageFileFactory, S settings) {
+ super(pageFileFactory);
+ this.settings = settings;
}
@Override
public TypeInformation getInputTypeRestriction() {
- return distanceFunction.getInputTypeRestriction();
+ return settings.distanceFunction.getInputTypeRestriction();
}
/**
@@ -93,19 +82,63 @@ public abstract class AbstractMTreeFactory<O, D extends Distance<D>, N extends A
*
* @apiviz.exclude
*/
- public abstract static class Parameterizer<O, D extends Distance<D>> extends TreeIndexFactory.Parameterizer<O> {
- protected DistanceFunction<O, D> distanceFunction = null;
+ public abstract static class Parameterizer<O, D extends NumberDistance<D, ?>, N extends AbstractMTreeNode<O, D, N, E>, E extends MTreeEntry, S extends MTreeSettings<O, D, N, E>> extends PagedIndexFactory.Parameterizer<O> {
+ /**
+ * Parameter to specify the distance function to determine the distance
+ * between database objects, must extend
+ * {@link de.lmu.ifi.dbs.elki.distance.distancefunction.DistanceFunction}.
+ * <p>
+ * Key: {@code -mtree.distancefunction}
+ * </p>
+ * <p>
+ * Default value:
+ * {@link de.lmu.ifi.dbs.elki.distance.distancefunction.minkowski.EuclideanDistanceFunction}
+ * </p>
+ */
+ public static final OptionID DISTANCE_FUNCTION_ID = new OptionID("mtree.distancefunction", "Distance function to determine the distance between database objects.");
+
+ /**
+ * Parameter to specify the splitting strategy to construct the tree.
+ * <p>
+ * Key: {@code -mtree.split}
+ * </p>
+ */
+ public static final OptionID SPLIT_STRATEGY_ID = new OptionID("mtree.split", "Split strategy to use for constructing the M-tree.");
+
+ /**
+ * Parameter to specify the insertion strategy to construct the tree.
+ * <p>
+ * Key: {@code -mtree.insert}
+ * </p>
+ */
+ public static final OptionID INSERT_STRATEGY_ID = new OptionID("mtree.insert", "Insertion strategy to use for constructing the M-tree.");
+
+ /**
+ * Tree settings.
+ */
+ protected S settings;
@Override
protected void makeOptions(Parameterization config) {
super.makeOptions(config);
- ObjectParameter<DistanceFunction<O, D>> distanceFunctionP = new ObjectParameter<DistanceFunction<O, D>>(DISTANCE_FUNCTION_ID, DistanceFunction.class, EuclideanDistanceFunction.class);
- if(config.grab(distanceFunctionP)) {
- distanceFunction = distanceFunctionP.instantiateClass(config);
+ settings = makeSettings();
+ ObjectParameter<DistanceFunction<O, D>> distanceFunctionP = new ObjectParameter<>(DISTANCE_FUNCTION_ID, DistanceFunction.class, EuclideanDistanceFunction.class);
+ if (config.grab(distanceFunctionP)) {
+ settings.distanceFunction = distanceFunctionP.instantiateClass(config);
+ }
+ ObjectParameter<MTreeSplit<O, D, N, E>> splitStrategyP = new ObjectParameter<>(SPLIT_STRATEGY_ID, MTreeSplit.class, MMRadSplit.class);
+ if (config.grab(splitStrategyP)) {
+ settings.splitStrategy = splitStrategyP.instantiateClass(config);
+ }
+ ObjectParameter<MTreeInsert<O, D, N, E>> insertStrategyP = new ObjectParameter<>(INSERT_STRATEGY_ID, MTreeInsert.class, MinimumEnlargementInsert.class);
+ if (config.grab(insertStrategyP)) {
+ settings.insertStrategy = insertStrategyP.instantiateClass(config);
}
}
+ abstract protected S makeSettings();
+
@Override
- protected abstract AbstractMTreeFactory<O, D, ?, ?, ?> makeInstance();
+ protected abstract AbstractMTreeFactory<O, D, N, E, ?, ?> makeInstance();
}
-} \ No newline at end of file
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/AbstractMTreeNode.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/AbstractMTreeNode.java
index 85a9571d..1c1f486c 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/AbstractMTreeNode.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/AbstractMTreeNode.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -26,8 +26,6 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants;
import java.util.logging.Logger;
import de.lmu.ifi.dbs.elki.database.ids.DBID;
-import de.lmu.ifi.dbs.elki.distance.DistanceUtil;
-import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
import de.lmu.ifi.dbs.elki.index.tree.AbstractNode;
import de.lmu.ifi.dbs.elki.logging.LoggingConfiguration;
@@ -38,13 +36,14 @@ import de.lmu.ifi.dbs.elki.logging.LoggingConfiguration;
* @author Elke Achtert
*
* @apiviz.has MTreeEntry oneway - - contains
+ * @apiviz.excludeSubtypes
*
* @param <O> the type of DatabaseObject to be stored in the M-Tree
* @param <D> the type of Distance used in the M-Tree
* @param <N> the type of AbstractMTreeNode used in the M-Tree
* @param <E> the type of MetricalEntry used in the M-Tree
*/
-public abstract class AbstractMTreeNode<O, D extends Distance<D>, N extends AbstractMTreeNode<O, D, N, E>, E extends MTreeEntry<D>> extends AbstractNode<E> {
+public abstract class AbstractMTreeNode<O, D extends NumberDistance<D, ?>, N extends AbstractMTreeNode<O, D, N, E>, E extends MTreeEntry> extends AbstractNode<E> {
/**
* Empty constructor for Externalizable interface.
*/
@@ -74,14 +73,14 @@ public abstract class AbstractMTreeNode<O, D extends Distance<D>, N extends Abst
* the routing object of the parent node
* @param mTree the M-Tree object holding this node
*/
- public void adjustEntry(E entry, DBID routingObjectID, D parentDistance, AbstractMTree<O, D, N, E> mTree) {
+ public void adjustEntry(E entry, DBID routingObjectID, double parentDistance, AbstractMTree<O, D, N, E, ?> mTree) {
entry.setRoutingObjectID(routingObjectID);
entry.setParentDistance(parentDistance);
entry.setCoveringRadius(coveringRadius(entry.getRoutingObjectID(), mTree));
- for(int i = 0; i < getNumEntries(); i++) {
+ for (int i = 0; i < getNumEntries(); i++) {
E childEntry = getEntry(i);
- D dist = mTree.distance(routingObjectID, childEntry.getRoutingObjectID());
+ double dist = mTree.distance(routingObjectID, childEntry.getRoutingObjectID()).doubleValue();
childEntry.setParentDistance(dist);
}
}
@@ -93,17 +92,12 @@ public abstract class AbstractMTreeNode<O, D extends Distance<D>, N extends Abst
* @param mTree the M-Tree
* @return the covering radius of this node
*/
- public D coveringRadius(DBID routingObjectID, AbstractMTree<O, D, N, E> mTree) {
- D coveringRadius = mTree.getDistanceFactory().nullDistance();
- for(int i = 0; i < getNumEntries(); i++) {
+ public double coveringRadius(DBID routingObjectID, AbstractMTree<O, D, N, E, ?> mTree) {
+ double coveringRadius = 0.;
+ for (int i = 0; i < getNumEntries(); i++) {
E entry = getEntry(i);
- D distance = mTree.distance(entry.getRoutingObjectID(), routingObjectID);
- // extend by the other objects covering radius, if non-null
- D d2 = entry.getCoveringRadius();
- if(d2 != null) {
- distance = distance.plus(d2);
- }
- coveringRadius = DistanceUtil.max(coveringRadius, distance);
+ double distance = mTree.distance(entry.getRoutingObjectID(), routingObjectID).doubleValue() + entry.getCoveringRadius();
+ coveringRadius = Math.max(coveringRadius, distance);
}
return coveringRadius;
}
@@ -115,48 +109,47 @@ public abstract class AbstractMTreeNode<O, D extends Distance<D>, N extends Abst
* @param entry the entry representing this node
*/
@SuppressWarnings("unchecked")
- public final void integrityCheck(AbstractMTree<O, D, N, E> mTree, E entry) {
+ public final void integrityCheck(AbstractMTree<O, D, N, E, ?> mTree, E entry) {
// leaf node
- if(isLeaf()) {
- for(int i = 0; i < getCapacity(); i++) {
+ if (isLeaf()) {
+ for (int i = 0; i < getCapacity(); i++) {
E e = getEntry(i);
- if(i < getNumEntries() && e == null) {
+ if (i < getNumEntries() && e == null) {
throw new RuntimeException("i < numEntries && entry == null");
}
- if(i >= getNumEntries() && e != null) {
+ if (i >= getNumEntries() && e != null) {
throw new RuntimeException("i >= numEntries && entry != null");
}
}
}
-
// dir node
else {
N tmp = mTree.getNode(getEntry(0));
boolean childIsLeaf = tmp.isLeaf();
- for(int i = 0; i < getCapacity(); i++) {
+ for (int i = 0; i < getCapacity(); i++) {
E e = getEntry(i);
- if(i < getNumEntries() && e == null) {
+ if (i < getNumEntries() && e == null) {
throw new RuntimeException("i < numEntries && entry == null");
}
- if(i >= getNumEntries() && e != null) {
+ if (i >= getNumEntries() && e != null) {
throw new RuntimeException("i >= numEntries && entry != null");
}
- if(e != null) {
+ if (e != null) {
N node = mTree.getNode(e);
- if(childIsLeaf && !node.isLeaf()) {
- for(int k = 0; k < getNumEntries(); k++) {
+ if (childIsLeaf && !node.isLeaf()) {
+ for (int k = 0; k < getNumEntries(); k++) {
mTree.getNode(getEntry(k));
}
throw new RuntimeException("Wrong Child in " + this + " at " + i);
}
- if(!childIsLeaf && node.isLeaf()) {
+ if (!childIsLeaf && node.isLeaf()) {
throw new RuntimeException("Wrong Child: child id no leaf, but node is leaf!");
}
@@ -166,7 +159,7 @@ public abstract class AbstractMTreeNode<O, D extends Distance<D>, N extends Abst
}
}
- if(LoggingConfiguration.DEBUG) {
+ if (LoggingConfiguration.DEBUG) {
Logger.getLogger(this.getClass().getName()).fine("DirNode " + getPageID() + " ok!");
}
}
@@ -181,30 +174,19 @@ public abstract class AbstractMTreeNode<O, D extends Distance<D>, N extends Abst
* @param index the index of the entry in the parents child arry
* @param mTree the M-Tree holding this node
*/
- protected void integrityCheckParameters(E parentEntry, N parent, int index, AbstractMTree<O, D, N, E> mTree) {
+ protected void integrityCheckParameters(E parentEntry, N parent, int index, AbstractMTree<O, D, N, E, ?> mTree) {
// test if parent distance is correctly set
E entry = parent.getEntry(index);
- D parentDistance = mTree.distance(entry.getRoutingObjectID(), parentEntry.getRoutingObjectID());
- if(!entry.getParentDistance().equals(parentDistance)) {
- String soll = parentDistance.toString();
- String ist = entry.getParentDistance().toString();
- throw new RuntimeException("Wrong parent distance in node " + parent.getPageID() + " at index " + index + " (child " + entry + ")" + "\nsoll: " + soll + ",\n ist: " + ist);
+ double parentDistance = mTree.distance(entry.getRoutingObjectID(), parentEntry.getRoutingObjectID()).doubleValue();
+ if (Math.abs(entry.getParentDistance() - parentDistance) > 1E-10) {
+ throw new RuntimeException("Wrong parent distance in node " + parent.getPageID() + " at index " + index + " (child " + entry + ")" + "\nsoll: " + parentDistance + ",\n ist: " + entry.getParentDistance());
}
// test if covering radius is correctly set
- D mincover = parentDistance.plus(entry.getCoveringRadius());
- if(parentEntry.getCoveringRadius().compareTo(mincover) < 0) {
- String msg = "pcr < pd + cr \n" + parentEntry.getCoveringRadius() + " < " + parentDistance + " + " + entry.getCoveringRadius() + "in node " + parent.getPageID() + " at index " + index + " (child " + entry + "):\n" + "dist(" + entry.getRoutingObjectID() + " - " + parentEntry.getRoutingObjectID() + ")" + " > cr(" + entry + ")";
-
- // throw new RuntimeException(msg);
- if(parentDistance instanceof NumberDistance<?, ?>) {
- double d1 = Double.parseDouble(parentDistance.toString());
- double d2 = Double.parseDouble(entry.getCoveringRadius().toString());
- if(Math.abs(d1 - d2) > 0.000000001) {
- throw new RuntimeException(msg);
- }
- }
- else {
+ double mincover = parentDistance + entry.getCoveringRadius();
+ if (parentEntry.getCoveringRadius() < mincover) {
+ if (Math.abs(parentDistance - entry.getCoveringRadius()) > 1e-10) {
+ String msg = "pcr < pd + cr \n" + parentEntry.getCoveringRadius() + " < " + parentDistance + " + " + entry.getCoveringRadius() + "in node " + parent.getPageID() + " at index " + index + " (child " + entry + "):\n" + "dist(" + entry.getRoutingObjectID() + " - " + parentEntry.getRoutingObjectID() + ")" + " > cr(" + entry + ")";
throw new RuntimeException(msg);
}
}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/MTreeDirectoryEntry.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/MTreeDirectoryEntry.java
index 3902973f..92d0a7ea 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/MTreeDirectoryEntry.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/MTreeDirectoryEntry.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -29,7 +29,6 @@ import java.io.ObjectOutput;
import de.lmu.ifi.dbs.elki.database.ids.DBID;
import de.lmu.ifi.dbs.elki.database.ids.DBIDUtil;
-import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
import de.lmu.ifi.dbs.elki.index.tree.AbstractDirectoryEntry;
/**
@@ -39,10 +38,9 @@ import de.lmu.ifi.dbs.elki.index.tree.AbstractDirectoryEntry;
* the routing object of the entry to its parent's routing object in the M-Tree.
*
* @author Elke Achtert
- * @param <D> the type of Distance used in the M-Tree
*/
-public class MTreeDirectoryEntry<D extends Distance<D>> extends AbstractDirectoryEntry implements MTreeEntry<D> {
- private static final long serialVersionUID = 1;
+public class MTreeDirectoryEntry extends AbstractDirectoryEntry implements MTreeEntry {
+ private static final long serialVersionUID = 2;
/**
* The id of routing object of this entry.
@@ -53,12 +51,12 @@ public class MTreeDirectoryEntry<D extends Distance<D>> extends AbstractDirector
* The distance from the routing object of this entry to its parent's routing
* object.
*/
- private D parentDistance;
+ private double parentDistance;
/**
* The covering radius of the entry.
*/
- private D coveringRadius;
+ private double coveringRadius;
/**
* Empty constructor for serialization purposes.
@@ -76,7 +74,7 @@ public class MTreeDirectoryEntry<D extends Distance<D>> extends AbstractDirector
* @param nodeID the id of the underlying node
* @param coveringRadius the covering radius of the entry
*/
- public MTreeDirectoryEntry(DBID objectID, D parentDistance, Integer nodeID, D coveringRadius) {
+ public MTreeDirectoryEntry(DBID objectID, double parentDistance, Integer nodeID, double coveringRadius) {
super(nodeID);
this.routingObjectID = objectID;
this.parentDistance = parentDistance;
@@ -89,7 +87,7 @@ public class MTreeDirectoryEntry<D extends Distance<D>> extends AbstractDirector
* @return the covering radius of this entry
*/
@Override
- public final D getCoveringRadius() {
+ public final double getCoveringRadius() {
return coveringRadius;
}
@@ -99,7 +97,7 @@ public class MTreeDirectoryEntry<D extends Distance<D>> extends AbstractDirector
* @param coveringRadius the covering radius to be set
*/
@Override
- public final void setCoveringRadius(D coveringRadius) {
+ public final void setCoveringRadius(double coveringRadius) {
this.coveringRadius = coveringRadius;
}
@@ -131,7 +129,7 @@ public class MTreeDirectoryEntry<D extends Distance<D>> extends AbstractDirector
* routing object.
*/
@Override
- public final D getParentDistance() {
+ public final double getParentDistance() {
return parentDistance;
}
@@ -141,7 +139,7 @@ public class MTreeDirectoryEntry<D extends Distance<D>> extends AbstractDirector
* @param parentDistance the distance to be set
*/
@Override
- public final void setParentDistance(D parentDistance) {
+ public final void setParentDistance(double parentDistance) {
this.parentDistance = parentDistance;
}
@@ -153,8 +151,8 @@ public class MTreeDirectoryEntry<D extends Distance<D>> extends AbstractDirector
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
out.writeInt(DBIDUtil.asInteger(routingObjectID));
- out.writeObject(parentDistance);
- out.writeObject(coveringRadius);
+ out.writeDouble(parentDistance);
+ out.writeDouble(coveringRadius);
}
/**
@@ -162,12 +160,11 @@ public class MTreeDirectoryEntry<D extends Distance<D>> extends AbstractDirector
* and the coveringRadius of this entry from the specified input stream.
*/
@Override
- @SuppressWarnings( { "unchecked" })
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
this.routingObjectID = DBIDUtil.importInteger(in.readInt());
- this.parentDistance = (D) in.readObject();
- this.coveringRadius = (D) in.readObject();
+ this.parentDistance = in.readDouble();
+ this.coveringRadius = in.readDouble();
}
/**
@@ -189,24 +186,23 @@ public class MTreeDirectoryEntry<D extends Distance<D>> extends AbstractDirector
* and routingObjectID as this entry.
*/
@Override
- @SuppressWarnings("unchecked")
public boolean equals(Object o) {
- if(this == o) {
+ if (this == o) {
return true;
}
- if(o == null || getClass() != o.getClass()) {
+ if (o == null || getClass() != o.getClass()) {
return false;
}
- if(!super.equals(o)) {
+ if (!super.equals(o)) {
return false;
}
- final MTreeDirectoryEntry<D> that = (MTreeDirectoryEntry<D>) o;
+ final MTreeDirectoryEntry that = (MTreeDirectoryEntry) o;
- if(coveringRadius != null ? !coveringRadius.equals(that.coveringRadius) : that.coveringRadius != null) {
+ if (Math.abs(coveringRadius - that.coveringRadius) < Double.MIN_NORMAL) {
return false;
}
- if(parentDistance != null ? !parentDistance.equals(that.parentDistance) : that.parentDistance != null) {
+ if (Math.abs(parentDistance - that.parentDistance) < Double.MIN_NORMAL) {
return false;
}
return !(routingObjectID != null ? !DBIDUtil.equal(routingObjectID, that.routingObjectID) : that.routingObjectID != null);
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/MTreeEntry.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/MTreeEntry.java
index f6969b92..66628087 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/MTreeEntry.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/MTreeEntry.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -24,16 +24,14 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants;
*/
import de.lmu.ifi.dbs.elki.database.ids.DBID;
-import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
import de.lmu.ifi.dbs.elki.index.tree.Entry;
/**
* Defines the requirements for an entry in an M-Tree node.
*
* @author Elke Achtert
- * @param <D> the type of Distance used in the M-Tree
*/
-public interface MTreeEntry<D extends Distance<D>> extends Entry {
+public interface MTreeEntry extends Entry {
/**
* Returns the id of the underlying database object of this entry, if this
* entry is a leaf entry, the id of the routing object, otherwise.
@@ -57,14 +55,14 @@ public interface MTreeEntry<D extends Distance<D>> extends Entry {
*
* @return the distance from the object to its parent object
*/
- D getParentDistance();
+ double getParentDistance();
/**
* Sets the distance from the routing object to routing object of its parent.
*
* @param parentDistance the distance to be set
*/
- void setParentDistance(D parentDistance);
+ void setParentDistance(double parentDistance);
/**
* Returns the covering radius if this entry is a directory entry, null
@@ -72,7 +70,7 @@ public interface MTreeEntry<D extends Distance<D>> extends Entry {
*
* @return the covering radius of this entry
*/
- D getCoveringRadius();
+ double getCoveringRadius();
/**
* Sets the covering radius of this entry if this entry is a directory entry,
@@ -80,5 +78,5 @@ public interface MTreeEntry<D extends Distance<D>> extends Entry {
*
* @param coveringRadius the covering radius to be set
*/
- void setCoveringRadius(D coveringRadius);
+ void setCoveringRadius(double coveringRadius);
}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/MTreeLeafEntry.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/MTreeLeafEntry.java
index 27fbc1ba..cfb22bac 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/MTreeLeafEntry.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/MTreeLeafEntry.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -28,7 +28,6 @@ import java.io.ObjectInput;
import java.io.ObjectOutput;
import de.lmu.ifi.dbs.elki.database.ids.DBID;
-import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
import de.lmu.ifi.dbs.elki.index.tree.AbstractLeafEntry;
/**
@@ -38,16 +37,18 @@ import de.lmu.ifi.dbs.elki.index.tree.AbstractLeafEntry;
* M-Tree.
*
* @author Elke Achtert
- * @param <D> the type of Distance used in the M-Tree
*/
-public class MTreeLeafEntry<D extends Distance<D>> extends AbstractLeafEntry implements MTreeEntry<D> {
- private static final long serialVersionUID = 1;
+public class MTreeLeafEntry extends AbstractLeafEntry implements MTreeEntry {
+ /**
+ * Serialization version ID.
+ */
+ private static final long serialVersionUID = 2;
/**
* The distance from the underlying data object to its parent's routing
* object.
*/
- private D parentDistance;
+ private double parentDistance;
/**
* Empty constructor for serialization purposes.
@@ -63,7 +64,7 @@ public class MTreeLeafEntry<D extends Distance<D>> extends AbstractLeafEntry imp
* @param parentDistance the distance from the underlying data object to its
* parent's routing object
*/
- public MTreeLeafEntry(DBID objectID, D parentDistance) {
+ public MTreeLeafEntry(DBID objectID, double parentDistance) {
super(objectID);
this.parentDistance = parentDistance;
}
@@ -87,7 +88,6 @@ public class MTreeLeafEntry<D extends Distance<D>> extends AbstractLeafEntry imp
@Override
public final void setRoutingObjectID(DBID objectID) {
throw new UnsupportedOperationException("Leaf entries should not be assigned a routing object.");
- // super.setEntryID(objectID.getIntegerID());
}
/**
@@ -98,7 +98,7 @@ public class MTreeLeafEntry<D extends Distance<D>> extends AbstractLeafEntry imp
* routing object
*/
@Override
- public final D getParentDistance() {
+ public final double getParentDistance() {
return parentDistance;
}
@@ -109,18 +109,18 @@ public class MTreeLeafEntry<D extends Distance<D>> extends AbstractLeafEntry imp
* @param parentDistance the distance to be set
*/
@Override
- public final void setParentDistance(D parentDistance) {
+ public final void setParentDistance(double parentDistance) {
this.parentDistance = parentDistance;
}
/**
- * Returns null, since a leaf entry has no covering radius.
+ * Returns zero, since a leaf entry has no covering radius.
*
- * @return null
+ * @return Zero
*/
@Override
- public D getCoveringRadius() {
- return null;
+ public double getCoveringRadius() {
+ return 0.0;
}
/**
@@ -131,7 +131,7 @@ public class MTreeLeafEntry<D extends Distance<D>> extends AbstractLeafEntry imp
* radius
*/
@Override
- public void setCoveringRadius(D coveringRadius) {
+ public void setCoveringRadius(double coveringRadius) {
throw new UnsupportedOperationException("This entry is not a directory entry!");
}
@@ -142,18 +142,17 @@ public class MTreeLeafEntry<D extends Distance<D>> extends AbstractLeafEntry imp
@Override
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
- out.writeObject(parentDistance);
+ out.writeDouble(parentDistance);
}
/**
* Calls the super method and reads the parentDistance of this entry from the
* specified input stream.
*/
- @SuppressWarnings("unchecked")
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
- this.parentDistance = (D) in.readObject();
+ this.parentDistance = in.readDouble();
}
/**
@@ -164,20 +163,19 @@ public class MTreeLeafEntry<D extends Distance<D>> extends AbstractLeafEntry imp
* and has the same parentDistance as this entry.
*/
@Override
- @SuppressWarnings("unchecked")
public boolean equals(Object o) {
- if(this == o) {
+ if (this == o) {
return true;
}
- if(o == null || getClass() != o.getClass()) {
+ if (o == null || getClass() != o.getClass()) {
return false;
}
- if(!super.equals(o)) {
+ if (!super.equals(o)) {
return false;
}
- final MTreeLeafEntry<D> that = (MTreeLeafEntry<D>) o;
+ final MTreeLeafEntry that = (MTreeLeafEntry) o;
- return !(parentDistance != null ? !parentDistance.equals(that.parentDistance) : that.parentDistance != null);
+ return Math.abs(parentDistance - that.parentDistance) < Double.MIN_NORMAL;
}
-} \ No newline at end of file
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/MTreeSettings.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/MTreeSettings.java
new file mode 100644
index 00000000..59f6e598
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/MTreeSettings.java
@@ -0,0 +1,56 @@
+package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants;
+
+/*
+ This file is part of ELKI:
+ Environment for Developing KDD-Applications Supported by Index-Structures
+
+ Copyright (C) 2013
+ Ludwig-Maximilians-Universität München
+ Lehr- und Forschungseinheit für Datenbanksysteme
+ ELKI Development Team
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import de.lmu.ifi.dbs.elki.distance.distancefunction.DistanceFunction;
+import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.strategies.insert.MTreeInsert;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.strategies.split.MTreeSplit;
+
+/**
+ * Class to store the MTree settings.
+ *
+ * @author Erich Schubert
+ *
+ * @param <O> Object type
+ * @param <D> Distance type
+ * @param <N> Node type
+ * @param <E> Entry type
+ */
+public class MTreeSettings<O, D extends NumberDistance<D, ?>, N extends AbstractMTreeNode<O, D, N, E>, E extends MTreeEntry> {
+ /**
+ * Holds the instance of the trees distance function.
+ */
+ protected DistanceFunction<? super O, D> distanceFunction;
+
+ /**
+ * Splitting strategy.
+ */
+ protected MTreeSplit<O, D, N, E> splitStrategy;
+
+ /**
+ * Insertion strategy.
+ */
+ protected MTreeInsert<O, D, N, E> insertStrategy;
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/AbstractMkTree.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/AbstractMkTree.java
index f3c440b5..aec4410e 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/AbstractMkTree.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/AbstractMkTree.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -31,15 +31,16 @@ import de.lmu.ifi.dbs.elki.database.ids.DBIDIter;
import de.lmu.ifi.dbs.elki.database.ids.DBIDRef;
import de.lmu.ifi.dbs.elki.database.ids.DBIDUtil;
import de.lmu.ifi.dbs.elki.database.ids.DBIDs;
+import de.lmu.ifi.dbs.elki.database.ids.distance.DistanceDBIDList;
+import de.lmu.ifi.dbs.elki.database.ids.distance.KNNList;
import de.lmu.ifi.dbs.elki.database.query.distance.DistanceQuery;
import de.lmu.ifi.dbs.elki.database.query.knn.KNNQuery;
-import de.lmu.ifi.dbs.elki.distance.distancefunction.DistanceFunction;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.DistanceDBIDResult;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.KNNResult;
-import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
+import de.lmu.ifi.dbs.elki.database.relation.Relation;
+import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTree;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTreeNode;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeEntry;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeSettings;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.query.MTreeQueryUtil;
import de.lmu.ifi.dbs.elki.persistent.PageFile;
@@ -53,25 +54,42 @@ import de.lmu.ifi.dbs.elki.persistent.PageFile;
* @param <D> the type of Distance used in the metrical index
* @param <N> the type of MetricalNode used in the metrical index
* @param <E> the type of MetricalEntry used in the metrical index
+ * @param <S> the type of Settings kept.
*/
-public abstract class AbstractMkTree<O, D extends Distance<D>, N extends AbstractMTreeNode<O, D, N, E>, E extends MTreeEntry<D>> extends AbstractMTree<O, D, N, E> {
+public abstract class AbstractMkTree<O, D extends NumberDistance<D, ?>, N extends AbstractMTreeNode<O, D, N, E>, E extends MTreeEntry, S extends MTreeSettings<O, D, N, E>> extends AbstractMTree<O, D, N, E, S> {
/**
* Internal class for performing knn queries
*/
protected KNNQuery<O, D> knnq;
/**
+ * Distance query to use.
+ */
+ private DistanceQuery<O, D> distanceQuery;
+
+ /**
* Constructor.
*
+ * @param relation Relation to index
* @param pagefile Page file
- * @param distanceQuery Distance query
- * @param distanceFunction Distance function
+ * @param settings Settings class
*/
- public AbstractMkTree(PageFile<N> pagefile, DistanceQuery<O, D> distanceQuery, DistanceFunction<O, D> distanceFunction) {
- super(pagefile, distanceQuery, distanceFunction);
+ public AbstractMkTree(Relation<O> relation, PageFile<N> pagefile, S settings) {
+ super(pagefile, settings);
+ // TODO: any way to un-tie MkTrees from relations?
+ this.distanceQuery = getDistanceFunction().instantiate(relation);
this.knnq = MTreeQueryUtil.getKNNQuery(this, distanceQuery);
}
+ @Override
+ public D distance(DBIDRef id1, DBIDRef id2) {
+ if (id1 == null || id2 == null) {
+ return getDistanceFactory().undefinedDistance();
+ }
+ statistics.countDistanceCalculation();
+ return distanceQuery.distance(id1, id2);
+ }
+
/**
* Performs a reverse k-nearest neighbor query for the given object ID. The
* query result is in ascending order to the distance to the query object.
@@ -80,7 +98,7 @@ public abstract class AbstractMkTree<O, D extends Distance<D>, N extends Abstrac
* @param k the number of nearest neighbors to be returned
* @return a List of the query results
*/
- public abstract DistanceDBIDResult<D> reverseKNNQuery(final DBIDRef id, int k);
+ public abstract DistanceDBIDList<D> reverseKNNQuery(final DBIDRef id, int k);
/**
* Performs a batch k-nearest neighbor query for a list of query objects.
@@ -93,8 +111,8 @@ public abstract class AbstractMkTree<O, D extends Distance<D>, N extends Abstrac
* @deprecated Change to use by-object NN lookups instead.
*/
@Deprecated
- protected final Map<DBID, KNNResult<D>> batchNN(N node, DBIDs ids, int kmax) {
- Map<DBID, KNNResult<D>> res = new HashMap<DBID, KNNResult<D>>(ids.size());
+ protected final Map<DBID, KNNList<D>> batchNN(N node, DBIDs ids, int kmax) {
+ Map<DBID, KNNList<D>> res = new HashMap<>(ids.size());
for (DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) {
DBID id = DBIDUtil.deref(iter);
res.put(id, knnq.getKNNForDBID(id, kmax));
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/AbstractMkTreeUnified.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/AbstractMkTreeUnified.java
index 34507479..455d372a 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/AbstractMkTreeUnified.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/AbstractMkTreeUnified.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -29,10 +29,9 @@ import java.util.Map;
import de.lmu.ifi.dbs.elki.database.ids.DBID;
import de.lmu.ifi.dbs.elki.database.ids.DBIDUtil;
import de.lmu.ifi.dbs.elki.database.ids.ModifiableDBIDs;
-import de.lmu.ifi.dbs.elki.database.query.distance.DistanceQuery;
-import de.lmu.ifi.dbs.elki.distance.distancefunction.DistanceFunction;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.KNNResult;
-import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
+import de.lmu.ifi.dbs.elki.database.ids.distance.KNNList;
+import de.lmu.ifi.dbs.elki.database.relation.Relation;
+import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
import de.lmu.ifi.dbs.elki.index.tree.TreeIndexHeader;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTreeNode;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeEntry;
@@ -46,29 +45,24 @@ import de.lmu.ifi.dbs.elki.persistent.PageFile;
* @author Elke Achtert
*
* @apiviz.has MkTreeHeader oneway
+ * @apiviz.composedOf MkTreeSettings
*
* @param <O> the type of DatabaseObject to be stored in the metrical index
* @param <D> the type of Distance used in the metrical index
* @param <N> the type of MetricalNode used in the metrical index
* @param <E> the type of MetricalEntry used in the metrical index
+ * @param <S> the type of Settings used.
*/
-public abstract class AbstractMkTreeUnified<O, D extends Distance<D>, N extends AbstractMTreeNode<O, D, N, E>, E extends MTreeEntry<D>> extends AbstractMkTree<O, D, N, E> {
- /**
- * Holds the maximum value of k to support.
- */
- private int k_max;
-
+public abstract class AbstractMkTreeUnified<O, D extends NumberDistance<D, ?>, N extends AbstractMTreeNode<O, D, N, E>, E extends MTreeEntry, S extends MkTreeSettings<O, D, N, E>> extends AbstractMkTree<O, D, N, E, S> {
/**
* Constructor.
*
+ * @param relation Relation to index
* @param pagefile Page file
- * @param distanceQuery Distance query
- * @param distanceFunction Distance function
- * @param k_max Maximum value for k
+ * @param settings Settings file
*/
- public AbstractMkTreeUnified(PageFile<N> pagefile, DistanceQuery<O, D> distanceQuery, DistanceFunction<O, D> distanceFunction, int k_max) {
- super(pagefile, distanceQuery, distanceFunction);
- this.k_max = k_max;
+ public AbstractMkTreeUnified(Relation<O> relation, PageFile<N> pagefile, S settings) {
+ super(relation, pagefile, settings);
}
/**
@@ -76,7 +70,7 @@ public abstract class AbstractMkTreeUnified<O, D extends Distance<D>, N extends
*/
@Override
protected TreeIndexHeader createHeader() {
- return new MkTreeHeader(getPageSize(), dirCapacity, leafCapacity, k_max);
+ return new MkTreeHeader(getPageSize(), dirCapacity, leafCapacity, settings.k_max);
}
@Override
@@ -98,7 +92,7 @@ public abstract class AbstractMkTreeUnified<O, D extends Distance<D>, N extends
}
// do batch nn
- Map<DBID, KNNResult<D>> knnLists = batchNN(getRoot(), ids, k_max);
+ Map<DBID, KNNList<D>> knnLists = batchNN(getRoot(), ids, settings.k_max);
// adjust the knn distances
kNNdistanceAdjustment(getRootEntry(), knnLists);
@@ -114,7 +108,7 @@ public abstract class AbstractMkTreeUnified<O, D extends Distance<D>, N extends
* @param entry the root entry of the current subtree
* @param knnLists a map of knn lists for each leaf entry
*/
- protected abstract void kNNdistanceAdjustment(E entry, Map<DBID, KNNResult<D>> knnLists);
+ protected abstract void kNNdistanceAdjustment(E entry, Map<DBID, KNNList<D>> knnLists);
/**
* Get the value of k_max.
@@ -122,6 +116,6 @@ public abstract class AbstractMkTreeUnified<O, D extends Distance<D>, N extends
* @return k_max value.
*/
public int getKmax() {
- return k_max;
+ return settings.k_max;
}
}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/AbstractMkTreeUnifiedFactory.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/AbstractMkTreeUnifiedFactory.java
index 9570995d..fe408035 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/AbstractMkTreeUnifiedFactory.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/AbstractMkTreeUnifiedFactory.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -23,12 +23,12 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees;
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-import de.lmu.ifi.dbs.elki.distance.distancefunction.DistanceFunction;
-import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
+import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
import de.lmu.ifi.dbs.elki.index.Index;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTreeFactory;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTreeNode;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeEntry;
+import de.lmu.ifi.dbs.elki.persistent.PageFileFactory;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.constraints.GreaterConstraint;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization;
@@ -36,44 +36,27 @@ import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.IntParameter;
/**
* Abstract factory for various Mk-Trees
+ *
* @author Erich Schubert
*
* @apiviz.stereotype factory
- * @apiviz.uses AbstractMkTree oneway - - «create»
- *
+ * @apiviz.uses AbstractMkTreeUnified oneway - - «create»
+ *
* @param <O> Object type
* @param <D> Distance type
* @param <N> Node type
* @param <E> Entry type
* @param <I> Index type
*/
-public abstract class AbstractMkTreeUnifiedFactory<O, D extends Distance<D>, N extends AbstractMTreeNode<O, D, N, E>, E extends MTreeEntry<D>, I extends AbstractMkTree<O, D, N, E> & Index> extends AbstractMTreeFactory<O, D, N, E, I> {
- /**
- * Parameter specifying the maximal number k of reverse k nearest neighbors to
- * be supported, must be an integer greater than 0.
- * <p>
- * Key: {@code -mktree.kmax}
- * </p>
- */
- public static final OptionID K_MAX_ID = new OptionID("mktree.kmax", "Specifies the maximal number k of reverse k nearest neighbors to be supported.");
-
- /**
- * Holds the value of parameter {@link #K_MAX_ID}.
- */
- protected int k_max;
-
+public abstract class AbstractMkTreeUnifiedFactory<O, D extends NumberDistance<D, ?>, N extends AbstractMTreeNode<O, D, N, E>, E extends MTreeEntry, I extends AbstractMkTree<O, D, N, E, S> & Index, S extends MkTreeSettings<O, D, N, E>> extends AbstractMTreeFactory<O, D, N, E, I, S> {
/**
* Constructor.
- *
- * @param fileName
- * @param pageSize
- * @param cacheSize
- * @param distanceFunction
- * @param k_max
+ *
+ * @param pageFileFactory Data storage
+ * @param settings Tree settings
*/
- public AbstractMkTreeUnifiedFactory(String fileName, int pageSize, long cacheSize, DistanceFunction<O, D> distanceFunction, int k_max) {
- super(fileName, pageSize, cacheSize, distanceFunction);
- this.k_max = k_max;
+ public AbstractMkTreeUnifiedFactory(PageFileFactory<?> pageFileFactory, S settings) {
+ super(pageFileFactory, settings);
}
/**
@@ -83,8 +66,15 @@ public abstract class AbstractMkTreeUnifiedFactory<O, D extends Distance<D>, N e
*
* @apiviz.exclude
*/
- public abstract static class Parameterizer<O, D extends Distance<D>> extends AbstractMTreeFactory.Parameterizer<O, D> {
- protected int k_max;
+ public abstract static class Parameterizer<O, D extends NumberDistance<D, ?>, N extends AbstractMTreeNode<O, D, N, E>, E extends MTreeEntry, S extends MkTreeSettings<O, D, N, E>> extends AbstractMTreeFactory.Parameterizer<O, D, N, E, S> {
+ /**
+ * Parameter specifying the maximal number k of reverse k nearest neighbors
+ * to be supported, must be an integer greater than 0.
+ * <p>
+ * Key: {@code -mktree.kmax}
+ * </p>
+ */
+ public static final OptionID K_MAX_ID = new OptionID("mktree.kmax", "Specifies the maximal number k of reverse k nearest neighbors to be supported.");
@Override
protected void makeOptions(Parameterization config) {
@@ -93,11 +83,11 @@ public abstract class AbstractMkTreeUnifiedFactory<O, D extends Distance<D>, N e
k_maxP.addConstraint(new GreaterConstraint(0));
if (config.grab(k_maxP)) {
- k_max = k_maxP.getValue();
+ settings.k_max = k_maxP.getValue();
}
}
@Override
- protected abstract AbstractMkTreeUnifiedFactory<O, D, ?, ?, ?> makeInstance();
+ protected abstract AbstractMkTreeUnifiedFactory<O, D, N, E, ?, S> makeInstance();
}
-} \ No newline at end of file
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/MkTreeHeader.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/MkTreeHeader.java
index c067a86c..ff49d789 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/MkTreeHeader.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/MkTreeHeader.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -23,11 +23,11 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees;
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-import de.lmu.ifi.dbs.elki.index.tree.TreeIndexHeader;
-
import java.io.IOException;
import java.io.RandomAccessFile;
+import de.lmu.ifi.dbs.elki.index.tree.TreeIndexHeader;
+
/**
* Encapsulates the header information for subclasses of
* {@link de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.AbstractMkTreeUnified}.
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/MkTreeSettings.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/MkTreeSettings.java
new file mode 100644
index 00000000..6a957bd7
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/MkTreeSettings.java
@@ -0,0 +1,46 @@
+package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees;
+
+/*
+ This file is part of ELKI:
+ Environment for Developing KDD-Applications Supported by Index-Structures
+
+ Copyright (C) 2013
+ Ludwig-Maximilians-Universität München
+ Lehr- und Forschungseinheit für Datenbanksysteme
+ ELKI Development Team
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTreeNode;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeEntry;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeSettings;
+
+/**
+ * Class with settings for MkTrees.
+ *
+ * @author Erich Schubert
+ *
+ * @param <O> Object type
+ * @param <D> Distance type
+ * @param <N> Node type
+ * @param <E> Entry type
+ */
+public class MkTreeSettings<O, D extends NumberDistance<D, ?>, N extends AbstractMTreeNode<O, D, N, E>, E extends MTreeEntry> extends MTreeSettings<O, D, N, E> {
+ /**
+ * Holds the maximum value of k to support.
+ */
+ public int k_max;
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppDirectoryEntry.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppDirectoryEntry.java
index ce7cf104..fd6f6bab 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppDirectoryEntry.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppDirectoryEntry.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mkapp;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -28,7 +28,6 @@ import java.io.ObjectInput;
import java.io.ObjectOutput;
import de.lmu.ifi.dbs.elki.database.ids.DBID;
-import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeDirectoryEntry;
/**
@@ -38,11 +37,11 @@ import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeDirectoryEntry
*
* @author Elke Achtert
*/
-class MkAppDirectoryEntry<D extends NumberDistance<D, ?>> extends MTreeDirectoryEntry<D> implements MkAppEntry<D> {
+class MkAppDirectoryEntry extends MTreeDirectoryEntry implements MkAppEntry {
/**
* Serial version UID
- */
- private static final long serialVersionUID = 1;
+ */
+ private static final long serialVersionUID = 2;
/**
* The polynomial approximation.
@@ -65,7 +64,7 @@ class MkAppDirectoryEntry<D extends NumberDistance<D, ?>> extends MTreeDirectory
* @param coveringRadius the covering radius of the entry
* @param approximation the polynomial approximation of the knn distances
*/
- public MkAppDirectoryEntry(DBID objectID, D parentDistance, Integer nodeID, D coveringRadius, PolynomialApproximation approximation) {
+ public MkAppDirectoryEntry(DBID objectID, double parentDistance, Integer nodeID, double coveringRadius, PolynomialApproximation approximation) {
super(objectID, parentDistance, nodeID, coveringRadius);
this.approximation = approximation;
}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppEntry.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppEntry.java
index b6eabf7e..5424f6f1 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppEntry.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppEntry.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mkapp;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -23,7 +23,6 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mkapp;
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeEntry;
/**
@@ -35,7 +34,7 @@ import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeEntry;
*
* @apiviz.composedOf PolynomialApproximation
*/
-interface MkAppEntry<D extends NumberDistance<D, ?>> extends MTreeEntry<D> {
+interface MkAppEntry extends MTreeEntry {
/**
* Returns the approximated value at the specified k.
*
@@ -57,4 +56,4 @@ interface MkAppEntry<D extends NumberDistance<D, ?>> extends MTreeEntry<D> {
* @param approximation the polynomial approximation to be set
*/
public void setKnnDistanceApproximation(PolynomialApproximation approximation);
-} \ No newline at end of file
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppLeafEntry.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppLeafEntry.java
index 4dbf0244..e1f2305a 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppLeafEntry.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppLeafEntry.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mkapp;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -28,7 +28,6 @@ import java.io.ObjectInput;
import java.io.ObjectOutput;
import de.lmu.ifi.dbs.elki.database.ids.DBID;
-import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeLeafEntry;
/**
@@ -38,11 +37,11 @@ import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeLeafEntry;
*
* @author Elke Achtert
*/
-class MkAppLeafEntry<D extends NumberDistance<D, ?>> extends MTreeLeafEntry<D> implements MkAppEntry<D> {
+class MkAppLeafEntry extends MTreeLeafEntry implements MkAppEntry {
/**
* Serial Version UID
*/
- private static final long serialVersionUID = 1;
+ private static final long serialVersionUID = 2;
/**
* The polynomial approximation.
@@ -64,7 +63,7 @@ class MkAppLeafEntry<D extends NumberDistance<D, ?>> extends MTreeLeafEntry<D> i
* parent's routing object
* @param approximation the polynomial approximation of the knn distances
*/
- public MkAppLeafEntry(DBID objectID, D parentDistance, PolynomialApproximation approximation) {
+ public MkAppLeafEntry(DBID objectID, double parentDistance, PolynomialApproximation approximation) {
super(objectID, parentDistance);
this.approximation = approximation;
}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppTree.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppTree.java
index 51d59e73..1ff0a030 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppTree.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppTree.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mkapp;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -34,18 +34,18 @@ import de.lmu.ifi.dbs.elki.database.ids.DBIDRef;
import de.lmu.ifi.dbs.elki.database.ids.DBIDUtil;
import de.lmu.ifi.dbs.elki.database.ids.DBIDs;
import de.lmu.ifi.dbs.elki.database.ids.ModifiableDBIDs;
-import de.lmu.ifi.dbs.elki.database.query.distance.DistanceQuery;
-import de.lmu.ifi.dbs.elki.distance.distancefunction.DistanceFunction;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.DistanceDBIDResult;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.DistanceDBIDResultIter;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.GenericDistanceDBIDList;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.KNNResult;
+import de.lmu.ifi.dbs.elki.database.ids.distance.DistanceDBIDList;
+import de.lmu.ifi.dbs.elki.database.ids.distance.DistanceDBIDListIter;
+import de.lmu.ifi.dbs.elki.database.ids.distance.KNNList;
+import de.lmu.ifi.dbs.elki.database.ids.generic.GenericDistanceDBIDList;
+import de.lmu.ifi.dbs.elki.database.relation.Relation;
import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
import de.lmu.ifi.dbs.elki.index.tree.LeafEntry;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.AbstractMkTree;
import de.lmu.ifi.dbs.elki.index.tree.query.GenericMTreeDistanceSearchCandidate;
import de.lmu.ifi.dbs.elki.logging.Logging;
import de.lmu.ifi.dbs.elki.math.statistics.PolynomialRegression;
+import de.lmu.ifi.dbs.elki.persistent.ByteArrayUtil;
import de.lmu.ifi.dbs.elki.persistent.PageFile;
import de.lmu.ifi.dbs.elki.utilities.datastructures.heap.Heap;
import de.lmu.ifi.dbs.elki.utilities.datastructures.heap.UpdatableHeap;
@@ -57,54 +57,34 @@ import de.lmu.ifi.dbs.elki.utilities.datastructures.heap.UpdatableHeap;
*
* @author Elke Achtert
*
+ * @apiviz.composedOf MkAppTreeSettings
* @apiviz.has MkAppTreeNode oneway - - contains
*
* @param <O> the type of DatabaseObject to be stored in the metrical index
* @param <D> the type of NumberDistance used in the metrical index
*/
-public class MkAppTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree<O, D, MkAppTreeNode<O, D>, MkAppEntry<D>> {
+public class MkAppTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree<O, D, MkAppTreeNode<O, D>, MkAppEntry, MkAppTreeSettings<O, D>> {
/**
* The logger for this class.
*/
private static final Logging LOG = Logging.getLogger(MkAppTree.class);
/**
- * Parameter k.
- */
- private int k_max;
-
- /**
- * Parameter p.
- */
- private int p;
-
- /**
- * Flag log.
- */
- private boolean log;
-
- /**
* Constructor.
*
+ * @param relation Relation to index
* @param pageFile Page file
- * @param distanceQuery Distance query
- * @param distanceFunction Distance function
- * @param k_max Maximum value of k supported
- * @param p Parameter p
- * @param log Logspace flag
+ * @param settings Tree settings
*/
- public MkAppTree(PageFile<MkAppTreeNode<O, D>> pageFile, DistanceQuery<O, D> distanceQuery, DistanceFunction<O, D> distanceFunction, int k_max, int p, boolean log) {
- super(pageFile, distanceQuery, distanceFunction);
- this.k_max = k_max;
- this.p = p;
- this.log = log;
+ public MkAppTree(Relation<O> relation, PageFile<MkAppTreeNode<O, D>> pageFile, MkAppTreeSettings<O, D> settings) {
+ super(relation, pageFile, settings);
}
/**
* @throws UnsupportedOperationException since this operation is not supported
*/
@Override
- public void insert(MkAppEntry<D> id, boolean withPreInsert) {
+ public void insert(MkAppEntry id, boolean withPreInsert) {
throw new UnsupportedOperationException("Insertion of single objects is not supported!");
}
@@ -112,7 +92,7 @@ public class MkAppTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
* @throws UnsupportedOperationException since this operation is not supported
*/
@Override
- protected void preInsert(MkAppEntry<D> entry) {
+ protected void preInsert(MkAppEntry entry) {
throw new UnsupportedOperationException("Insertion of single objects is not supported!");
}
@@ -122,35 +102,35 @@ public class MkAppTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
* @param entries the entries to be inserted
*/
@Override
- public void insertAll(List<MkAppEntry<D>> entries) {
- if(entries.isEmpty()) {
+ public void insertAll(List<MkAppEntry> entries) {
+ if (entries.isEmpty()) {
return;
}
- if(LOG.isDebugging()) {
+ if (LOG.isDebugging()) {
LOG.debugFine("insert " + entries + "\n");
}
- if(!initialized) {
+ if (!initialized) {
initialize(entries.get(0));
}
ModifiableDBIDs ids = DBIDUtil.newArray(entries.size());
// insert
- for(MkAppEntry<D> entry : entries) {
+ for (MkAppEntry entry : entries) {
ids.add(entry.getRoutingObjectID());
// insert the object
super.insert(entry, false);
}
// do batch nn
- Map<DBID, KNNResult<D>> knnLists = batchNN(getRoot(), ids, k_max + 1);
-
+ Map<DBID, KNNList<D>> knnLists = batchNN(getRoot(), ids, settings.k_max + 1);
+
// adjust the knn distances
adjustApproximatedKNNDistances(getRootEntry(), knnLists);
- if(EXTRA_INTEGRITY_CHECKS) {
+ if (EXTRA_INTEGRITY_CHECKS) {
getRoot().integrityCheck(this, getRootEntry());
}
}
@@ -164,50 +144,49 @@ public class MkAppTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
* @return a List of the query results
*/
@Override
- public DistanceDBIDResult<D> reverseKNNQuery(DBIDRef id, int k) {
- GenericDistanceDBIDList<D> result = new GenericDistanceDBIDList<D>();
- final Heap<GenericMTreeDistanceSearchCandidate<D>> pq = new UpdatableHeap<GenericMTreeDistanceSearchCandidate<D>>();
+ public DistanceDBIDList<D> reverseKNNQuery(DBIDRef id, int k) {
+ GenericDistanceDBIDList<D> result = new GenericDistanceDBIDList<>();
+ final Heap<GenericMTreeDistanceSearchCandidate> pq = new UpdatableHeap<>();
// push root
- pq.add(new GenericMTreeDistanceSearchCandidate<D>(getDistanceQuery().nullDistance(), getRootID(), null, null));
+ pq.add(new GenericMTreeDistanceSearchCandidate(0., getRootID(), null));
// search in tree
- while(!pq.isEmpty()) {
- GenericMTreeDistanceSearchCandidate<D> pqNode = pq.poll();
+ while (!pq.isEmpty()) {
+ GenericMTreeDistanceSearchCandidate pqNode = pq.poll();
// FIXME: cache the distance to the routing object in the queue node!
MkAppTreeNode<O, D> node = getNode(pqNode.nodeID);
// directory node
- if(!node.isLeaf()) {
- for(int i = 0; i < node.getNumEntries(); i++) {
- MkAppEntry<D> entry = node.getEntry(i);
- D distance = getDistanceQuery().distance(entry.getRoutingObjectID(), id);
- D minDist = entry.getCoveringRadius().compareTo(distance) > 0 ? getDistanceQuery().nullDistance() : distance.minus(entry.getCoveringRadius());
-
- double approxValue = log ? Math.exp(entry.approximatedValueAt(k)) : entry.approximatedValueAt(k);
- if(approxValue < 0) {
+ if (!node.isLeaf()) {
+ for (int i = 0; i < node.getNumEntries(); i++) {
+ MkAppEntry entry = node.getEntry(i);
+ double distance = distance(entry.getRoutingObjectID(), id).doubleValue();
+ double minDist = (entry.getCoveringRadius() > distance) ? 0. : distance - entry.getCoveringRadius();
+
+ double approxValue = settings.log ? Math.exp(entry.approximatedValueAt(k)) : entry.approximatedValueAt(k);
+ if (approxValue < 0) {
approxValue = 0;
}
- D approximatedKnnDist = getDistanceQuery().getDistanceFactory().fromDouble(approxValue);
- if(minDist.compareTo(approximatedKnnDist) <= 0) {
- pq.add(new GenericMTreeDistanceSearchCandidate<D>(minDist, getPageID(entry), entry.getRoutingObjectID(), null));
+ if (minDist <= approxValue) {
+ pq.add(new GenericMTreeDistanceSearchCandidate(minDist, getPageID(entry), entry.getRoutingObjectID()));
}
}
}
// data node
else {
- for(int i = 0; i < node.getNumEntries(); i++) {
- MkAppLeafEntry<D> entry = (MkAppLeafEntry<D>) node.getEntry(i);
- D distance = getDistanceQuery().distance(entry.getRoutingObjectID(), id);
- double approxValue = log ? StrictMath.exp(entry.approximatedValueAt(k)) : entry.approximatedValueAt(k);
- if(approxValue < 0) {
+ for (int i = 0; i < node.getNumEntries(); i++) {
+ MkAppLeafEntry entry = (MkAppLeafEntry) node.getEntry(i);
+ D distance = distance(entry.getRoutingObjectID(), id);
+ double approxValue = settings.log ? StrictMath.exp(entry.approximatedValueAt(k)) : entry.approximatedValueAt(k);
+ if (approxValue < 0) {
approxValue = 0;
}
- D approximatedKnnDist = getDistanceQuery().getDistanceFactory().fromDouble(approxValue);
+ D approximatedKnnDist = getDistanceFactory().fromDouble(approxValue);
- if(distance.compareTo(approximatedKnnDist) <= 0) {
+ if (distance.compareTo(approximatedKnnDist) <= 0) {
result.add(distance, entry.getRoutingObjectID());
}
}
@@ -222,69 +201,69 @@ public class MkAppTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
* @return the value of the k_max parameter
*/
public int getK_max() {
- return k_max;
+ return settings.k_max;
}
/**
* Determines the maximum and minimum number of entries in a node.
*/
@Override
- protected void initializeCapacities(MkAppEntry<D> exampleLeaf) {
- int distanceSize = exampleLeaf.getParentDistance().externalizableSize();
+ protected void initializeCapacities(MkAppEntry exampleLeaf) {
+ int distanceSize = ByteArrayUtil.SIZE_DOUBLE; // exampleLeaf.getParentDistance().externalizableSize();
// overhead = index(4), numEntries(4), id(4), isLeaf(0.125)
double overhead = 12.125;
- if(getPageSize() - overhead < 0) {
+ if (getPageSize() - overhead < 0) {
throw new RuntimeException("Node size of " + getPageSize() + " Bytes is chosen too small!");
}
// dirCapacity = (file.getPageSize() - overhead) / (nodeID + objectID +
// coveringRadius + parentDistance + approx) + 1
- dirCapacity = (int) (getPageSize() - overhead) / (4 + 4 + distanceSize + distanceSize + (p + 1) * 4 + 2) + 1;
+ dirCapacity = (int) (getPageSize() - overhead) / (4 + 4 + distanceSize + distanceSize + (settings.p + 1) * 4 + 2) + 1;
- if(dirCapacity <= 1) {
+ if (dirCapacity <= 1) {
throw new RuntimeException("Node size of " + getPageSize() + " Bytes is chosen too small!");
}
- if(dirCapacity < 10) {
+ if (dirCapacity < 10) {
LOG.warning("Page size is choosen too small! Maximum number of entries " + "in a directory node = " + (dirCapacity - 1));
}
// leafCapacity = (file.getPageSize() - overhead) / (objectID +
// parentDistance +
// approx) + 1
- leafCapacity = (int) (getPageSize() - overhead) / (4 + distanceSize + (p + 1) * 4 + 2) + 1;
+ leafCapacity = (int) (getPageSize() - overhead) / (4 + distanceSize + (settings.p + 1) * 4 + 2) + 1;
- if(leafCapacity <= 1) {
+ if (leafCapacity <= 1) {
throw new RuntimeException("Node size of " + getPageSize() + " Bytes is chosen too small!");
}
- if(leafCapacity < 10) {
+ if (leafCapacity < 10) {
LOG.warning("Page size is choosen too small! Maximum number of entries " + "in a leaf node = " + (leafCapacity - 1));
}
initialized = true;
- if(LOG.isVerbose()) {
+ if (LOG.isVerbose()) {
LOG.verbose("Directory Capacity: " + (dirCapacity - 1) + "\nLeaf Capacity: " + (leafCapacity - 1));
}
}
- private List<D> getMeanKNNList(DBIDs ids, Map<DBID, KNNResult<D>> knnLists) {
- double[] means = new double[k_max];
- for(DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) {
+ private List<D> getMeanKNNList(DBIDs ids, Map<DBID, KNNList<D>> knnLists) {
+ double[] means = new double[settings.k_max];
+ for (DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) {
DBID id = DBIDUtil.deref(iter);
- KNNResult<D> knns = knnLists.get(id);
+ KNNList<D> knns = knnLists.get(id);
int k = 0;
- for(DistanceDBIDResultIter<D> it = knns.iter(); k < k_max && it.valid(); it.advance(), k++) {
+ for (DistanceDBIDListIter<D> it = knns.iter(); k < settings.k_max && it.valid(); it.advance(), k++) {
means[k] += it.getDistance().doubleValue();
}
}
- List<D> result = new ArrayList<D>();
- for(int k = 0; k < k_max; k++) {
+ List<D> result = new ArrayList<>();
+ for (int k = 0; k < settings.k_max; k++) {
means[k] /= ids.size();
- result.add(getDistanceQuery().getDistanceFactory().fromDouble(means[k]));
+ result.add(getDistanceFactory().fromDouble(means[k]));
}
return result;
@@ -296,21 +275,20 @@ public class MkAppTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
* @param entry the root entry of the current subtree
* @param knnLists a map of knn lists for each leaf entry
*/
- private void adjustApproximatedKNNDistances(MkAppEntry<D> entry, Map<DBID, KNNResult<D>> knnLists) {
+ private void adjustApproximatedKNNDistances(MkAppEntry entry, Map<DBID, KNNList<D>> knnLists) {
MkAppTreeNode<O, D> node = getNode(entry);
- if(node.isLeaf()) {
- for(int i = 0; i < node.getNumEntries(); i++) {
- MkAppLeafEntry<D> leafEntry = (MkAppLeafEntry<D>) node.getEntry(i);
+ if (node.isLeaf()) {
+ for (int i = 0; i < node.getNumEntries(); i++) {
+ MkAppLeafEntry leafEntry = (MkAppLeafEntry) node.getEntry(i);
// approximateKnnDistances(leafEntry,
// getKNNList(leafEntry.getRoutingObjectID(), knnLists));
PolynomialApproximation approx = approximateKnnDistances(getMeanKNNList(leafEntry.getDBID(), knnLists));
leafEntry.setKnnDistanceApproximation(approx);
}
- }
- else {
- for(int i = 0; i < node.getNumEntries(); i++) {
- MkAppEntry<D> dirEntry = node.getEntry(i);
+ } else {
+ for (int i = 0; i < node.getNumEntries(); i++) {
+ MkAppEntry dirEntry = node.getEntry(i);
adjustApproximatedKNNDistances(dirEntry, knnLists);
}
}
@@ -330,14 +308,13 @@ public class MkAppTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
* in the specified subtree
*/
private void leafEntryIDs(MkAppTreeNode<O, D> node, ModifiableDBIDs result) {
- if(node.isLeaf()) {
- for(int i = 0; i < node.getNumEntries(); i++) {
- MkAppEntry<D> entry = node.getEntry(i);
+ if (node.isLeaf()) {
+ for (int i = 0; i < node.getNumEntries(); i++) {
+ MkAppEntry entry = node.getEntry(i);
result.add(((LeafEntry) entry).getDBID());
}
- }
- else {
- for(int i = 0; i < node.getNumEntries(); i++) {
+ } else {
+ for (int i = 0; i < node.getNumEntries(); i++) {
MkAppTreeNode<O, D> childNode = getNode(node.getEntry(i));
leafEntryIDs(childNode, result);
}
@@ -355,36 +332,34 @@ public class MkAppTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
// count the zero distances (necessary of log-log space is used)
int k_0 = 0;
- if(log) {
- for(int i = 0; i < k_max; i++) {
+ if (settings.log) {
+ for (int i = 0; i < settings.k_max; i++) {
double dist = knnDistances.get(i).doubleValue();
- if(dist == 0) {
+ if (dist == 0) {
k_0++;
- }
- else {
+ } else {
break;
}
}
}
- de.lmu.ifi.dbs.elki.math.linearalgebra.Vector x = new de.lmu.ifi.dbs.elki.math.linearalgebra.Vector(k_max - k_0);
- de.lmu.ifi.dbs.elki.math.linearalgebra.Vector y = new de.lmu.ifi.dbs.elki.math.linearalgebra.Vector(k_max - k_0);
+ de.lmu.ifi.dbs.elki.math.linearalgebra.Vector x = new de.lmu.ifi.dbs.elki.math.linearalgebra.Vector(settings.k_max - k_0);
+ de.lmu.ifi.dbs.elki.math.linearalgebra.Vector y = new de.lmu.ifi.dbs.elki.math.linearalgebra.Vector(settings.k_max - k_0);
- for(int k = 0; k < k_max - k_0; k++) {
- if(log) {
+ for (int k = 0; k < settings.k_max - k_0; k++) {
+ if (settings.log) {
x.set(k, Math.log(k + k_0));
y.set(k, Math.log(knnDistances.get(k + k_0).doubleValue()));
- }
- else {
+ } else {
x.set(k, k + k_0);
y.set(k, knnDistances.get(k + k_0).doubleValue());
}
}
- PolynomialRegression regression = new PolynomialRegression(y, x, p);
+ PolynomialRegression regression = new PolynomialRegression(y, x, settings.p);
PolynomialApproximation approximation = new PolynomialApproximation(regression.getEstimatedCoefficients().getArrayCopy());
- if(LOG.isDebugging()) {
+ if (LOG.isDebugging()) {
msg.append("approximation ").append(approximation);
LOG.debugFine(msg.toString());
}
@@ -399,7 +374,7 @@ public class MkAppTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
*/
@Override
protected MkAppTreeNode<O, D> createNewLeafNode() {
- return new MkAppTreeNode<O, D>(leafCapacity, true);
+ return new MkAppTreeNode<>(leafCapacity, true);
}
/**
@@ -409,7 +384,7 @@ public class MkAppTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
*/
@Override
protected MkAppTreeNode<O, D> createNewDirectoryNode() {
- return new MkAppTreeNode<O, D>(dirCapacity, false);
+ return new MkAppTreeNode<>(dirCapacity, false);
}
/**
@@ -421,8 +396,8 @@ public class MkAppTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
* the routing object of the parent node
*/
@Override
- protected MkAppEntry<D> createNewDirectoryEntry(MkAppTreeNode<O, D> node, DBID routingObjectID, D parentDistance) {
- return new MkAppDirectoryEntry<D>(routingObjectID, parentDistance, node.getPageID(), node.coveringRadius(routingObjectID, this), null);
+ protected MkAppEntry createNewDirectoryEntry(MkAppTreeNode<O, D> node, DBID routingObjectID, double parentDistance) {
+ return new MkAppDirectoryEntry(routingObjectID, parentDistance, node.getPageID(), node.coveringRadius(routingObjectID, this), null);
}
/**
@@ -431,12 +406,12 @@ public class MkAppTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
* @return an entry representing the root node
*/
@Override
- protected MkAppEntry<D> createRootEntry() {
- return new MkAppDirectoryEntry<D>(null, null, 0, null, null);
+ protected MkAppEntry createRootEntry() {
+ return new MkAppDirectoryEntry(null, 0., 0, 0., null);
}
@Override
protected Logging getLogger() {
return LOG;
}
-} \ No newline at end of file
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppTreeFactory.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppTreeFactory.java
index c0f12895..45a2e85f 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppTreeFactory.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppTreeFactory.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mkapp;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -24,10 +24,10 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mkapp;
*/
import de.lmu.ifi.dbs.elki.database.relation.Relation;
-import de.lmu.ifi.dbs.elki.distance.distancefunction.DistanceFunction;
import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTreeFactory;
import de.lmu.ifi.dbs.elki.persistent.PageFile;
+import de.lmu.ifi.dbs.elki.persistent.PageFileFactory;
import de.lmu.ifi.dbs.elki.utilities.ClassGenericsUtil;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.constraints.GreaterConstraint;
@@ -46,7 +46,7 @@ import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.IntParameter;
* @param <O> Object type
* @param <D> Distance type
*/
-public class MkAppTreeFactory<O, D extends NumberDistance<D, ?>> extends AbstractMTreeFactory<O, D, MkAppTreeNode<O, D>, MkAppEntry<D>, MkAppTreeIndex<O, D>> {
+public class MkAppTreeFactory<O, D extends NumberDistance<D, ?>> extends AbstractMTreeFactory<O, D, MkAppTreeNode<O, D>, MkAppEntry, MkAppTreeIndex<O, D>, MkAppTreeSettings<O, D>> {
/**
* Parameter for nolog
*/
@@ -63,42 +63,19 @@ public class MkAppTreeFactory<O, D extends NumberDistance<D, ?>> extends Abstrac
public static final OptionID P_ID = new OptionID("mkapp.p", "positive integer specifying the order of the polynomial approximation.");
/**
- * Parameter k.
- */
- private int k_max;
-
- /**
- * Parameter p.
- */
- private int p;
-
- /**
- * Flag log.
- */
- private boolean log;
-
- /**
* Constructor.
*
- * @param fileName
- * @param pageSize
- * @param cacheSize
- * @param distanceFunction
- * @param k_max
- * @param p
- * @param log
+ * @param pageFileFactory Data storage
+ * @param settings Tree settings
*/
- public MkAppTreeFactory(String fileName, int pageSize, long cacheSize, DistanceFunction<O, D> distanceFunction, int k_max, int p, boolean log) {
- super(fileName, pageSize, cacheSize, distanceFunction);
- this.k_max = k_max;
- this.p = p;
- this.log = log;
+ public MkAppTreeFactory(PageFileFactory<?> pageFileFactory, MkAppTreeSettings<O, D> settings) {
+ super(pageFileFactory, settings);
}
@Override
public MkAppTreeIndex<O, D> instantiate(Relation<O> relation) {
PageFile<MkAppTreeNode<O, D>> pagefile = makePageFile(getNodeClass());
- return new MkAppTreeIndex<O, D>(relation, pagefile, distanceFunction.instantiate(relation), distanceFunction, k_max, p, log);
+ return new MkAppTreeIndex<>(relation, pagefile, settings);
}
protected Class<MkAppTreeNode<O, D>> getNodeClass() {
@@ -112,46 +89,36 @@ public class MkAppTreeFactory<O, D extends NumberDistance<D, ?>> extends Abstrac
*
* @apiviz.exclude
*/
- public static class Parameterizer<O, D extends NumberDistance<D, ?>> extends AbstractMTreeFactory.Parameterizer<O, D> {
- /**
- * Parameter k.
- */
- protected int k_max;
-
- /**
- * Parameter p.
- */
- protected int p;
-
- /**
- * Flag log.
- */
- protected boolean log;
-
+ public static class Parameterizer<O, D extends NumberDistance<D, ?>> extends AbstractMTreeFactory.Parameterizer<O, D, MkAppTreeNode<O, D>, MkAppEntry, MkAppTreeSettings<O, D>> {
@Override
protected void makeOptions(Parameterization config) {
super.makeOptions(config);
IntParameter kP = new IntParameter(K_ID);
kP.addConstraint(new GreaterConstraint(0));
- if(config.grab(kP)) {
- k_max = kP.getValue();
+ if (config.grab(kP)) {
+ settings.k_max = kP.getValue();
}
IntParameter pP = new IntParameter(P_ID);
pP.addConstraint(new GreaterConstraint(0));
- if(config.grab(pP)) {
- p = pP.getValue();
+ if (config.grab(pP)) {
+ settings.p = pP.getValue();
}
Flag nologF = new Flag(NOLOG_ID);
- if(config.grab(nologF)) {
- log = !nologF.getValue();
+ if (config.grab(nologF)) {
+ settings.log = !nologF.getValue();
}
}
@Override
protected MkAppTreeFactory<O, D> makeInstance() {
- return new MkAppTreeFactory<O, D>(fileName, pageSize, cacheSize, distanceFunction, k_max, p, log);
+ return new MkAppTreeFactory<>(pageFileFactory, settings);
+ }
+
+ @Override
+ protected MkAppTreeSettings<O, D> makeSettings() {
+ return new MkAppTreeSettings<>();
}
}
-} \ No newline at end of file
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppTreeIndex.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppTreeIndex.java
index 9776de63..2a630bf0 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppTreeIndex.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppTreeIndex.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mkapp;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -28,9 +28,7 @@ import java.util.List;
import de.lmu.ifi.dbs.elki.database.ids.DBID;
import de.lmu.ifi.dbs.elki.database.ids.DBIDIter;
-import de.lmu.ifi.dbs.elki.database.ids.DBIDRef;
import de.lmu.ifi.dbs.elki.database.ids.DBIDUtil;
-import de.lmu.ifi.dbs.elki.database.ids.DBIDs;
import de.lmu.ifi.dbs.elki.database.query.DatabaseQuery;
import de.lmu.ifi.dbs.elki.database.query.distance.DistanceQuery;
import de.lmu.ifi.dbs.elki.database.query.knn.KNNQuery;
@@ -43,12 +41,9 @@ import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
import de.lmu.ifi.dbs.elki.index.KNNIndex;
import de.lmu.ifi.dbs.elki.index.RKNNIndex;
import de.lmu.ifi.dbs.elki.index.RangeIndex;
-import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTree;
-import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.AbstractMkTree;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.query.MTreeQueryUtil;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.query.MkTreeRKNNQuery;
import de.lmu.ifi.dbs.elki.persistent.PageFile;
-import de.lmu.ifi.dbs.elki.utilities.exceptions.ExceptionMessages;
/**
* MkAppTree used as database index.
@@ -69,16 +64,11 @@ public class MkAppTreeIndex<O, D extends NumberDistance<D, ?>> extends MkAppTree
*
* @param relation Relation to index
* @param pageFile Page file
- * @param distanceQuery Distance query
- * @param distanceFunction Distance function
- * @param k_max Maximum value of k supported
- * @param p Parameter p
- * @param log Logspace flag
+ * @param settings Tree settings
*/
- public MkAppTreeIndex(Relation<O> relation, PageFile<MkAppTreeNode<O, D>> pageFile, DistanceQuery<O, D> distanceQuery, DistanceFunction<O, D> distanceFunction, int k_max, int p, boolean log) {
- super(pageFile, distanceQuery, distanceFunction, k_max, p, log);
+ public MkAppTreeIndex(Relation<O> relation, PageFile<MkAppTreeNode<O, D>> pageFile, MkAppTreeSettings<O, D> settings) {
+ super(relation, pageFile, settings);
this.relation = relation;
- this.initialize();
}
/**
@@ -89,119 +79,88 @@ public class MkAppTreeIndex<O, D extends NumberDistance<D, ?>> extends MkAppTree
* @param parentDistance the distance from the object to the routing object of
* the parent node
*/
- protected MkAppEntry<D> createNewLeafEntry(DBID id, O object, D parentDistance) {
- return new MkAppLeafEntry<D>(id, parentDistance, null);
+ protected MkAppEntry createNewLeafEntry(DBID id, O object, double parentDistance) {
+ return new MkAppLeafEntry(id, parentDistance, null);
}
@Override
- public void insert(DBIDRef id) {
- throw new UnsupportedOperationException("Insertion of single objects is not supported!");
- }
-
- @Override
- public void insertAll(DBIDs ids) {
- List<MkAppEntry<D>> objs = new ArrayList<MkAppEntry<D>>(ids.size());
- for (DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) {
+ public void initialize() {
+ super.initialize();
+ List<MkAppEntry> objs = new ArrayList<>(relation.size());
+ for (DBIDIter iter = relation.iterDBIDs(); iter.valid(); iter.advance()) {
DBID id = DBIDUtil.deref(iter);
final O object = relation.get(id);
- objs.add(createNewLeafEntry(id, object, getDistanceFactory().undefinedDistance()));
+ objs.add(createNewLeafEntry(id, object, Double.NaN));
}
insertAll(objs);
}
- /**
- * Throws an UnsupportedOperationException since deletion of objects is not
- * yet supported by an M-Tree.
- *
- * @throws UnsupportedOperationException thrown, since deletions aren't
- * implemented yet.
- */
- @Override
- public final boolean delete(DBIDRef id) {
- throw new UnsupportedOperationException(ExceptionMessages.UNSUPPORTED_NOT_YET);
- }
-
- /**
- * Throws an UnsupportedOperationException since deletion of objects is not
- * yet supported by an M-Tree.
- *
- * @throws UnsupportedOperationException thrown, since deletions aren't
- * implemented yet.
- */
- @Override
- public void deleteAll(DBIDs ids) {
- throw new UnsupportedOperationException(ExceptionMessages.UNSUPPORTED_NOT_YET);
- }
-
@SuppressWarnings("unchecked")
@Override
public <S extends Distance<S>> KNNQuery<O, S> getKNNQuery(DistanceQuery<O, S> distanceQuery, Object... hints) {
// Query on the relation we index
- if(distanceQuery.getRelation() != relation) {
+ if (distanceQuery.getRelation() != relation) {
return null;
}
- DistanceFunction<? super O, S> distanceFunction = distanceQuery.getDistanceFunction();
- if(!this.distanceFunction.equals(distanceFunction)) {
- if(getLogger().isDebugging()) {
+ DistanceFunction<? super O, D> distanceFunction = (DistanceFunction<? super O, D>) distanceQuery.getDistanceFunction();
+ if (!this.getDistanceFunction().equals(distanceFunction)) {
+ if (getLogger().isDebugging()) {
getLogger().debug("Distance function not supported by index - or 'equals' not implemented right!");
}
return null;
}
// Bulk is not yet supported
- for(Object hint : hints) {
- if(hint == DatabaseQuery.HINT_BULK) {
+ for (Object hint : hints) {
+ if (hint == DatabaseQuery.HINT_BULK) {
return null;
}
}
- AbstractMTree<O, S, ?, ?> idx = (AbstractMTree<O, S, ?, ?>) this;
- DistanceQuery<O, S> dq = distanceFunction.instantiate(relation);
- return MTreeQueryUtil.getKNNQuery(idx, dq, hints);
+ DistanceQuery<O, D> dq = distanceFunction.instantiate(relation);
+ return (KNNQuery<O, S>) MTreeQueryUtil.getKNNQuery(this, dq, hints);
}
@SuppressWarnings("unchecked")
@Override
public <S extends Distance<S>> RangeQuery<O, S> getRangeQuery(DistanceQuery<O, S> distanceQuery, Object... hints) {
// Query on the relation we index
- if(distanceQuery.getRelation() != relation) {
+ if (distanceQuery.getRelation() != relation) {
return null;
}
- DistanceFunction<? super O, S> distanceFunction = distanceQuery.getDistanceFunction();
- if(!this.distanceFunction.equals(distanceFunction)) {
- if(getLogger().isDebugging()) {
+ DistanceFunction<? super O, D> distanceFunction = (DistanceFunction<? super O, D>) distanceQuery.getDistanceFunction();
+ if (!this.getDistanceFunction().equals(distanceFunction)) {
+ if (getLogger().isDebugging()) {
getLogger().debug("Distance function not supported by index - or 'equals' not implemented right!");
}
return null;
}
// Bulk is not yet supported
- for(Object hint : hints) {
- if(hint == DatabaseQuery.HINT_BULK) {
+ for (Object hint : hints) {
+ if (hint == DatabaseQuery.HINT_BULK) {
return null;
}
}
- AbstractMTree<O, S, ?, ?> idx = (AbstractMTree<O, S, ?, ?>) this;
- DistanceQuery<O, S> dq = distanceFunction.instantiate(relation);
- return MTreeQueryUtil.getRangeQuery(idx, dq, hints);
+ DistanceQuery<O, D> dq = distanceFunction.instantiate(relation);
+ return (RangeQuery<O, S>) MTreeQueryUtil.getRangeQuery(this, dq, hints);
}
@SuppressWarnings("unchecked")
@Override
public <S extends Distance<S>> RKNNQuery<O, S> getRKNNQuery(DistanceQuery<O, S> distanceQuery, Object... hints) {
- DistanceFunction<? super O, S> distanceFunction = distanceQuery.getDistanceFunction();
- if(!this.getDistanceFunction().equals(distanceFunction)) {
- if(getLogger().isDebugging()) {
+ DistanceFunction<? super O, D> distanceFunction = (DistanceFunction<? super O, D>) distanceQuery.getDistanceFunction();
+ if (!this.getDistanceFunction().equals(distanceFunction)) {
+ if (getLogger().isDebugging()) {
getLogger().debug("Distance function not supported by index - or 'equals' not implemented right!");
}
return null;
}
// Bulk is not yet supported
- for(Object hint : hints) {
- if(hint == DatabaseQuery.HINT_BULK) {
+ for (Object hint : hints) {
+ if (hint == DatabaseQuery.HINT_BULK) {
return null;
}
}
- AbstractMkTree<O, S, ?, ?> idx = (AbstractMkTree<O, S, ?, ?>) this;
- DistanceQuery<O, S> dq = distanceFunction.instantiate(relation);
- return new MkTreeRKNNQuery<O, S>(idx, dq);
+ DistanceQuery<O, D> dq = distanceFunction.instantiate(relation);
+ return (RKNNQuery<O, S>) new MkTreeRKNNQuery<>(this, dq);
}
@Override
@@ -213,4 +172,4 @@ public class MkAppTreeIndex<O, D extends NumberDistance<D, ?>> extends MkAppTree
public String getShortName() {
return "mkapptree";
}
-} \ No newline at end of file
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppTreeNode.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppTreeNode.java
index c730eb4f..29609274 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppTreeNode.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppTreeNode.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mkapp;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -43,8 +43,8 @@ import de.lmu.ifi.dbs.elki.utilities.FormatUtil;
* @param <O> object type
* @param <D> distance type
*/
-class MkAppTreeNode<O, D extends NumberDistance<D, ?>> extends AbstractMTreeNode<O, D, MkAppTreeNode<O, D>, MkAppEntry<D>> {
- private static final long serialVersionUID = 1;
+class MkAppTreeNode<O, D extends NumberDistance<D, ?>> extends AbstractMTreeNode<O, D, MkAppTreeNode<O, D>, MkAppEntry> {
+ private static final long serialVersionUID = 2;
/**
* Empty constructor for Externalizable interface.
@@ -75,7 +75,7 @@ class MkAppTreeNode<O, D extends NumberDistance<D, ?>> extends AbstractMTreeNode
int p_max = 0;
double[] b = null;
for(int i = 0; i < getNumEntries(); i++) {
- MkAppEntry<D> entry = getEntry(i);
+ MkAppEntry entry = getEntry(i);
PolynomialApproximation approximation = entry.getKnnDistanceApproximation();
if(b == null) {
p_max = approximation.getPolynomialOrder();
@@ -109,16 +109,16 @@ class MkAppTreeNode<O, D extends NumberDistance<D, ?>> extends AbstractMTreeNode
* @param mTree the M-Tree object holding this node
*/
@Override
- public void adjustEntry(MkAppEntry<D> entry, DBID routingObjectID, D parentDistance, AbstractMTree<O, D, MkAppTreeNode<O, D>, MkAppEntry<D>> mTree) {
+ public void adjustEntry(MkAppEntry entry, DBID routingObjectID, double parentDistance, AbstractMTree<O, D, MkAppTreeNode<O, D>, MkAppEntry, ?> mTree) {
super.adjustEntry(entry, routingObjectID, parentDistance, mTree);
// entry.setKnnDistanceApproximation(knnDistanceApproximation());
}
@Override
- protected void integrityCheckParameters(MkAppEntry<D> parentEntry, MkAppTreeNode<O, D> parent, int index, AbstractMTree<O, D, MkAppTreeNode<O, D>, MkAppEntry<D>> mTree) {
+ protected void integrityCheckParameters(MkAppEntry parentEntry, MkAppTreeNode<O, D> parent, int index, AbstractMTree<O, D, MkAppTreeNode<O, D>, MkAppEntry, ?> mTree) {
super.integrityCheckParameters(parentEntry, parent, index, mTree);
- MkAppEntry<D> entry = parent.getEntry(index);
+ MkAppEntry entry = parent.getEntry(index);
PolynomialApproximation approximation_soll = knnDistanceApproximation();
PolynomialApproximation approximation_ist = entry.getKnnDistanceApproximation();
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppTreeSettings.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppTreeSettings.java
new file mode 100644
index 00000000..b9e0b8aa
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppTreeSettings.java
@@ -0,0 +1,47 @@
+package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mkapp;
+
+/*
+ This file is part of ELKI:
+ Environment for Developing KDD-Applications Supported by Index-Structures
+
+ Copyright (C) 2013
+ Ludwig-Maximilians-Universität München
+ Lehr- und Forschungseinheit für Datenbanksysteme
+ ELKI Development Team
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.MkTreeSettings;
+
+/**
+ * Settings class for the MkApp Tree.
+ *
+ * @author Erich Schubert
+ *
+ * @param <O> Object type
+ * @param <D> Distance type
+ */
+public class MkAppTreeSettings<O, D extends NumberDistance<D, ?>> extends MkTreeSettings<O, D, MkAppTreeNode<O, D>, MkAppEntry> {
+ /**
+ * Parameter p.
+ */
+ protected int p;
+
+ /**
+ * Flag log.
+ */
+ protected boolean log;
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/PolynomialApproximation.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/PolynomialApproximation.java
index 2ad3558e..dc28b7c3 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/PolynomialApproximation.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/PolynomialApproximation.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mkapp;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/package-info.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/package-info.java
index 0f3cfde9..7b897fe3 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/package-info.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/package-info.java
@@ -5,7 +5,7 @@
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
-Copyright (C) 2012
+Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/ApproximationLine.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/ApproximationLine.java
index 7f2aa3fe..318c437b 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/ApproximationLine.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/ApproximationLine.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mkcop;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -28,9 +28,6 @@ import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
-import de.lmu.ifi.dbs.elki.database.query.distance.DistanceQuery;
-import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
-
/**
* Provides an approximation for knn-distances line consisting of incline m,
* axes intercept t and a start value for k.
@@ -111,7 +108,7 @@ public class ApproximationLine implements Externalizable {
* @return the function value of the approximation line at the specified k
*/
public double getValueAt(int k) {
- if(k < k_0) {
+ if (k < k_0) {
return Double.POSITIVE_INFINITY;
}
return m * StrictMath.log(k) + t;
@@ -120,17 +117,14 @@ public class ApproximationLine implements Externalizable {
/**
* Returns the approximated knn-distance at the specified k.
*
- * @param <O> Object type
- * @param <D> Distance type
* @param k the value for which the knn-distance should be returned
- * @param distanceFunction the distance function
* @return the approximated knn-distance at the specified k
*/
- public <O, D extends NumberDistance<D, ?>> D getApproximatedKnnDistance(int k, DistanceQuery<O, D> distanceFunction) {
- if(k < k_0) {
- return distanceFunction.nullDistance();
+ public double getApproximatedKnnDistance(int k) {
+ if (k < k_0) {
+ return 0.;
}
- return distanceFunction.getDistanceFactory().parseString("" + StrictMath.exp(getValueAt(k)));
+ return Math.exp(getValueAt(k));
}
/**
@@ -171,10 +165,10 @@ public class ApproximationLine implements Externalizable {
*/
@Override
public boolean equals(Object o) {
- if(this == o) {
+ if (this == o) {
return true;
}
- if(o == null || getClass() != o.getClass()) {
+ if (o == null || getClass() != o.getClass()) {
return false;
}
@@ -208,4 +202,4 @@ public class ApproximationLine implements Externalizable {
public String toString() {
return "m = " + m + ", t = " + t + " k_0 " + k_0;
}
-} \ No newline at end of file
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/ConvexHull.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/ConvexHull.java
index 6787aa9c..fe0e20b0 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/ConvexHull.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/ConvexHull.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mkcop;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCoPDirectoryEntry.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCoPDirectoryEntry.java
index 22b4efa4..8b6282a3 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCoPDirectoryEntry.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCoPDirectoryEntry.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mkcop;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -28,8 +28,6 @@ import java.io.ObjectInput;
import java.io.ObjectOutput;
import de.lmu.ifi.dbs.elki.database.ids.DBID;
-import de.lmu.ifi.dbs.elki.database.query.distance.DistanceQuery;
-import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeDirectoryEntry;
/**
@@ -39,8 +37,11 @@ import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeDirectoryEntry
*
* @author Elke Achtert
*/
-class MkCoPDirectoryEntry<D extends NumberDistance<D, ?>> extends MTreeDirectoryEntry<D> implements MkCoPEntry<D> {
- private static final long serialVersionUID = 1;
+class MkCoPDirectoryEntry extends MTreeDirectoryEntry implements MkCoPEntry {
+ /**
+ * Serialization version number.
+ */
+ private static final long serialVersionUID = 2;
/**
* The conservative approximation.
@@ -64,7 +65,7 @@ class MkCoPDirectoryEntry<D extends NumberDistance<D, ?>> extends MTreeDirectory
* @param conservativeApproximation the conservative approximation of the knn
* distances
*/
- public MkCoPDirectoryEntry(DBID objectID, D parentDistance, Integer nodeID, D coveringRadius, ApproximationLine conservativeApproximation) {
+ public MkCoPDirectoryEntry(DBID objectID, double parentDistance, Integer nodeID, double coveringRadius, ApproximationLine conservativeApproximation) {
super(objectID, parentDistance, nodeID, coveringRadius);
this.conservativeApproximation = conservativeApproximation;
}
@@ -73,12 +74,11 @@ class MkCoPDirectoryEntry<D extends NumberDistance<D, ?>> extends MTreeDirectory
* Returns the conservative approximated knn distance of the entry.
*
* @param k the parameter k of the knn distance
- * @param distanceFunction the distance function
* @return the conservative approximated knn distance of the entry
*/
@Override
- public <O> D approximateConservativeKnnDistance(int k, DistanceQuery<O, D> distanceFunction) {
- return conservativeApproximation.getApproximatedKnnDistance(k, distanceFunction);
+ public double approximateConservativeKnnDistance(int k) {
+ return conservativeApproximation.getApproximatedKnnDistance(k);
}
/**
@@ -138,20 +138,19 @@ class MkCoPDirectoryEntry<D extends NumberDistance<D, ?>> extends MTreeDirectory
* and has the same conservative approximation as this entry.
*/
@Override
- @SuppressWarnings("unchecked")
public boolean equals(Object o) {
- if(this == o) {
+ if (this == o) {
return true;
}
- if(o == null || getClass() != o.getClass()) {
+ if (o == null || getClass() != o.getClass()) {
return false;
}
- if(!super.equals(o)) {
+ if (!super.equals(o)) {
return false;
}
- final MkCoPDirectoryEntry<D> that = (MkCoPDirectoryEntry<D>) o;
+ final MkCoPDirectoryEntry that = (MkCoPDirectoryEntry) o;
return !(conservativeApproximation != null ? !conservativeApproximation.equals(that.conservativeApproximation) : that.conservativeApproximation != null);
}
-} \ No newline at end of file
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCoPEntry.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCoPEntry.java
index 077fb1ec..ae569d03 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCoPEntry.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCoPEntry.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mkcop;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -23,8 +23,6 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mkcop;
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-import de.lmu.ifi.dbs.elki.database.query.distance.DistanceQuery;
-import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeEntry;
/**
@@ -36,17 +34,14 @@ import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeEntry;
*
* @apiviz.composedOf ApproximationLine
*/
-interface MkCoPEntry<D extends NumberDistance<D, ?>> extends MTreeEntry<D> {
-
+interface MkCoPEntry extends MTreeEntry {
/**
* Returns the conservative approximated knn distance of the entry.
*
- * @param <O> Object type
* @param k the parameter k of the knn distance
- * @param distanceFunction the distance function
* @return the conservative approximated knn distance of the entry
*/
- public <O> D approximateConservativeKnnDistance(int k, DistanceQuery<O, D> distanceFunction);
+ public double approximateConservativeKnnDistance(int k);
/**
* Returns the conservative approximation line.
@@ -62,4 +57,4 @@ interface MkCoPEntry<D extends NumberDistance<D, ?>> extends MTreeEntry<D> {
* set
*/
public void setConservativeKnnDistanceApproximation(ApproximationLine conservativeApproximation);
-} \ No newline at end of file
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCoPLeafEntry.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCoPLeafEntry.java
index 0daf7950..7d241eba 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCoPLeafEntry.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCoPLeafEntry.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mkcop;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -28,8 +28,6 @@ import java.io.ObjectInput;
import java.io.ObjectOutput;
import de.lmu.ifi.dbs.elki.database.ids.DBID;
-import de.lmu.ifi.dbs.elki.database.query.distance.DistanceQuery;
-import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeLeafEntry;
/**
@@ -39,8 +37,11 @@ import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeLeafEntry;
*
* @author Elke Achtert
*/
-class MkCoPLeafEntry<D extends NumberDistance<D, ?>> extends MTreeLeafEntry<D> implements MkCoPEntry<D> {
- private static final long serialVersionUID = 1;
+class MkCoPLeafEntry extends MTreeLeafEntry implements MkCoPEntry {
+ /**
+ * Serialization version ID.
+ */
+ private static final long serialVersionUID = 2;
/**
* The conservative approximation.
@@ -70,7 +71,7 @@ class MkCoPLeafEntry<D extends NumberDistance<D, ?>> extends MTreeLeafEntry<D> i
* @param progressiveApproximation the progressive approximation of the knn
* distances
*/
- public MkCoPLeafEntry(DBID objectID, D parentDistance, ApproximationLine conservativeApproximation, ApproximationLine progressiveApproximation) {
+ public MkCoPLeafEntry(DBID objectID, double parentDistance, ApproximationLine conservativeApproximation, ApproximationLine progressiveApproximation) {
super(objectID, parentDistance);
this.conservativeApproximation = conservativeApproximation;
this.progressiveApproximation = progressiveApproximation;
@@ -80,24 +81,21 @@ class MkCoPLeafEntry<D extends NumberDistance<D, ?>> extends MTreeLeafEntry<D> i
* Returns the conservative approximated knn distance of the entry.
*
* @param k the parameter k of the knn distance
- * @param distanceFunction the distance function
* @return the conservative approximated knn distance of the entry
*/
@Override
- public <O> D approximateConservativeKnnDistance(int k, DistanceQuery<O, D> distanceFunction) {
- return conservativeApproximation.getApproximatedKnnDistance(k, distanceFunction);
+ public double approximateConservativeKnnDistance(int k) {
+ return conservativeApproximation.getApproximatedKnnDistance(k);
}
/**
* Returns the progressive approximated knn distance of the entry.
*
- * @param <O> Object type
* @param k the parameter k of the knn distance
- * @param distanceFunction the distance function
* @return the progressive approximated knn distance of the entry
*/
- public <O> D approximateProgressiveKnnDistance(int k, DistanceQuery<O, D> distanceFunction) {
- return progressiveApproximation.getApproximatedKnnDistance(k, distanceFunction);
+ public double approximateProgressiveKnnDistance(int k) {
+ return progressiveApproximation.getApproximatedKnnDistance(k);
}
/**
@@ -180,21 +178,20 @@ class MkCoPLeafEntry<D extends NumberDistance<D, ?>> extends MTreeLeafEntry<D> i
* entry.
*/
@Override
- @SuppressWarnings("unchecked")
public boolean equals(Object o) {
- if(this == o) {
+ if (this == o) {
return true;
}
- if(o == null || getClass() != o.getClass()) {
+ if (o == null || getClass() != o.getClass()) {
return false;
}
- if(!super.equals(o)) {
+ if (!super.equals(o)) {
return false;
}
- final MkCoPLeafEntry<D> that = (MkCoPLeafEntry<D>) o;
+ final MkCoPLeafEntry that = (MkCoPLeafEntry) o;
- if(conservativeApproximation != null ? !conservativeApproximation.equals(that.conservativeApproximation) : that.conservativeApproximation != null) {
+ if (conservativeApproximation != null ? !conservativeApproximation.equals(that.conservativeApproximation) : that.conservativeApproximation != null) {
return false;
}
@@ -211,4 +208,4 @@ class MkCoPLeafEntry<D extends NumberDistance<D, ?>> extends MTreeLeafEntry<D> i
return super.toString() + "\ncons " + conservativeApproximation + "\n";
// "prog " + progressiveApproximation;
}
-} \ No newline at end of file
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCoPTree.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCoPTree.java
index 562f7f4a..b98d6821 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCoPTree.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCoPTree.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mkcop;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -32,20 +32,20 @@ import de.lmu.ifi.dbs.elki.database.ids.DBIDIter;
import de.lmu.ifi.dbs.elki.database.ids.DBIDRef;
import de.lmu.ifi.dbs.elki.database.ids.DBIDUtil;
import de.lmu.ifi.dbs.elki.database.ids.ModifiableDBIDs;
-import de.lmu.ifi.dbs.elki.database.query.distance.DistanceQuery;
-import de.lmu.ifi.dbs.elki.distance.distancefunction.DistanceFunction;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.DistanceDBIDResult;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.DistanceDBIDResultIter;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.GenericDistanceDBIDList;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.KNNResult;
+import de.lmu.ifi.dbs.elki.database.ids.distance.DistanceDBIDList;
+import de.lmu.ifi.dbs.elki.database.ids.distance.DistanceDBIDListIter;
+import de.lmu.ifi.dbs.elki.database.ids.distance.KNNList;
+import de.lmu.ifi.dbs.elki.database.ids.generic.GenericDistanceDBIDList;
+import de.lmu.ifi.dbs.elki.database.relation.Relation;
import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.AbstractMkTree;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.MkTreeSettings;
import de.lmu.ifi.dbs.elki.index.tree.query.GenericMTreeDistanceSearchCandidate;
import de.lmu.ifi.dbs.elki.logging.Logging;
+import de.lmu.ifi.dbs.elki.persistent.ByteArrayUtil;
import de.lmu.ifi.dbs.elki.persistent.PageFile;
import de.lmu.ifi.dbs.elki.utilities.FormatUtil;
-import de.lmu.ifi.dbs.elki.utilities.QueryStatistic;
-import de.lmu.ifi.dbs.elki.utilities.datastructures.heap.Heap;
+import de.lmu.ifi.dbs.elki.utilities.datastructures.heap.ComparableMinHeap;
/**
* MkCopTree is a metrical index structure based on the concepts of the M-Tree
@@ -55,46 +55,34 @@ import de.lmu.ifi.dbs.elki.utilities.datastructures.heap.Heap;
* @author Elke Achtert
*
* @apiviz.has MkCoPTreeNode oneway - - contains
- * @apiviz.uses ConvexHull
+ * @apiviz.has ConvexHull
*
* @param <O> Object type
* @param <D> Distance type
*/
-public class MkCoPTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree<O, D, MkCoPTreeNode<O, D>, MkCoPEntry<D>> {
+public class MkCoPTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree<O, D, MkCoPTreeNode<O, D>, MkCoPEntry, MkTreeSettings<O, D, MkCoPTreeNode<O, D>, MkCoPEntry>> {
/**
* The logger for this class.
*/
private static final Logging LOG = Logging.getLogger(MkCoPTree.class);
/**
- * Parameter k.
- */
- int k_max;
-
- /**
* The values of log(1),..,log(k_max)
*/
private double[] log_k;
/**
- * Provides some statistics about performed reverse knn-queries.
- */
- private QueryStatistic rkNNStatistics = new QueryStatistic();
-
- /**
* Constructor.
*
+ * @param relation Relation to index
* @param pagefile Page file
- * @param distanceQuery Distance query
- * @param distanceFunction Distance function
- * @param k_max Maximum value of k supported
+ * @param settings Tree settings
*/
- public MkCoPTree(PageFile<MkCoPTreeNode<O, D>> pagefile, DistanceQuery<O, D> distanceQuery, DistanceFunction<O, D> distanceFunction, int k_max) {
- super(pagefile, distanceQuery, distanceFunction);
- this.k_max = k_max;
+ public MkCoPTree(Relation<O> relation, PageFile<MkCoPTreeNode<O, D>> pagefile, MkTreeSettings<O, D, MkCoPTreeNode<O, D>, MkCoPEntry> settings) {
+ super(relation, pagefile, settings);
// init log k
- log_k = new double[k_max];
- for(int k = 1; k <= k_max; k++) {
+ log_k = new double[settings.k_max];
+ for (int k = 1; k <= settings.k_max; k++) {
log_k[k - 1] = Math.log(k);
}
}
@@ -103,7 +91,7 @@ public class MkCoPTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
* @throws UnsupportedOperationException since this operation is not supported
*/
@Override
- protected void preInsert(MkCoPEntry<D> entry) {
+ protected void preInsert(MkCoPEntry entry) {
throw new UnsupportedOperationException("Insertion of single objects is not supported!");
}
@@ -111,40 +99,40 @@ public class MkCoPTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
* @throws UnsupportedOperationException since this operation is not supported
*/
@Override
- public void insert(MkCoPEntry<D> entry, boolean withPreInsert) {
+ public void insert(MkCoPEntry entry, boolean withPreInsert) {
throw new UnsupportedOperationException("Insertion of single objects is not supported!");
}
@Override
- public void insertAll(List<MkCoPEntry<D>> entries) {
- if(entries.isEmpty()) {
+ public void insertAll(List<MkCoPEntry> entries) {
+ if (entries.isEmpty()) {
return;
}
- if(LOG.isDebugging()) {
+ if (LOG.isDebugging()) {
LOG.debugFine("insert " + entries + "\n");
}
- if(!initialized) {
+ if (!initialized) {
initialize(entries.get(0));
}
ModifiableDBIDs ids = DBIDUtil.newArray(entries.size());
// insert
- for(MkCoPEntry<D> entry : entries) {
+ for (MkCoPEntry entry : entries) {
ids.add(entry.getRoutingObjectID());
// insert the object
super.insert(entry, false);
}
// perform nearest neighbor queries
- Map<DBID, KNNResult<D>> knnLists = batchNN(getRoot(), ids, k_max);
+ Map<DBID, KNNList<D>> knnLists = batchNN(getRoot(), ids, settings.k_max);
// adjust the knn distances
adjustApproximatedKNNDistances(getRootEntry(), knnLists);
- if(EXTRA_INTEGRITY_CHECKS) {
+ if (EXTRA_INTEGRITY_CHECKS) {
getRoot().integrityCheck(this, getRootEntry());
}
}
@@ -158,29 +146,30 @@ public class MkCoPTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
* @return a List of the query results
*/
@Override
- public DistanceDBIDResult<D> reverseKNNQuery(DBIDRef id, int k) {
- if(k > this.k_max) {
+ public DistanceDBIDList<D> reverseKNNQuery(DBIDRef id, int k) {
+ if (k > settings.k_max) {
throw new IllegalArgumentException("Parameter k has to be less or equal than " + "parameter kmax of the MCop-Tree!");
}
- GenericDistanceDBIDList<D> result = new GenericDistanceDBIDList<D>();
+ GenericDistanceDBIDList<D> result = new GenericDistanceDBIDList<>();
ModifiableDBIDs candidates = DBIDUtil.newArray();
doReverseKNNQuery(k, id, result, candidates);
// refinement of candidates
- Map<DBID, KNNResult<D>> knnLists = batchNN(getRoot(), candidates, k);
+ Map<DBID, KNNList<D>> knnLists = batchNN(getRoot(), candidates, k);
result.sort();
// Collections.sort(candidates);
- rkNNStatistics.addCandidates(candidates.size());
- rkNNStatistics.addTrueHits(result.size());
+ // FIXME: re-add statistics.
+ // rkNNStatistics.addCandidates(candidates.size());
+ // rkNNStatistics.addTrueHits(result.size());
- for(DBIDIter iter = candidates.iter(); iter.valid(); iter.advance()) {
+ for (DBIDIter iter = candidates.iter(); iter.valid(); iter.advance()) {
DBID cid = DBIDUtil.deref(iter);
- KNNResult<D> cands = knnLists.get(cid);
- for (DistanceDBIDResultIter<D> iter2 = cands.iter(); iter2.valid(); iter2.advance()) {
- if(DBIDUtil.equal(id, iter2)) {
+ KNNList<D> cands = knnLists.get(cid);
+ for (DistanceDBIDListIter<D> iter2 = cands.iter(); iter2.valid(); iter2.advance()) {
+ if (DBIDUtil.equal(id, iter2)) {
result.add(iter2.getDistance(), cid);
break;
}
@@ -188,45 +177,30 @@ public class MkCoPTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
}
result.sort();
- rkNNStatistics.addResults(result.size());
+ // FIXME: re-add statistics.
+ // rkNNStatistics.addResults(result.size());
return result;
}
/**
- * Returns the statistic for performed rknn queries.
- *
- * @return the statistic for performed rknn queries
- */
- public QueryStatistic getRkNNStatistics() {
- return rkNNStatistics;
- }
-
- /**
- * Clears the values of the statistic for performed rknn queries
- */
- public void clearRkNNStatistics() {
- rkNNStatistics.clear();
- }
-
- /**
* Returns the value of the k_max parameter.
*
* @return the value of the k_max parameter
*/
public int getK_max() {
- return k_max;
+ return settings.k_max;
}
/**
* Determines the maximum and minimum number of entries in a node.
*/
@Override
- protected void initializeCapacities(MkCoPEntry<D> exampleLeaf) {
- int distanceSize = exampleLeaf.getParentDistance().externalizableSize();
+ protected void initializeCapacities(MkCoPEntry exampleLeaf) {
+ int distanceSize = ByteArrayUtil.SIZE_DOUBLE; // exampleLeaf.getParentDistance().externalizableSize();
// overhead = index(4), numEntries(4), id(4), isLeaf(0.125)
double overhead = 12.125;
- if(getPageSize() - overhead < 0) {
+ if (getPageSize() - overhead < 0) {
throw new RuntimeException("Node size of " + getPageSize() + " Bytes is chosen too small!");
}
@@ -234,11 +208,11 @@ public class MkCoPTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
// coveringRadius + parentDistance + consApprox) + 1
dirCapacity = (int) (getPageSize() - overhead) / (4 + 4 + distanceSize + distanceSize + 10) + 1;
- if(dirCapacity <= 1) {
+ if (dirCapacity <= 1) {
throw new RuntimeException("Node size of " + getPageSize() + " Bytes is chosen too small!");
}
- if(dirCapacity < 10) {
+ if (dirCapacity < 10) {
LOG.warning("Page size is choosen too small! Maximum number of entries " + "in a directory node = " + (dirCapacity - 1));
}
@@ -247,17 +221,17 @@ public class MkCoPTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
// consApprox + progrApprox) + 1
leafCapacity = (int) (getPageSize() - overhead) / (4 + distanceSize + 2 * 10) + 1;
- if(leafCapacity <= 1) {
+ if (leafCapacity <= 1) {
throw new RuntimeException("Node size of " + getPageSize() + " Bytes is chosen too small!");
}
- if(leafCapacity < 10) {
+ if (leafCapacity < 10) {
LOG.warning("Page size is choosen too small! Maximum number of entries " + "in a leaf node = " + (leafCapacity - 1));
}
initialized = true;
- if(LOG.isVerbose()) {
+ if (LOG.isVerbose()) {
LOG.verbose("Directory Capacity: " + (dirCapacity - 1) + "\nLeaf Capacity: " + (leafCapacity - 1));
}
}
@@ -272,45 +246,44 @@ public class MkCoPTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
* refinement)
*/
private void doReverseKNNQuery(int k, DBIDRef q, GenericDistanceDBIDList<D> result, ModifiableDBIDs candidates) {
- final Heap<GenericMTreeDistanceSearchCandidate<D>> pq = new Heap<GenericMTreeDistanceSearchCandidate<D>>();
+ final ComparableMinHeap<GenericMTreeDistanceSearchCandidate> pq = new ComparableMinHeap<>();
// push root
- pq.add(new GenericMTreeDistanceSearchCandidate<D>(getDistanceQuery().nullDistance(), getRootID(), null, null));
+ pq.add(new GenericMTreeDistanceSearchCandidate(0., getRootID(), null));
// search in tree
- while(!pq.isEmpty()) {
- GenericMTreeDistanceSearchCandidate<D> pqNode = pq.poll();
+ while (!pq.isEmpty()) {
+ GenericMTreeDistanceSearchCandidate pqNode = pq.poll();
// FIXME: cache the distance to the routing object in the queue node!
MkCoPTreeNode<O, D> node = getNode(pqNode.nodeID);
// directory node
- if(!node.isLeaf()) {
- for(int i = 0; i < node.getNumEntries(); i++) {
- MkCoPEntry<D> entry = node.getEntry(i);
- D distance = getDistanceQuery().distance(entry.getRoutingObjectID(), q);
- D minDist = entry.getCoveringRadius().compareTo(distance) > 0 ? getDistanceQuery().nullDistance() : distance.minus(entry.getCoveringRadius());
- D approximatedKnnDist_cons = entry.approximateConservativeKnnDistance(k, getDistanceQuery());
-
- if(minDist.compareTo(approximatedKnnDist_cons) <= 0) {
- pq.add(new GenericMTreeDistanceSearchCandidate<D>(minDist, getPageID(entry), entry.getRoutingObjectID(), null));
+ if (!node.isLeaf()) {
+ for (int i = 0; i < node.getNumEntries(); i++) {
+ MkCoPEntry entry = node.getEntry(i);
+ double distance = distance(entry.getRoutingObjectID(), q).doubleValue();
+ double minDist = entry.getCoveringRadius() > distance ? 0. : distance - entry.getCoveringRadius();
+ double approximatedKnnDist_cons = entry.approximateConservativeKnnDistance(k);
+
+ if (minDist <= approximatedKnnDist_cons) {
+ pq.add(new GenericMTreeDistanceSearchCandidate(minDist, getPageID(entry), entry.getRoutingObjectID()));
}
}
}
// data node
else {
- for(int i = 0; i < node.getNumEntries(); i++) {
- MkCoPLeafEntry<D> entry = (MkCoPLeafEntry<D>) node.getEntry(i);
- D distance = getDistanceQuery().distance(entry.getRoutingObjectID(), q);
- D approximatedKnnDist_prog = entry.approximateProgressiveKnnDistance(k, getDistanceQuery());
+ for (int i = 0; i < node.getNumEntries(); i++) {
+ MkCoPLeafEntry entry = (MkCoPLeafEntry) node.getEntry(i);
+ D distance = distance(entry.getRoutingObjectID(), q);
+ double approximatedKnnDist_prog = entry.approximateProgressiveKnnDistance(k);
- if(distance.compareTo(approximatedKnnDist_prog) <= 0) {
+ if (distance.doubleValue() <= approximatedKnnDist_prog) {
result.add(distance, entry.getRoutingObjectID());
- }
- else {
- D approximatedKnnDist_cons = entry.approximateConservativeKnnDistance(k, getDistanceQuery());
- double diff = distance.doubleValue() - approximatedKnnDist_cons.doubleValue();
- if(diff <= 0.0000000001) {
+ } else {
+ double approximatedKnnDist_cons = entry.approximateConservativeKnnDistance(k);
+ double diff = distance.doubleValue() - approximatedKnnDist_cons;
+ if (diff <= 1E-10) {
candidates.add(entry.getRoutingObjectID());
}
}
@@ -325,23 +298,22 @@ public class MkCoPTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
* @param entry the root entry of the current subtree
* @param knnLists a map of knn lists for each leaf entry
*/
- private void adjustApproximatedKNNDistances(MkCoPEntry<D> entry, Map<DBID, KNNResult<D>> knnLists) {
+ private void adjustApproximatedKNNDistances(MkCoPEntry entry, Map<DBID, KNNList<D>> knnLists) {
MkCoPTreeNode<O, D> node = getNode(entry);
- if(node.isLeaf()) {
- for(int i = 0; i < node.getNumEntries(); i++) {
- MkCoPLeafEntry<D> leafEntry = (MkCoPLeafEntry<D>) node.getEntry(i);
+ if (node.isLeaf()) {
+ for (int i = 0; i < node.getNumEntries(); i++) {
+ MkCoPLeafEntry leafEntry = (MkCoPLeafEntry) node.getEntry(i);
approximateKnnDistances(leafEntry, knnLists.get(leafEntry.getRoutingObjectID()));
}
- }
- else {
- for(int i = 0; i < node.getNumEntries(); i++) {
- MkCoPEntry<D> dirEntry = node.getEntry(i);
+ } else {
+ for (int i = 0; i < node.getNumEntries(); i++) {
+ MkCoPEntry dirEntry = node.getEntry(i);
adjustApproximatedKNNDistances(dirEntry, knnLists);
}
}
- ApproximationLine approx = node.conservativeKnnDistanceApproximation(k_max);
+ ApproximationLine approx = node.conservativeKnnDistanceApproximation(settings.k_max);
entry.setConservativeKnnDistanceApproximation(approx);
}
@@ -351,7 +323,7 @@ public class MkCoPTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
private double ssqerr(int k0, int kmax, double[] logk, double[] log_kDist, double m, double t) {
int k = kmax - k0;
double result = 0;
- for(int i = 0; i < k; i++) {
+ for (int i = 0; i < k; i++) {
// double h = log_kDist[i] - (m * (logk[i] - logk[0]) + t); ???
double h = log_kDist[i] - m * logk[i] - t;
result += h * h;
@@ -377,33 +349,32 @@ public class MkCoPTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
* @param knnDistances TODO: Spezialbehandlung fuer identische Punkte in DB
* (insbes. Distanz 0)
*/
- private void approximateKnnDistances(MkCoPLeafEntry<D> entry, KNNResult<D> knnDistances) {
+ private void approximateKnnDistances(MkCoPLeafEntry entry, KNNList<D> knnDistances) {
StringBuilder msg = LOG.isDebugging() ? new StringBuilder() : null;
- if(msg != null) {
+ if (msg != null) {
msg.append("\nknnDistances ").append(knnDistances);
}
// count the zero distances
int k_0 = 0;
- for(int i = 0; i < k_max; i++) {
+ for (int i = 0; i < settings.k_max; i++) {
double dist = knnDistances.get(i).getDistance().doubleValue();
- if(dist == 0) {
+ if (dist == 0) {
k_0++;
- }
- else {
+ } else {
break;
}
}
// init variables
- double[] log_k = new double[k_max - k_0];
- System.arraycopy(this.log_k, k_0, log_k, 0, k_max - k_0);
+ double[] log_k = new double[settings.k_max - k_0];
+ System.arraycopy(this.log_k, k_0, log_k, 0, settings.k_max - k_0);
double sum_log_kDist = 0;
double sum_log_k_kDist = 0;
- double[] log_kDist = new double[k_max - k_0];
+ double[] log_kDist = new double[settings.k_max - k_0];
- for(int i = 0; i < k_max - k_0; i++) {
+ for (int i = 0; i < settings.k_max - k_0; i++) {
double dist = knnDistances.get(i + k_0).getDistance().doubleValue();
log_kDist[i] = Math.log(dist);
sum_log_kDist += log_kDist[i];
@@ -413,14 +384,14 @@ public class MkCoPTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
double sum_log_k = 0;
double sum_log_k2 = 0;
// noinspection ForLoopReplaceableByForEach
- for(int i = 0; i < log_k.length; i++) {
+ for (int i = 0; i < log_k.length; i++) {
sum_log_k += log_k[i];
sum_log_k2 += (log_k[i] * log_k[i]);
}
- if(msg != null) {
+ if (msg != null) {
msg.append("\nk_0 ").append(k_0);
- msg.append("\nk_max ").append(k_max);
+ msg.append("\nk_max ").append(settings.k_max);
msg.append("\nlog_k(").append(log_k.length).append(") ").append(FormatUtil.format(log_k));
msg.append("\nsum_log_k ").append(sum_log_k);
msg.append("\nsum_log_k^2 ").append(sum_log_k2);
@@ -438,15 +409,15 @@ public class MkCoPTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
ApproximationLine c2 = approximateUpperHull_PAPER(convexHull, log_k, sum_log_k, sum_log_k2, log_kDist, sum_log_kDist, sum_log_k_kDist);
- double err1 = ssqerr(k_0, k_max, log_k, log_kDist, conservative.getM(), conservative.getT());
- double err2 = ssqerr(k_0, k_max, log_k, log_kDist, c2.getM(), c2.getT());
+ double err1 = ssqerr(k_0, settings.k_max, log_k, log_kDist, conservative.getM(), conservative.getT());
+ double err2 = ssqerr(k_0, settings.k_max, log_k, log_kDist, c2.getM(), c2.getT());
- if(msg != null) {
+ if (msg != null) {
msg.append("err1 ").append(err1);
msg.append("err2 ").append(err2);
}
- if(err1 > err2 && err1 - err2 > 0.000000001) {
+ if (err1 > err2 && err1 - err2 > 0.000000001) {
// if (err1 > err2) {
StringBuilder warning = new StringBuilder();
@@ -460,7 +431,7 @@ public class MkCoPTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
warning.append("\nconservative1 ").append(conservative);
warning.append("\nconservative2 ").append(c2);
- for(int i = 0; i < u; i++) {
+ for (int i = 0; i < u; i++) {
warning.append("\nlog_k[").append(upperHull[i]).append("] = ").append(log_k[upperHull[i]]);
warning.append("\nlog_kDist[").append(upperHull[i]).append("] = ").append(log_kDist[upperHull[i]]);
}
@@ -473,7 +444,7 @@ public class MkCoPTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
entry.setConservativeKnnDistanceApproximation(conservative);
entry.setProgressiveKnnDistanceApproximation(progressive);
- if(msg != null) {
+ if (msg != null) {
LOG.debugFine(msg.toString());
}
}
@@ -491,7 +462,7 @@ public class MkCoPTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
StringBuilder msg = new StringBuilder();
int[] lowerHull = convexHull.getLowerHull();
int l = convexHull.getNumberOfPointsInLowerHull();
- int k_0 = k_max - lowerHull.length + 1;
+ int k_0 = settings.k_max - lowerHull.length + 1;
// linear search on all line segments on the lower convex hull
msg.append("lower hull l = ").append(l).append("\n");
@@ -499,12 +470,12 @@ public class MkCoPTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
double low_m = 0.0;
double low_t = 0.0;
- for(int i = 1; i < l; i++) {
+ for (int i = 1; i < l; i++) {
double cur_m = (log_kDist[lowerHull[i]] - log_kDist[lowerHull[i - 1]]) / (log_k[lowerHull[i]] - log_k[lowerHull[i - 1]]);
double cur_t = log_kDist[lowerHull[i]] - cur_m * log_k[lowerHull[i]];
- double cur_error = ssqerr(k_0, k_max, log_k, log_kDist, cur_m, cur_t);
+ double cur_error = ssqerr(k_0, settings.k_max, log_k, log_kDist, cur_m, cur_t);
msg.append(" Segment = ").append(i).append(" m = ").append(cur_m).append(" t = ").append(cur_t).append(" lowerror = ").append(cur_error).append("\n");
- if(cur_error < low_error) {
+ if (cur_error < low_error) {
low_error = cur_error;
low_m = cur_m;
low_t = cur_t;
@@ -513,13 +484,13 @@ public class MkCoPTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
// linear search on all points of the lower convex hull
boolean is_right = true; // NEEDED FOR PROOF CHECK
- for(int i = 0; i < l; i++) {
- double cur_m = optimize(k_0, k_max, sum_log_k, sum_log_k2, log_k[lowerHull[i]], log_kDist[lowerHull[i]], sum_log_k_kDist, sum_log_kDist);
+ for (int i = 0; i < l; i++) {
+ double cur_m = optimize(k_0, settings.k_max, sum_log_k, sum_log_k2, log_k[lowerHull[i]], log_kDist[lowerHull[i]], sum_log_k_kDist, sum_log_kDist);
double cur_t = log_kDist[lowerHull[i]] - cur_m * log_k[lowerHull[i]];
// only valid if both neighboring points are underneath y=mx+t
- if((i == 0 || log_kDist[lowerHull[i - 1]] >= log_kDist[lowerHull[i]] - cur_m * (log_k[lowerHull[i]] - log_k[lowerHull[i - 1]])) && (i == l - 1 || log_kDist[lowerHull[i + 1]] >= log_kDist[lowerHull[i]] + cur_m * (log_k[lowerHull[i + 1]] - log_k[lowerHull[i]]))) {
- double cur_error = ssqerr(k_0, k_max, log_k, log_kDist, cur_m, cur_t);
- if(cur_error < low_error) {
+ if ((i == 0 || log_kDist[lowerHull[i - 1]] >= log_kDist[lowerHull[i]] - cur_m * (log_k[lowerHull[i]] - log_k[lowerHull[i - 1]])) && (i == l - 1 || log_kDist[lowerHull[i + 1]] >= log_kDist[lowerHull[i]] + cur_m * (log_k[lowerHull[i + 1]] - log_k[lowerHull[i]]))) {
+ double cur_error = ssqerr(k_0, settings.k_max, log_k, log_kDist, cur_m, cur_t);
+ if (cur_error < low_error) {
low_error = cur_error;
low_m = cur_m;
low_t = cur_t;
@@ -527,9 +498,9 @@ public class MkCoPTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
}
// check proof of bisection search
- if(!(i > 0 && log_kDist[lowerHull[i - 1]] < log_kDist[lowerHull[i]] - cur_m * (log_k[lowerHull[i]] - log_k[lowerHull[i - 1]])) && !is_right) {
+ if (!(i > 0 && log_kDist[lowerHull[i - 1]] < log_kDist[lowerHull[i]] - cur_m * (log_k[lowerHull[i]] - log_k[lowerHull[i - 1]])) && !is_right) {
// warning("ERROR lower: The bisection search will not work properly !");
- if(!(i < l - 1 && log_kDist[lowerHull[i + 1]] < log_kDist[lowerHull[i]] + cur_m * (log_k[lowerHull[i + 1]] - log_k[lowerHull[i]]))) {
+ if (!(i < l - 1 && log_kDist[lowerHull[i + 1]] < log_kDist[lowerHull[i]] + cur_m * (log_k[lowerHull[i + 1]] - log_k[lowerHull[i]]))) {
is_right = false;
}
}
@@ -544,18 +515,18 @@ public class MkCoPTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
int[] upperHull = convexHull.getUpperHull();
int u = convexHull.getNumberOfPointsInUpperHull();
- int k_0 = k_max - upperHull.length + 1;
+ int k_0 = settings.k_max - upperHull.length + 1;
ApproximationLine approx = null;
double error = Double.POSITIVE_INFINITY;
- for(int i = 0; i < u - 1; i++) {
+ for (int i = 0; i < u - 1; i++) {
int ii = upperHull[i];
int jj = upperHull[i + 1];
double current_m = (log_kDist[jj] - log_kDist[ii]) / (log_k[jj] - log_k[ii]);
double current_t = log_kDist[ii] - current_m * log_k[ii];
ApproximationLine current_approx = new ApproximationLine(k_0, current_m, current_t);
- if(LOG.isDebugging()) {
+ if (LOG.isDebugging()) {
msg.append("\nlog_kDist[").append(jj).append("] ").append(log_kDist[jj]);
msg.append("\nlog_kDist[").append(ii).append("] ").append(log_kDist[ii]);
msg.append("\nlog_k[").append(jj).append("] ").append(log_k[jj]);
@@ -566,22 +537,22 @@ public class MkCoPTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
boolean ok = true;
double currentError = 0;
- for(int k = k_0; k <= k_max; k++) {
+ for (int k = k_0; k <= settings.k_max; k++) {
double appDist = current_approx.getValueAt(k);
- if(appDist < log_kDist[k - k_0] && log_kDist[k - k_0] - appDist > 0.000000001) {
+ if (appDist < log_kDist[k - k_0] && log_kDist[k - k_0] - appDist > 0.000000001) {
ok = false;
break;
}
currentError += (appDist - log_kDist[k - k_0]);
}
- if(ok && currentError < error) {
+ if (ok && currentError < error) {
approx = current_approx;
error = currentError;
}
}
- if(LOG.isDebugging()) {
+ if (LOG.isDebugging()) {
msg.append("\nupper Approx ").append(approx);
LOG.debugFine(msg.toString());
}
@@ -594,22 +565,22 @@ public class MkCoPTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
int[] upperHull = convexHull.getUpperHull();
int u = convexHull.getNumberOfPointsInUpperHull();
- List<Integer> marked = new ArrayList<Integer>();
+ List<Integer> marked = new ArrayList<>();
- int k_0 = k_max - upperHull.length + 1;
+ int k_0 = settings.k_max - upperHull.length + 1;
int a = u / 2;
- while(marked.size() != u) {
+ while (marked.size() != u) {
marked.add(a);
double x_a = log_k[upperHull[a]];
double y_a = log_kDist[upperHull[a]];
- double m_a = optimize(k_0, k_max, sum_log_k, sum_log_k2, x_a, y_a, sum_log_k_kDist, sum_log_kDist);
+ double m_a = optimize(k_0, settings.k_max, sum_log_k, sum_log_k2, x_a, y_a, sum_log_k_kDist, sum_log_kDist);
double t_a = y_a - m_a * x_a;
- if(msg != null) {
+ if (msg != null) {
msg.append("\na=").append(a).append(" m_a=").append(m_a).append(", t_a=").append(t_a);
- msg.append("\n err ").append(ssqerr(k_0, k_max, log_k, log_kDist, m_a, m_a));
+ msg.append("\n err ").append(ssqerr(k_0, settings.k_max, log_k, log_kDist, m_a, m_a));
}
double x_p = a == 0 ? Double.NaN : log_k[upperHull[a - 1]];
@@ -620,24 +591,23 @@ public class MkCoPTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
boolean lessThanPre = a == 0 || y_p <= m_a * x_p + t_a;
boolean lessThanSuc = a == u || y_s <= m_a * x_s + t_a;
- if(lessThanPre && lessThanSuc) {
+ if (lessThanPre && lessThanSuc) {
ApproximationLine appr = new ApproximationLine(k_0, m_a, t_a);
- if(msg != null) {
+ if (msg != null) {
msg.append("\n1 anchor = ").append(a);
LOG.debugFine(msg.toString());
}
return appr;
- }
- else if(!lessThanPre) {
- if(marked.contains(a - 1)) {
+ } else if (!lessThanPre) {
+ if (marked.contains(a - 1)) {
m_a = (y_a - y_p) / (x_a - x_p);
- if(y_a == y_p) {
+ if (y_a == y_p) {
m_a = 0;
}
t_a = y_a - m_a * x_a;
ApproximationLine appr = new ApproximationLine(k_0, m_a, t_a);
- if(msg != null) {
+ if (msg != null) {
msg.append("2 anchor = ").append(a);
msg.append(" appr1 ").append(appr);
msg.append(" x_a ").append(x_a).append(", y_a ").append(y_a);
@@ -647,28 +617,25 @@ public class MkCoPTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
LOG.debugFine(msg.toString());
}
return appr;
- }
- else {
+ } else {
a = a - 1;
}
- }
- else {
- if(marked.contains(a + 1)) {
+ } else {
+ if (marked.contains(a + 1)) {
m_a = (y_a - y_s) / (x_a - x_s);
- if(y_a == y_p) {
+ if (y_a == y_p) {
m_a = 0;
}
t_a = y_a - m_a * x_a;
ApproximationLine appr = new ApproximationLine(k_0, m_a, t_a);
- if(msg != null) {
+ if (msg != null) {
msg.append("3 anchor = ").append(a).append(" -- ").append((a + 1));
msg.append(" appr2 ").append(appr);
LOG.debugFine(msg.toString());
}
return appr;
- }
- else {
+ } else {
a = a + 1;
}
}
@@ -683,18 +650,18 @@ public class MkCoPTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
StringBuilder msg = new StringBuilder();
int[] upperHull = convexHull.getUpperHull();
int u = convexHull.getNumberOfPointsInUpperHull();
- int k_0 = k_max - upperHull.length + 1;
+ int k_0 = settings.k_max - upperHull.length + 1;
// linear search on all line segments on the upper convex hull
msg.append("upper hull:").append(u);
double upp_error = Double.MAX_VALUE;
double upp_m = 0.0;
double upp_t = 0.0;
- for(int i = 1; i < u; i++) {
+ for (int i = 1; i < u; i++) {
double cur_m = (log_kDist[upperHull[i]] - log_kDist[upperHull[i - 1]]) / (log_k[upperHull[i]] - log_k[upperHull[i - 1]]);
double cur_t = log_kDist[upperHull[i]] - cur_m * log_k[upperHull[i]];
- double cur_error = ssqerr(k_0, k_max, log_k, log_kDist, cur_m, cur_t);
- if(cur_error < upp_error) {
+ double cur_error = ssqerr(k_0, settings.k_max, log_k, log_kDist, cur_m, cur_t);
+ if (cur_error < upp_error) {
upp_error = cur_error;
upp_m = cur_m;
upp_t = cur_t;
@@ -702,13 +669,13 @@ public class MkCoPTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
}
// linear search on all points of the upper convex hull
boolean is_left = true; // NEEDED FOR PROOF CHECK
- for(int i = 0; i < u; i++) {
- double cur_m = optimize(k_0, k_max, sum_log_k, sum_log_k2, log_k[upperHull[i]], log_kDist[upperHull[i]], sum_log_k_kDist, sum_log_kDist);
+ for (int i = 0; i < u; i++) {
+ double cur_m = optimize(k_0, settings.k_max, sum_log_k, sum_log_k2, log_k[upperHull[i]], log_kDist[upperHull[i]], sum_log_k_kDist, sum_log_kDist);
double cur_t = log_kDist[upperHull[i]] - cur_m * log_k[upperHull[i]];
// only valid if both neighboring points are underneath y=mx+t
- if((i == 0 || log_kDist[upperHull[i - 1]] <= log_kDist[upperHull[i]] - cur_m * (log_k[upperHull[i]] - log_k[upperHull[i - 1]])) && (i == u - 1 || log_kDist[upperHull[i + 1]] <= log_kDist[upperHull[i]] + cur_m * (log_k[upperHull[i + 1]] - log_k[upperHull[i]]))) {
- double cur_error = ssqerr(k_0, k_max, log_k, log_kDist, cur_m, cur_t);
- if(cur_error < upp_error) {
+ if ((i == 0 || log_kDist[upperHull[i - 1]] <= log_kDist[upperHull[i]] - cur_m * (log_k[upperHull[i]] - log_k[upperHull[i - 1]])) && (i == u - 1 || log_kDist[upperHull[i + 1]] <= log_kDist[upperHull[i]] + cur_m * (log_k[upperHull[i + 1]] - log_k[upperHull[i]]))) {
+ double cur_error = ssqerr(k_0, settings.k_max, log_k, log_kDist, cur_m, cur_t);
+ if (cur_error < upp_error) {
upp_error = cur_error;
upp_m = cur_m;
upp_t = cur_t;
@@ -716,12 +683,12 @@ public class MkCoPTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
}
// check proof of bisection search
- if(!(i > 0 && log_kDist[upperHull[i - 1]] > log_kDist[upperHull[i]] - cur_m * (log_k[upperHull[i]] - log_k[upperHull[i - 1]])) && !is_left) {
+ if (!(i > 0 && log_kDist[upperHull[i - 1]] > log_kDist[upperHull[i]] - cur_m * (log_k[upperHull[i]] - log_k[upperHull[i - 1]])) && !is_left) {
// warning("ERROR upper: The bisection search will not work properly !"
// +
// "\n" + Util.format(log_kDist));
}
- if(!(i < u - 1 && log_kDist[upperHull[i + 1]] > log_kDist[upperHull[i]] + cur_m * (log_k[upperHull[i + 1]] - log_k[upperHull[i]]))) {
+ if (!(i < u - 1 && log_kDist[upperHull[i + 1]] > log_kDist[upperHull[i]] + cur_m * (log_k[upperHull[i + 1]] - log_k[upperHull[i]]))) {
is_left = false;
}
}
@@ -737,7 +704,7 @@ public class MkCoPTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
*/
@Override
protected MkCoPTreeNode<O, D> createNewLeafNode() {
- return new MkCoPTreeNode<O, D>(leafCapacity, true);
+ return new MkCoPTreeNode<>(leafCapacity, true);
}
/**
@@ -747,7 +714,7 @@ public class MkCoPTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
*/
@Override
protected MkCoPTreeNode<O, D> createNewDirectoryNode() {
- return new MkCoPTreeNode<O, D>(dirCapacity, false);
+ return new MkCoPTreeNode<>(dirCapacity, false);
}
/**
@@ -759,8 +726,8 @@ public class MkCoPTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
* the routing object of the parent node
*/
@Override
- protected MkCoPEntry<D> createNewDirectoryEntry(MkCoPTreeNode<O, D> node, DBID routingObjectID, D parentDistance) {
- return new MkCoPDirectoryEntry<D>(routingObjectID, parentDistance, node.getPageID(), node.coveringRadius(routingObjectID, this), null);
+ protected MkCoPEntry createNewDirectoryEntry(MkCoPTreeNode<O, D> node, DBID routingObjectID, double parentDistance) {
+ return new MkCoPDirectoryEntry(routingObjectID, parentDistance, node.getPageID(), node.coveringRadius(routingObjectID, this), null);
// node.conservativeKnnDistanceApproximation(k_max));
}
@@ -770,12 +737,12 @@ public class MkCoPTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTree
* @return an entry representing the root node
*/
@Override
- protected MkCoPEntry<D> createRootEntry() {
- return new MkCoPDirectoryEntry<D>(null, null, 0, null, null);
+ protected MkCoPEntry createRootEntry() {
+ return new MkCoPDirectoryEntry(null, 0., 0, 0., null);
}
@Override
protected Logging getLogger() {
return LOG;
}
-} \ No newline at end of file
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCoPTreeIndex.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCoPTreeIndex.java
index d3e45f8c..96def76b 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCoPTreeIndex.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCoPTreeIndex.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mkcop;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -28,9 +28,7 @@ import java.util.List;
import de.lmu.ifi.dbs.elki.database.ids.DBID;
import de.lmu.ifi.dbs.elki.database.ids.DBIDIter;
-import de.lmu.ifi.dbs.elki.database.ids.DBIDRef;
import de.lmu.ifi.dbs.elki.database.ids.DBIDUtil;
-import de.lmu.ifi.dbs.elki.database.ids.DBIDs;
import de.lmu.ifi.dbs.elki.database.query.DatabaseQuery;
import de.lmu.ifi.dbs.elki.database.query.distance.DistanceQuery;
import de.lmu.ifi.dbs.elki.database.query.knn.KNNQuery;
@@ -43,12 +41,10 @@ import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
import de.lmu.ifi.dbs.elki.index.KNNIndex;
import de.lmu.ifi.dbs.elki.index.RKNNIndex;
import de.lmu.ifi.dbs.elki.index.RangeIndex;
-import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTree;
-import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.AbstractMkTree;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.MkTreeSettings;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.query.MTreeQueryUtil;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.query.MkTreeRKNNQuery;
import de.lmu.ifi.dbs.elki.persistent.PageFile;
-import de.lmu.ifi.dbs.elki.utilities.exceptions.ExceptionMessages;
/**
* MkCoPTree used as database index.
@@ -69,14 +65,11 @@ public class MkCoPTreeIndex<O, D extends NumberDistance<D, ?>> extends MkCoPTree
*
* @param relation Relation to index.
* @param pageFile Page file
- * @param distanceQuery Distance query
- * @param distanceFunction Distance function
- * @param k_max Maximum value of k supported
+ * @param settings Tree settings
*/
- public MkCoPTreeIndex(Relation<O> relation, PageFile<MkCoPTreeNode<O, D>> pageFile, DistanceQuery<O, D> distanceQuery, DistanceFunction<O, D> distanceFunction, int k_max) {
- super(pageFile, distanceQuery, distanceFunction, k_max);
+ public MkCoPTreeIndex(Relation<O> relation, PageFile<MkCoPTreeNode<O, D>> pageFile, MkTreeSettings<O, D, MkCoPTreeNode<O, D>, MkCoPEntry> settings) {
+ super(relation, pageFile, settings);
this.relation = relation;
- this.initialize();
}
/**
@@ -87,120 +80,89 @@ public class MkCoPTreeIndex<O, D extends NumberDistance<D, ?>> extends MkCoPTree
* @param parentDistance the distance from the object to the routing object of
* the parent node
*/
- protected MkCoPEntry<D> createNewLeafEntry(DBID id, O object, D parentDistance) {
- MkCoPLeafEntry<D> leafEntry = new MkCoPLeafEntry<D>(id, parentDistance, null, null);
+ protected MkCoPEntry createNewLeafEntry(DBID id, O object, double parentDistance) {
+ MkCoPLeafEntry leafEntry = new MkCoPLeafEntry(id, parentDistance, null, null);
return leafEntry;
}
@Override
- public void insert(DBIDRef id) {
- throw new UnsupportedOperationException("Insertion of single objects is not supported!");
- }
-
- @Override
- public void insertAll(DBIDs ids) {
- List<MkCoPEntry<D>> objs = new ArrayList<MkCoPEntry<D>>(ids.size());
- for (DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) {
- DBID id = DBIDUtil.deref(iter);
+ public void initialize() {
+ super.initialize();
+ List<MkCoPEntry> objs = new ArrayList<>(relation.size());
+ for (DBIDIter iter = relation.iterDBIDs(); iter.valid(); iter.advance()) {
+ DBID id = DBIDUtil.deref(iter); // FIXME: expensive
final O object = relation.get(id);
- objs.add(createNewLeafEntry(id, object, getDistanceFactory().undefinedDistance()));
+ objs.add(createNewLeafEntry(id, object, Double.NaN));
}
insertAll(objs);
}
- /**
- * Throws an UnsupportedOperationException since deletion of objects is not
- * yet supported by an M-Tree.
- *
- * @throws UnsupportedOperationException thrown, since deletions aren't
- * implemented yet.
- */
- @Override
- public final boolean delete(DBIDRef id) {
- throw new UnsupportedOperationException(ExceptionMessages.UNSUPPORTED_NOT_YET);
- }
-
- /**
- * Throws an UnsupportedOperationException since deletion of objects is not
- * yet supported by an M-Tree.
- *
- * @throws UnsupportedOperationException thrown, since deletions aren't
- * implemented yet.
- */
- @Override
- public void deleteAll(DBIDs ids) {
- throw new UnsupportedOperationException(ExceptionMessages.UNSUPPORTED_NOT_YET);
- }
-
@SuppressWarnings("unchecked")
@Override
public <S extends Distance<S>> KNNQuery<O, S> getKNNQuery(DistanceQuery<O, S> distanceQuery, Object... hints) {
// Query on the relation we index
- if(distanceQuery.getRelation() != relation) {
+ if (distanceQuery.getRelation() != relation) {
return null;
}
- DistanceFunction<? super O, S> distanceFunction = distanceQuery.getDistanceFunction();
- if(!this.distanceFunction.equals(distanceFunction)) {
- if(getLogger().isDebugging()) {
+ DistanceFunction<? super O, D> distanceFunction = (DistanceFunction<? super O, D>) distanceQuery.getDistanceFunction();
+ if (!this.getDistanceFunction().equals(distanceFunction)) {
+ if (getLogger().isDebugging()) {
getLogger().debug("Distance function not supported by index - or 'equals' not implemented right!");
}
return null;
}
// Bulk is not yet supported
- for(Object hint : hints) {
- if(hint == DatabaseQuery.HINT_BULK) {
+ for (Object hint : hints) {
+ if (hint == DatabaseQuery.HINT_BULK) {
return null;
}
}
- AbstractMTree<O, S, ?, ?> idx = (AbstractMTree<O, S, ?, ?>) this;
- DistanceQuery<O, S> dq = distanceFunction.instantiate(relation);
- return MTreeQueryUtil.getKNNQuery(idx, dq, hints);
+ DistanceQuery<O, D> dq = distanceFunction.instantiate(relation);
+ return (KNNQuery<O, S>) MTreeQueryUtil.getKNNQuery(this, dq, hints);
}
@SuppressWarnings("unchecked")
@Override
public <S extends Distance<S>> RangeQuery<O, S> getRangeQuery(DistanceQuery<O, S> distanceQuery, Object... hints) {
// Query on the relation we index
- if(distanceQuery.getRelation() != relation) {
+ if (distanceQuery.getRelation() != relation) {
return null;
}
- DistanceFunction<? super O, S> distanceFunction = distanceQuery.getDistanceFunction();
- if(!this.distanceFunction.equals(distanceFunction)) {
- if(getLogger().isDebugging()) {
+ DistanceFunction<? super O, D> distanceFunction = (DistanceFunction<? super O, D>) distanceQuery.getDistanceFunction();
+ if (!this.getDistanceFunction().equals(distanceFunction)) {
+ if (getLogger().isDebugging()) {
getLogger().debug("Distance function not supported by index - or 'equals' not implemented right!");
}
return null;
}
// Bulk is not yet supported
- for(Object hint : hints) {
- if(hint == DatabaseQuery.HINT_BULK) {
+ for (Object hint : hints) {
+ if (hint == DatabaseQuery.HINT_BULK) {
return null;
}
}
- AbstractMTree<O, S, ?, ?> idx = (AbstractMTree<O, S, ?, ?>) this;
- DistanceQuery<O, S> dq = distanceFunction.instantiate(relation);
- return MTreeQueryUtil.getRangeQuery(idx, dq, hints);
+ DistanceQuery<O, D> dq = distanceFunction.instantiate(relation);
+ return (RangeQuery<O, S>) MTreeQueryUtil.getRangeQuery(this, dq, hints);
}
@SuppressWarnings("unchecked")
@Override
public <S extends Distance<S>> RKNNQuery<O, S> getRKNNQuery(DistanceQuery<O, S> distanceQuery, Object... hints) {
- DistanceFunction<? super O, S> distanceFunction = distanceQuery.getDistanceFunction();
- if(!this.getDistanceFunction().equals(distanceFunction)) {
- if(getLogger().isDebugging()) {
+ DistanceFunction<? super O, D> distanceFunction = (DistanceFunction<? super O, D>) distanceQuery.getDistanceFunction();
+ if (!this.getDistanceFunction().equals(distanceFunction)) {
+ if (getLogger().isDebugging()) {
getLogger().debug("Distance function not supported by index - or 'equals' not implemented right!");
}
return null;
}
// Bulk is not yet supported
- for(Object hint : hints) {
- if(hint == DatabaseQuery.HINT_BULK) {
+ for (Object hint : hints) {
+ if (hint == DatabaseQuery.HINT_BULK) {
return null;
}
}
- AbstractMkTree<O, S, ?, ?> idx = (AbstractMkTree<O, S, ?, ?>) this;
- DistanceQuery<O, S> dq = distanceFunction.instantiate(relation);
- return new MkTreeRKNNQuery<O, S>(idx, dq);
+ DistanceQuery<O, D> dq = distanceFunction.instantiate(relation);
+ return (RKNNQuery<O, S>) new MkTreeRKNNQuery<>(this, dq);
}
@Override
@@ -212,4 +174,4 @@ public class MkCoPTreeIndex<O, D extends NumberDistance<D, ?>> extends MkCoPTree
public String getShortName() {
return "mkcoptree";
}
-} \ No newline at end of file
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCoPTreeNode.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCoPTreeNode.java
index f2e4a114..79a9c6cc 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCoPTreeNode.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCoPTreeNode.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mkcop;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -38,7 +38,7 @@ import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTreeNode;
* @param <O> object type
* @param <D> distance type
*/
-class MkCoPTreeNode<O, D extends NumberDistance<D, ?>> extends AbstractMTreeNode<O, D, MkCoPTreeNode<O, D>, MkCoPEntry<D>> {
+class MkCoPTreeNode<O, D extends NumberDistance<D, ?>> extends AbstractMTreeNode<O, D, MkCoPTreeNode<O, D>, MkCoPEntry> {
/**
* Serial version UID
*/
@@ -77,13 +77,13 @@ class MkCoPTreeNode<O, D extends NumberDistance<D, ?>> extends AbstractMTreeNode
double y_kmax = Double.NEGATIVE_INFINITY;
for(int i = 0; i < getNumEntries(); i++) {
- MkCoPEntry<D> entry = getEntry(i);
+ MkCoPEntry entry = getEntry(i);
ApproximationLine approx = entry.getConservativeKnnDistanceApproximation();
k_0 = Math.min(approx.getK_0(), k_0);
}
for(int i = 0; i < getNumEntries(); i++) {
- MkCoPEntry<D> entry = getEntry(i);
+ MkCoPEntry entry = getEntry(i);
ApproximationLine approx = entry.getConservativeKnnDistanceApproximation();
double entry_y_1 = approx.getValueAt(k_0);
double entry_y_kmax = approx.getValueAt(k_max);
@@ -122,13 +122,13 @@ class MkCoPTreeNode<O, D extends NumberDistance<D, ?>> extends AbstractMTreeNode
double y_kmax = Double.POSITIVE_INFINITY;
for(int i = 0; i < getNumEntries(); i++) {
- MkCoPLeafEntry<D> entry = (MkCoPLeafEntry<D>) getEntry(i);
+ MkCoPLeafEntry entry = (MkCoPLeafEntry) getEntry(i);
ApproximationLine approx = entry.getProgressiveKnnDistanceApproximation();
k_0 = Math.max(approx.getK_0(), k_0);
}
for(int i = 0; i < getNumEntries(); i++) {
- MkCoPLeafEntry<D> entry = (MkCoPLeafEntry<D>) getEntry(i);
+ MkCoPLeafEntry entry = (MkCoPLeafEntry) getEntry(i);
ApproximationLine approx = entry.getProgressiveKnnDistanceApproximation();
y_1 = Math.min(approx.getValueAt(k_0), y_1);
y_kmax = Math.min(approx.getValueAt(k_max), y_kmax);
@@ -142,7 +142,7 @@ class MkCoPTreeNode<O, D extends NumberDistance<D, ?>> extends AbstractMTreeNode
}
@Override
- public void adjustEntry(MkCoPEntry<D> entry, DBID routingObjectID, D parentDistance, AbstractMTree<O, D, MkCoPTreeNode<O, D>, MkCoPEntry<D>> mTree) {
+ public void adjustEntry(MkCoPEntry entry, DBID routingObjectID, double parentDistance, AbstractMTree<O, D, MkCoPTreeNode<O, D>, MkCoPEntry, ?> mTree) {
super.adjustEntry(entry, routingObjectID, parentDistance, mTree);
// adjust conservative distance approximation
// int k_max = ((MkCoPTree<O,D>) mTree).getK_max();
@@ -150,10 +150,10 @@ class MkCoPTreeNode<O, D extends NumberDistance<D, ?>> extends AbstractMTreeNode
}
@Override
- protected void integrityCheckParameters(MkCoPEntry<D> parentEntry, MkCoPTreeNode<O, D> parent, int index, AbstractMTree<O, D, MkCoPTreeNode<O, D>, MkCoPEntry<D>> mTree) {
+ protected void integrityCheckParameters(MkCoPEntry parentEntry, MkCoPTreeNode<O, D> parent, int index, AbstractMTree<O, D, MkCoPTreeNode<O, D>, MkCoPEntry, ?> mTree) {
super.integrityCheckParameters(parentEntry, parent, index, mTree);
// test conservative approximation
- MkCoPEntry<D> entry = parent.getEntry(index);
+ MkCoPEntry entry = parent.getEntry(index);
int k_max = ((MkCoPTree<O, D>) mTree).getK_max();
ApproximationLine approx = conservativeKnnDistanceApproximation(k_max);
if(!entry.getConservativeKnnDistanceApproximation().equals(approx)) {
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCopTreeFactory.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCopTreeFactory.java
index 4ac96df3..6a39e92f 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCopTreeFactory.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCopTreeFactory.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mkcop;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -24,10 +24,11 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mkcop;
*/
import de.lmu.ifi.dbs.elki.database.relation.Relation;
-import de.lmu.ifi.dbs.elki.distance.distancefunction.DistanceFunction;
import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTreeFactory;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.MkTreeSettings;
import de.lmu.ifi.dbs.elki.persistent.PageFile;
+import de.lmu.ifi.dbs.elki.persistent.PageFileFactory;
import de.lmu.ifi.dbs.elki.utilities.ClassGenericsUtil;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.constraints.GreaterConstraint;
@@ -45,35 +46,26 @@ import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.IntParameter;
* @param <O> Object type
* @param <D> Distance type
*/
-public class MkCopTreeFactory<O, D extends NumberDistance<D, ?>> extends AbstractMTreeFactory<O, D, MkCoPTreeNode<O, D>, MkCoPEntry<D>, MkCoPTreeIndex<O, D>> {
+public class MkCopTreeFactory<O, D extends NumberDistance<D, ?>> extends AbstractMTreeFactory<O, D, MkCoPTreeNode<O, D>, MkCoPEntry, MkCoPTreeIndex<O, D>, MkTreeSettings<O, D, MkCoPTreeNode<O, D>, MkCoPEntry>> {
/**
* Parameter for k
*/
public static final OptionID K_ID = new OptionID("mkcop.k", "positive integer specifying the maximum number k of reverse k nearest neighbors to be supported.");
/**
- * Parameter k.
- */
- int k_max;
-
- /**
* Constructor.
- *
- * @param fileName
- * @param pageSize
- * @param cacheSize
- * @param distanceFunction
- * @param k_max
+ *
+ * @param pageFileFactory Data storage
+ * @param settings Tree settings
*/
- public MkCopTreeFactory(String fileName, int pageSize, long cacheSize, DistanceFunction<O, D> distanceFunction, int k_max) {
- super(fileName, pageSize, cacheSize, distanceFunction);
- this.k_max = k_max;
+ public MkCopTreeFactory(PageFileFactory<?> pageFileFactory, MkTreeSettings<O, D, MkCoPTreeNode<O, D>, MkCoPEntry> settings) {
+ super(pageFileFactory, settings);
}
@Override
public MkCoPTreeIndex<O, D> instantiate(Relation<O> relation) {
PageFile<MkCoPTreeNode<O, D>> pagefile = makePageFile(getNodeClass());
- return new MkCoPTreeIndex<O, D>(relation, pagefile, distanceFunction.instantiate(relation), distanceFunction, k_max);
+ return new MkCoPTreeIndex<>(relation, pagefile, settings);
}
protected Class<MkCoPTreeNode<O, D>> getNodeClass() {
@@ -87,22 +79,25 @@ public class MkCopTreeFactory<O, D extends NumberDistance<D, ?>> extends Abstrac
*
* @apiviz.exclude
*/
- public static class Parameterizer<O, D extends NumberDistance<D, ?>> extends AbstractMTreeFactory.Parameterizer<O, D> {
- protected int k_max = 0;
-
+ public static class Parameterizer<O, D extends NumberDistance<D, ?>> extends AbstractMTreeFactory.Parameterizer<O, D, MkCoPTreeNode<O, D>, MkCoPEntry, MkTreeSettings<O, D, MkCoPTreeNode<O, D>, MkCoPEntry>> {
@Override
protected void makeOptions(Parameterization config) {
super.makeOptions(config);
IntParameter k_maxP = new IntParameter(K_ID);
k_maxP.addConstraint(new GreaterConstraint(0));
if (config.grab(k_maxP)) {
- k_max = k_maxP.intValue();
+ settings.k_max = k_maxP.intValue();
}
}
@Override
protected MkCopTreeFactory<O, D> makeInstance() {
- return new MkCopTreeFactory<O, D>(fileName, pageSize, cacheSize, distanceFunction, k_max);
+ return new MkCopTreeFactory<>(pageFileFactory, settings);
+ }
+
+ @Override
+ protected MkTreeSettings<O, D, MkCoPTreeNode<O, D>, MkCoPEntry> makeSettings() {
+ return new MkTreeSettings<>();
}
}
-} \ No newline at end of file
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/package-info.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/package-info.java
index 516af071..c767c565 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/package-info.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/package-info.java
@@ -5,7 +5,7 @@
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
-Copyright (C) 2012
+Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxDirectoryEntry.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxDirectoryEntry.java
index 0781dcb1..b3e39ca0 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxDirectoryEntry.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxDirectoryEntry.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mkmax;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -28,7 +28,6 @@ import java.io.ObjectInput;
import java.io.ObjectOutput;
import de.lmu.ifi.dbs.elki.database.ids.DBID;
-import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeDirectoryEntry;
/**
@@ -37,19 +36,18 @@ import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeDirectoryEntry
* the underlying MkMax-Tree node.
*
* @author Elke Achtert
- * @param <D> the type of Distance used in the MkMaxTree
*/
-class MkMaxDirectoryEntry<D extends Distance<D>> extends MTreeDirectoryEntry<D> implements MkMaxEntry<D> {
+class MkMaxDirectoryEntry extends MTreeDirectoryEntry implements MkMaxEntry {
/**
* Serial version UID
*/
- private static final long serialVersionUID = 1;
+ private static final long serialVersionUID = 2;
/**
* The aggregated k-nearest neighbor distance of the underlying MkMax-Tree
* node.
*/
- private D knnDistance;
+ private double knnDistance;
/**
* Empty constructor for serialization purposes.
@@ -69,18 +67,18 @@ class MkMaxDirectoryEntry<D extends Distance<D>> extends MTreeDirectoryEntry<D>
* @param knnDistance the aggregated knn distance of the underlying MkMax-Tree
* node
*/
- public MkMaxDirectoryEntry(DBID objectID, D parentDistance, Integer nodeID, D coveringRadius, D knnDistance) {
+ public MkMaxDirectoryEntry(DBID objectID, double parentDistance, Integer nodeID, double coveringRadius, double knnDistance) {
super(objectID, parentDistance, nodeID, coveringRadius);
this.knnDistance = knnDistance;
}
@Override
- public D getKnnDistance() {
+ public double getKnnDistance() {
return knnDistance;
}
@Override
- public void setKnnDistance(D knnDistance) {
+ public void setKnnDistance(double knnDistance) {
this.knnDistance = knnDistance;
}
@@ -91,7 +89,7 @@ class MkMaxDirectoryEntry<D extends Distance<D>> extends MTreeDirectoryEntry<D>
@Override
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
- out.writeObject(knnDistance);
+ out.writeDouble(knnDistance);
}
/**
@@ -99,10 +97,9 @@ class MkMaxDirectoryEntry<D extends Distance<D>> extends MTreeDirectoryEntry<D>
* specified input stream.
*/
@Override
- @SuppressWarnings("unchecked")
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
- this.knnDistance = (D) in.readObject();
+ this.knnDistance = in.readDouble();
}
/**
@@ -113,20 +110,19 @@ class MkMaxDirectoryEntry<D extends Distance<D>> extends MTreeDirectoryEntry<D>
* MkMaxDirectoryEntry and has the same knnDistance as this entry.
*/
@Override
- @SuppressWarnings("unchecked")
public boolean equals(Object o) {
- if(this == o) {
+ if (this == o) {
return true;
}
- if(o == null || getClass() != o.getClass()) {
+ if (o == null || getClass() != o.getClass()) {
return false;
}
- if(!super.equals(o)) {
+ if (!super.equals(o)) {
return false;
}
- final MkMaxDirectoryEntry<D> that = (MkMaxDirectoryEntry<D>) o;
+ final MkMaxDirectoryEntry that = (MkMaxDirectoryEntry) o;
- return !(knnDistance != null ? !knnDistance.equals(that.knnDistance) : that.knnDistance != null);
+ return Double.compare(knnDistance, that.knnDistance) == 0;
}
-} \ No newline at end of file
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxEntry.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxEntry.java
index 0a7032f3..9e5133c9 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxEntry.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxEntry.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mkmax;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -23,30 +23,28 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mkmax;
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeEntry;
/**
* Defines the requirements for an entry in an
- * {@link de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mkmax.MkMaxTreeNode}.
- * Additionally to an entry in an M-Tree an MkMaxEntry holds the k-nearest neighbor distance of the underlying
- * data object or MkMax-Tree node.
- *
+ * {@link de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mkmax.MkMaxTreeNode}
+ * . Additionally to an entry in an M-Tree an MkMaxEntry holds the k-nearest
+ * neighbor distance of the underlying data object or MkMax-Tree node.
+ *
* @author Elke Achtert
- * @param <D> the type of Distance used in the MkMaxTree
*/
-interface MkMaxEntry<D extends Distance<D>> extends MTreeEntry<D> {
+interface MkMaxEntry extends MTreeEntry {
/**
* Returns the knn distance of the entry.
- *
+ *
* @return the knn distance of the entry
*/
- public D getKnnDistance();
+ public double getKnnDistance();
/**
* Sets the knn distance of the entry.
- *
+ *
* @param knnDistance the knn distance to be set
*/
- public void setKnnDistance(D knnDistance);
+ public void setKnnDistance(double knnDistance);
}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxLeafEntry.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxLeafEntry.java
index 29221fdc..d49f18ec 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxLeafEntry.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxLeafEntry.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mkmax;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -28,7 +28,6 @@ import java.io.ObjectInput;
import java.io.ObjectOutput;
import de.lmu.ifi.dbs.elki.database.ids.DBID;
-import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeLeafEntry;
/**
@@ -37,9 +36,8 @@ import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeLeafEntry;
* the underlying data object.
*
* @author Elke Achtert
- * @param <D> the type of Distance used in the MkMaxTree
*/
-class MkMaxLeafEntry<D extends Distance<D>> extends MTreeLeafEntry<D> implements MkMaxEntry<D> {
+class MkMaxLeafEntry extends MTreeLeafEntry implements MkMaxEntry {
/**
* Serial version number
*/
@@ -48,7 +46,7 @@ class MkMaxLeafEntry<D extends Distance<D>> extends MTreeLeafEntry<D> implements
/**
* The k-nearest neighbor distance of the underlying data object.
*/
- private D knnDistance;
+ private double knnDistance;
/**
* Empty constructor for serialization purposes.
@@ -65,18 +63,18 @@ class MkMaxLeafEntry<D extends Distance<D>> extends MTreeLeafEntry<D> implements
* parent's routing object
* @param knnDistance the knn distance of the underlying data object
*/
- public MkMaxLeafEntry(DBID objectID, D parentDistance, D knnDistance) {
+ public MkMaxLeafEntry(DBID objectID, double parentDistance, double knnDistance) {
super(objectID, parentDistance);
this.knnDistance = knnDistance;
}
@Override
- public D getKnnDistance() {
+ public double getKnnDistance() {
return knnDistance;
}
@Override
- public void setKnnDistance(D knnDistance) {
+ public void setKnnDistance(double knnDistance) {
this.knnDistance = knnDistance;
}
@@ -95,10 +93,9 @@ class MkMaxLeafEntry<D extends Distance<D>> extends MTreeLeafEntry<D> implements
* specified input stream.
*/
@Override
- @SuppressWarnings("unchecked")
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
- this.knnDistance = (D) in.readObject();
+ this.knnDistance = in.readDouble();
}
/**
@@ -109,20 +106,19 @@ class MkMaxLeafEntry<D extends Distance<D>> extends MTreeLeafEntry<D> implements
* and has the same knnDistance as this entry.
*/
@Override
- @SuppressWarnings("unchecked")
public boolean equals(Object o) {
- if(this == o) {
+ if (this == o) {
return true;
}
- if(o == null || getClass() != o.getClass()) {
+ if (o == null || getClass() != o.getClass()) {
return false;
}
- if(!super.equals(o)) {
+ if (!super.equals(o)) {
return false;
}
- final MkMaxLeafEntry<D> that = (MkMaxLeafEntry<D>) o;
+ final MkMaxLeafEntry that = (MkMaxLeafEntry) o;
- return !(knnDistance != null ? !knnDistance.equals(that.knnDistance) : that.knnDistance != null);
+ return Double.compare(knnDistance, that.knnDistance) == 0;
}
-} \ No newline at end of file
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxTree.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxTree.java
index 36f9bbf1..c1f87f20 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxTree.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxTree.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mkmax;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -31,27 +31,25 @@ import de.lmu.ifi.dbs.elki.database.ids.DBIDIter;
import de.lmu.ifi.dbs.elki.database.ids.DBIDRef;
import de.lmu.ifi.dbs.elki.database.ids.DBIDUtil;
import de.lmu.ifi.dbs.elki.database.ids.ModifiableDBIDs;
-import de.lmu.ifi.dbs.elki.database.query.distance.DistanceQuery;
-import de.lmu.ifi.dbs.elki.distance.DistanceUtil;
-import de.lmu.ifi.dbs.elki.distance.distancefunction.DistanceFunction;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.DistanceDBIDResult;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.DistanceDBIDResultIter;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.GenericDistanceDBIDList;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.KNNHeap;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.KNNResult;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.KNNUtil;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.ModifiableDistanceDBIDResult;
-import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
-import de.lmu.ifi.dbs.elki.index.tree.DistanceEntry;
+import de.lmu.ifi.dbs.elki.database.ids.distance.DistanceDBIDList;
+import de.lmu.ifi.dbs.elki.database.ids.distance.DistanceDBIDListIter;
+import de.lmu.ifi.dbs.elki.database.ids.distance.KNNHeap;
+import de.lmu.ifi.dbs.elki.database.ids.distance.KNNList;
+import de.lmu.ifi.dbs.elki.database.ids.distance.ModifiableDistanceDBIDList;
+import de.lmu.ifi.dbs.elki.database.ids.generic.GenericDistanceDBIDList;
+import de.lmu.ifi.dbs.elki.database.relation.Relation;
+import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.AbstractMkTreeUnified;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.MkTreeSettings;
import de.lmu.ifi.dbs.elki.logging.Logging;
+import de.lmu.ifi.dbs.elki.persistent.ByteArrayUtil;
import de.lmu.ifi.dbs.elki.persistent.PageFile;
-import de.lmu.ifi.dbs.elki.utilities.QueryStatistic;
+import de.lmu.ifi.dbs.elki.utilities.pairs.DoubleIntPair;
/**
* MkMaxTree is a metrical index structure based on the concepts of the M-Tree
* supporting efficient processing of reverse k nearest neighbor queries for
- * parameter k <= k_max. The k-nearest neigbor distance for k = k_max is stored
+ * parameter k <= k_max. The k-nearest neighbor distance for k = k_max is stored
* in each entry of a node.
*
* @author Elke Achtert
@@ -61,49 +59,44 @@ import de.lmu.ifi.dbs.elki.utilities.QueryStatistic;
* @param <O> the type of DatabaseObject to be stored in the MkMaxTree
* @param <D> the type of Distance used in the MkMaxTree
*/
-public class MkMaxTree<O, D extends Distance<D>> extends AbstractMkTreeUnified<O, D, MkMaxTreeNode<O, D>, MkMaxEntry<D>> {
+public class MkMaxTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTreeUnified<O, D, MkMaxTreeNode<O, D>, MkMaxEntry, MkTreeSettings<O, D, MkMaxTreeNode<O, D>, MkMaxEntry>> {
/**
* The logger for this class.
*/
private static final Logging LOG = Logging.getLogger(MkMaxTree.class);
/**
- * Provides some statistics about performed reverse knn-queries.
- */
- private QueryStatistic rkNNStatistics = new QueryStatistic();
-
- /**
* Constructor.
*
+ * @param relation Relation to index
* @param pagefile Page file
- * @param distanceQuery Distance query
- * @param distanceFunction Distance function
- * @param k_max Maximum value for k
+ * @param settings Tree settings
*/
- public MkMaxTree(PageFile<MkMaxTreeNode<O, D>> pagefile, DistanceQuery<O, D> distanceQuery, DistanceFunction<O, D> distanceFunction, int k_max) {
- super(pagefile, distanceQuery, distanceFunction, k_max);
+ public MkMaxTree(Relation<O> relation, PageFile<MkMaxTreeNode<O, D>> pagefile, MkTreeSettings<O, D, MkMaxTreeNode<O, D>, MkMaxEntry> settings) {
+ super(relation, pagefile, settings);
}
/**
* Performs a reverse k-nearest neighbor query for the given object ID. In the
* first step the candidates are chosen by performing a reverse k-nearest
- * neighbor query with k = {@link #k_max}. Then these candidates are refined
+ * neighbor query with k = {@link #getKmax()}. Then these candidates are refined
* in a second step.
*/
@Override
- public DistanceDBIDResult<D> reverseKNNQuery(DBIDRef id, int k) {
- if(k > this.getKmax()) {
+ public DistanceDBIDList<D> reverseKNNQuery(DBIDRef id, int k) {
+ if (k > this.getKmax()) {
throw new IllegalArgumentException("Parameter k has to be equal or less than " + "parameter k of the MkMax-Tree!");
}
// get the candidates
- GenericDistanceDBIDList<D> candidates = new GenericDistanceDBIDList<D>();
+ GenericDistanceDBIDList<D> candidates = new GenericDistanceDBIDList<>();
doReverseKNNQuery(id, getRoot(), null, candidates);
- if(k == this.getKmax()) {
+ if (k == this.getKmax()) {
candidates.sort();
- rkNNStatistics.addTrueHits(candidates.size());
- rkNNStatistics.addResults(candidates.size());
+ // FIXME: re-add statistics.
+ // rkNNStatistics.addTrueHits(candidates.size());
+ // rkNNStatistics.addResults(candidates.size());
return candidates;
}
@@ -112,49 +105,34 @@ public class MkMaxTree<O, D extends Distance<D>> extends AbstractMkTreeUnified<O
for (DBIDIter candidate = candidates.iter(); candidate.valid(); candidate.advance()) {
candidateIDs.add(candidate);
}
- Map<DBID, KNNResult<D>> knnLists = batchNN(getRoot(), candidateIDs, k);
+ Map<DBID, KNNList<D>> knnLists = batchNN(getRoot(), candidateIDs, k);
- GenericDistanceDBIDList<D> result = new GenericDistanceDBIDList<D>();
+ GenericDistanceDBIDList<D> result = new GenericDistanceDBIDList<>();
for (DBIDIter iter = candidateIDs.iter(); iter.valid(); iter.advance()) {
DBID cid = DBIDUtil.deref(iter);
- KNNResult<D> cands = knnLists.get(cid);
- for (DistanceDBIDResultIter<D> iter2 = cands.iter(); iter2.valid(); iter2.advance()) {
- if(DBIDUtil.equal(id, iter2)) {
+ KNNList<D> cands = knnLists.get(cid);
+ for (DistanceDBIDListIter<D> iter2 = cands.iter(); iter2.valid(); iter2.advance()) {
+ if (DBIDUtil.equal(id, iter2)) {
result.add(iter2.getDistance(), cid);
break;
}
}
}
- rkNNStatistics.addResults(result.size());
- rkNNStatistics.addCandidates(candidates.size());
+ // FIXME: re-add statistics.
+ // rkNNStatistics.addResults(result.size());
+ // rkNNStatistics.addCandidates(candidates.size());
result.sort();
return result;
}
/**
- * Returns the statistic for performed rknn queries.
- *
- * @return the statistic for performed rknn queries
- */
- public QueryStatistic getRkNNStatistics() {
- return rkNNStatistics;
- }
-
- /**
- * Clears the values of the statistic for performed rknn queries
- */
- public void clearRkNNStatistics() {
- rkNNStatistics.clear();
- }
-
- /**
* Adapts the knn distances before insertion of the specified entry.
*
*/
@Override
- protected void preInsert(MkMaxEntry<D> entry) {
- KNNHeap<D> knns_o = KNNUtil.newHeap(distanceFunction, getKmax());
+ protected void preInsert(MkMaxEntry entry) {
+ KNNHeap<D> knns_o = DBIDUtil.newHeap(getDistanceFactory(), getKmax());
preInsert(entry, getRootEntry(), knns_o);
}
@@ -162,21 +140,20 @@ public class MkMaxTree<O, D extends Distance<D>> extends AbstractMkTreeUnified<O
* Adjusts the knn distance in the subtree of the specified root entry.
*/
@Override
- protected void kNNdistanceAdjustment(MkMaxEntry<D> entry, Map<DBID, KNNResult<D>> knnLists) {
+ protected void kNNdistanceAdjustment(MkMaxEntry entry, Map<DBID, KNNList<D>> knnLists) {
MkMaxTreeNode<O, D> node = getNode(entry);
- D knnDist_node = getDistanceQuery().nullDistance();
- if(node.isLeaf()) {
- for(int i = 0; i < node.getNumEntries(); i++) {
- MkMaxEntry<D> leafEntry = node.getEntry(i);
- leafEntry.setKnnDistance(knnLists.get(leafEntry.getRoutingObjectID()).getKNNDistance());
- knnDist_node = DistanceUtil.max(knnDist_node, leafEntry.getKnnDistance());
+ double knnDist_node = 0.;
+ if (node.isLeaf()) {
+ for (int i = 0; i < node.getNumEntries(); i++) {
+ MkMaxEntry leafEntry = node.getEntry(i);
+ leafEntry.setKnnDistance(knnLists.get(leafEntry.getRoutingObjectID()).getKNNDistance().doubleValue());
+ knnDist_node = Math.max(knnDist_node, leafEntry.getKnnDistance());
}
- }
- else {
- for(int i = 0; i < node.getNumEntries(); i++) {
- MkMaxEntry<D> dirEntry = node.getEntry(i);
+ } else {
+ for (int i = 0; i < node.getNumEntries(); i++) {
+ MkMaxEntry dirEntry = node.getEntry(i);
kNNdistanceAdjustment(dirEntry, knnLists);
- knnDist_node = DistanceUtil.max(knnDist_node, dirEntry.getKnnDistance());
+ knnDist_node = Math.max(knnDist_node, dirEntry.getKnnDistance());
}
}
entry.setKnnDistance(knnDist_node);
@@ -184,22 +161,22 @@ public class MkMaxTree<O, D extends Distance<D>> extends AbstractMkTreeUnified<O
/**
* Performs a reverse k-nearest neighbor query in the specified subtree for
- * the given query object with k = {@link #k_max}. It recursively traverses
+ * the given query object with k = {@link #getKmax()}. It recursively traverses
* all paths from the specified node, which cannot be excluded from leading to
- * qualififying objects.
+ * qualifying objects.
*
* @param q the id of the query object
* @param node the node of the subtree on which the query is performed
* @param node_entry the entry representing the node
* @param result the list for the query result
*/
- private void doReverseKNNQuery(DBIDRef q, MkMaxTreeNode<O, D> node, MkMaxEntry<D> node_entry, ModifiableDistanceDBIDResult<D> result) {
+ private void doReverseKNNQuery(DBIDRef q, MkMaxTreeNode<O, D> node, MkMaxEntry node_entry, ModifiableDistanceDBIDList<D> result) {
// data node
- if(node.isLeaf()) {
- for(int i = 0; i < node.getNumEntries(); i++) {
- MkMaxEntry<D> entry = node.getEntry(i);
- D distance = getDistanceQuery().distance(entry.getRoutingObjectID(), q);
- if(distance.compareTo(entry.getKnnDistance()) <= 0) {
+ if (node.isLeaf()) {
+ for (int i = 0; i < node.getNumEntries(); i++) {
+ MkMaxEntry entry = node.getEntry(i);
+ D distance = distance(entry.getRoutingObjectID(), q);
+ if (distance.doubleValue() <= entry.getKnnDistance()) {
result.add(distance, entry.getRoutingObjectID());
}
}
@@ -207,14 +184,14 @@ public class MkMaxTree<O, D extends Distance<D>> extends AbstractMkTreeUnified<O
// directory node
else {
- for(int i = 0; i < node.getNumEntries(); i++) {
- MkMaxEntry<D> entry = node.getEntry(i);
- D node_knnDist = node_entry != null ? node_entry.getKnnDistance() : getDistanceQuery().infiniteDistance();
+ for (int i = 0; i < node.getNumEntries(); i++) {
+ MkMaxEntry entry = node.getEntry(i);
+ double node_knnDist = node_entry != null ? node_entry.getKnnDistance() : Double.POSITIVE_INFINITY;
- D distance = getDistanceQuery().distance(entry.getRoutingObjectID(), q);
- D minDist = entry.getCoveringRadius().compareTo(distance) > 0 ? getDistanceQuery().nullDistance() : distance.minus(entry.getCoveringRadius());
+ double distance = distance(entry.getRoutingObjectID(), q).doubleValue();
+ double minDist = (entry.getCoveringRadius() > distance) ? 0.0 : distance - entry.getCoveringRadius();
- if(minDist.compareTo(node_knnDist) <= 0) {
+ if (minDist <= node_knnDist) {
MkMaxTreeNode<O, D> childNode = getNode(entry);
doReverseKNNQuery(q, childNode, entry, result);
}
@@ -226,77 +203,76 @@ public class MkMaxTree<O, D extends Distance<D>> extends AbstractMkTreeUnified<O
* Adapts the knn distances before insertion of entry q.
*
* @param q the entry to be inserted
- * @param nodeEntry the entry representing the root of thge current subtree
+ * @param nodeEntry the entry representing the root of the current subtree
* @param knns_q the knns of q
*/
- private void preInsert(MkMaxEntry<D> q, MkMaxEntry<D> nodeEntry, KNNHeap<D> knns_q) {
- if(LOG.isDebugging()) {
+ private void preInsert(MkMaxEntry q, MkMaxEntry nodeEntry, KNNHeap<D> knns_q) {
+ if (LOG.isDebugging()) {
LOG.debugFine("preInsert " + q + " - " + nodeEntry + "\n");
}
- D knnDist_q = knns_q.getKNNDistance();
+ double knnDist_q = knns_q.getKNNDistance().doubleValue();
MkMaxTreeNode<O, D> node = getNode(nodeEntry);
- D knnDist_node = getDistanceQuery().nullDistance();
+ double knnDist_node = 0.;
// leaf node
- if(node.isLeaf()) {
- for(int i = 0; i < node.getNumEntries(); i++) {
- MkMaxEntry<D> p = node.getEntry(i);
- D dist_pq = getDistanceQuery().distance(p.getRoutingObjectID(), q.getRoutingObjectID());
+ if (node.isLeaf()) {
+ for (int i = 0; i < node.getNumEntries(); i++) {
+ MkMaxEntry p = node.getEntry(i);
+ D dist_pq = distance(p.getRoutingObjectID(), q.getRoutingObjectID());
// p is nearer to q than the farthest kNN-candidate of q
// ==> p becomes a knn-candidate
- if(dist_pq.compareTo(knnDist_q) <= 0) {
+ if (dist_pq.doubleValue() <= knnDist_q) {
knns_q.add(dist_pq, p.getRoutingObjectID());
- if(knns_q.size() >= getKmax()) {
- knnDist_q = knns_q.getKNNDistance();
+ if (knns_q.size() >= getKmax()) {
+ knnDist_q = knns_q.getKNNDistance().doubleValue();
q.setKnnDistance(knnDist_q);
}
}
// p is nearer to q than to its farthest knn-candidate
// q becomes knn of p
- if(dist_pq.compareTo(p.getKnnDistance()) <= 0) {
- KNNResult<D> knns_p = knnq.getKNNForDBID(p.getRoutingObjectID(), getKmax() - 1);
+ if (dist_pq.doubleValue() <= p.getKnnDistance()) {
+ KNNList<D> knns_p = knnq.getKNNForDBID(p.getRoutingObjectID(), getKmax() - 1);
- if(knns_p.size() + 1 < getKmax()) {
- p.setKnnDistance(getDistanceQuery().undefinedDistance());
- }
- else {
- D knnDist_p = DistanceUtil.max(dist_pq, knns_p.getKNNDistance());
+ if (knns_p.size() + 1 < getKmax()) {
+ p.setKnnDistance(Double.NaN);
+ } else {
+ double knnDist_p = Math.max(dist_pq.doubleValue(), knns_p.getKNNDistance().doubleValue());
p.setKnnDistance(knnDist_p);
}
}
- knnDist_node = DistanceUtil.max(knnDist_node, p.getKnnDistance());
+ knnDist_node = Math.max(knnDist_node, p.getKnnDistance());
}
}
// directory node
else {
- List<DistanceEntry<D, MkMaxEntry<D>>> entries = getSortedEntries(node, q.getRoutingObjectID());
- for(DistanceEntry<D, MkMaxEntry<D>> distEntry : entries) {
- MkMaxEntry<D> dirEntry = distEntry.getEntry();
- D entry_knnDist = dirEntry.getKnnDistance();
+ List<DoubleIntPair> entries = getSortedEntries(node, q.getRoutingObjectID());
+ for (DoubleIntPair distEntry : entries) {
+ MkMaxEntry dirEntry = node.getEntry(distEntry.second);
+ double entry_knnDist = dirEntry.getKnnDistance();
- if(distEntry.getDistance().compareTo(entry_knnDist) < 0 || distEntry.getDistance().compareTo(knnDist_q) < 0) {
+ if (distEntry.second < entry_knnDist || distEntry.second < knnDist_q) {
preInsert(q, dirEntry, knns_q);
- knnDist_q = knns_q.getKNNDistance();
+ knnDist_q = knns_q.getKNNDistance().doubleValue();
}
- knnDist_node = DistanceUtil.max(knnDist_node, dirEntry.getKnnDistance());
+ knnDist_node = Math.max(knnDist_node, dirEntry.getKnnDistance());
}
}
- if(LOG.isDebugging()) {
+ if (LOG.isDebugging()) {
LOG.debugFine(nodeEntry + "set knn dist " + knnDist_node);
}
nodeEntry.setKnnDistance(knnDist_node);
}
@Override
- protected void initializeCapacities(MkMaxEntry<D> exampleLeaf) {
- int distanceSize = exampleLeaf.getParentDistance().externalizableSize();
+ protected void initializeCapacities(MkMaxEntry exampleLeaf) {
+ int distanceSize = ByteArrayUtil.SIZE_DOUBLE; // exampleLeaf.getParentDistance().externalizableSize();
// overhead = index(4), numEntries(4), id(4), isLeaf(0.125)
double overhead = 12.125;
- if(getPageSize() - overhead < 0) {
+ if (getPageSize() - overhead < 0) {
throw new RuntimeException("Node size of " + getPageSize() + " Bytes is chosen too small!");
}
@@ -304,11 +280,11 @@ public class MkMaxTree<O, D extends Distance<D>> extends AbstractMkTreeUnified<O
// coveringRadius + parentDistance + knnDistance) + 1
dirCapacity = (int) (getPageSize() - overhead) / (4 + 4 + 3 * distanceSize) + 1;
- if(dirCapacity <= 1) {
+ if (dirCapacity <= 1) {
throw new RuntimeException("Node size of " + getPageSize() + " Bytes is chosen too small!");
}
- if(dirCapacity < 10) {
+ if (dirCapacity < 10) {
LOG.warning("Page size is choosen too small! Maximum number of entries " + "in a directory node = " + (dirCapacity - 1));
}
@@ -317,11 +293,11 @@ public class MkMaxTree<O, D extends Distance<D>> extends AbstractMkTreeUnified<O
// knnDistance) + 1
leafCapacity = (int) (getPageSize() - overhead) / (4 + 2 * distanceSize) + 1;
- if(leafCapacity <= 1) {
+ if (leafCapacity <= 1) {
throw new RuntimeException("Node size of " + getPageSize() + " Bytes is chosen too small!");
}
- if(leafCapacity < 10) {
+ if (leafCapacity < 10) {
LOG.warning("Page size is choosen too small! Maximum number of entries " + "in a leaf node = " + (leafCapacity - 1));
}
}
@@ -331,7 +307,7 @@ public class MkMaxTree<O, D extends Distance<D>> extends AbstractMkTreeUnified<O
*/
@Override
protected MkMaxTreeNode<O, D> createNewLeafNode() {
- return new MkMaxTreeNode<O, D>(leafCapacity, true);
+ return new MkMaxTreeNode<>(leafCapacity, true);
}
/**
@@ -339,28 +315,28 @@ public class MkMaxTree<O, D extends Distance<D>> extends AbstractMkTreeUnified<O
*/
@Override
protected MkMaxTreeNode<O, D> createNewDirectoryNode() {
- return new MkMaxTreeNode<O, D>(dirCapacity, false);
+ return new MkMaxTreeNode<>(dirCapacity, false);
}
/**
* @return a new MkMaxDirectoryEntry representing the specified node
*/
@Override
- protected MkMaxEntry<D> createNewDirectoryEntry(MkMaxTreeNode<O, D> node, DBID routingObjectID, D parentDistance) {
- return new MkMaxDirectoryEntry<D>(routingObjectID, parentDistance, node.getPageID(), node.coveringRadius(routingObjectID, this), node.kNNDistance(getDistanceQuery()));
+ protected MkMaxEntry createNewDirectoryEntry(MkMaxTreeNode<O, D> node, DBID routingObjectID, double parentDistance) {
+ return new MkMaxDirectoryEntry(routingObjectID, parentDistance, node.getPageID(), node.coveringRadius(routingObjectID, this), node.kNNDistance());
}
/**
* @return a new MkMaxDirectoryEntry by calling
- * <code>new MkMaxDirectoryEntry<D>(null, null, 0, null)</code>
+ * <code>new MkMaxDirectoryEntry(null, null, 0, null)</code>
*/
@Override
- protected MkMaxEntry<D> createRootEntry() {
- return new MkMaxDirectoryEntry<D>(null, null, 0, null, null);
+ protected MkMaxEntry createRootEntry() {
+ return new MkMaxDirectoryEntry(null, 0., 0, 0., 0.);
}
@Override
protected Logging getLogger() {
return LOG;
}
-} \ No newline at end of file
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxTreeFactory.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxTreeFactory.java
index 7e9a7753..a03006f4 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxTreeFactory.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxTreeFactory.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mkmax;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -24,10 +24,11 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mkmax;
*/
import de.lmu.ifi.dbs.elki.database.relation.Relation;
-import de.lmu.ifi.dbs.elki.distance.distancefunction.DistanceFunction;
-import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
+import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.AbstractMkTreeUnifiedFactory;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.MkTreeSettings;
import de.lmu.ifi.dbs.elki.persistent.PageFile;
+import de.lmu.ifi.dbs.elki.persistent.PageFileFactory;
import de.lmu.ifi.dbs.elki.utilities.ClassGenericsUtil;
/**
@@ -37,28 +38,25 @@ import de.lmu.ifi.dbs.elki.utilities.ClassGenericsUtil;
*
* @apiviz.stereotype factory
* @apiviz.uses MkMaxTreeIndex oneway - - «create»
- *
+ *
* @param <O> Object type
* @param <D> Distance type
*/
-public class MkMaxTreeFactory<O, D extends Distance<D>> extends AbstractMkTreeUnifiedFactory<O, D, MkMaxTreeNode<O, D>, MkMaxEntry<D>, MkMaxTreeIndex<O, D>> {
+public class MkMaxTreeFactory<O, D extends NumberDistance<D, ?>> extends AbstractMkTreeUnifiedFactory<O, D, MkMaxTreeNode<O, D>, MkMaxEntry, MkMaxTreeIndex<O, D>, MkTreeSettings<O, D, MkMaxTreeNode<O, D>, MkMaxEntry>> {
/**
* Constructor.
- *
- * @param fileName
- * @param pageSize
- * @param cacheSize
- * @param distanceFunction
- * @param k_max
+ *
+ * @param pageFileFactory Data storage
+ * @param settings Tree settings
*/
- public MkMaxTreeFactory(String fileName, int pageSize, long cacheSize, DistanceFunction<O, D> distanceFunction, int k_max) {
- super(fileName, pageSize, cacheSize, distanceFunction, k_max);
+ public MkMaxTreeFactory(PageFileFactory<?> pageFileFactory, MkTreeSettings<O, D, MkMaxTreeNode<O, D>, MkMaxEntry> settings) {
+ super(pageFileFactory, settings);
}
@Override
public MkMaxTreeIndex<O, D> instantiate(Relation<O> relation) {
PageFile<MkMaxTreeNode<O, D>> pagefile = makePageFile(getNodeClass());
- return new MkMaxTreeIndex<O, D>(relation, pagefile, distanceFunction.instantiate(relation), distanceFunction, k_max);
+ return new MkMaxTreeIndex<>(relation, pagefile, settings);
}
protected Class<MkMaxTreeNode<O, D>> getNodeClass() {
@@ -72,10 +70,15 @@ public class MkMaxTreeFactory<O, D extends Distance<D>> extends AbstractMkTreeUn
*
* @apiviz.exclude
*/
- public static class Parameterizer<O, D extends Distance<D>> extends AbstractMkTreeUnifiedFactory.Parameterizer<O, D> {
+ public static class Parameterizer<O, D extends NumberDistance<D, ?>> extends AbstractMkTreeUnifiedFactory.Parameterizer<O, D, MkMaxTreeNode<O, D>, MkMaxEntry, MkTreeSettings<O, D, MkMaxTreeNode<O, D>, MkMaxEntry>> {
@Override
protected MkMaxTreeFactory<O, D> makeInstance() {
- return new MkMaxTreeFactory<O, D>(fileName, pageSize, cacheSize, distanceFunction, k_max);
+ return new MkMaxTreeFactory<>(pageFileFactory, settings);
+ }
+
+ @Override
+ protected MkTreeSettings<O, D, MkMaxTreeNode<O, D>, MkMaxEntry> makeSettings() {
+ return new MkTreeSettings<>();
}
}
-} \ No newline at end of file
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxTreeIndex.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxTreeIndex.java
index 0bd31dca..482c86eb 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxTreeIndex.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxTreeIndex.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mkmax;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -31,6 +31,7 @@ import de.lmu.ifi.dbs.elki.database.ids.DBIDIter;
import de.lmu.ifi.dbs.elki.database.ids.DBIDRef;
import de.lmu.ifi.dbs.elki.database.ids.DBIDUtil;
import de.lmu.ifi.dbs.elki.database.ids.DBIDs;
+import de.lmu.ifi.dbs.elki.database.ids.distance.KNNList;
import de.lmu.ifi.dbs.elki.database.query.DatabaseQuery;
import de.lmu.ifi.dbs.elki.database.query.distance.DistanceQuery;
import de.lmu.ifi.dbs.elki.database.query.knn.KNNQuery;
@@ -38,68 +39,72 @@ import de.lmu.ifi.dbs.elki.database.query.range.RangeQuery;
import de.lmu.ifi.dbs.elki.database.query.rknn.RKNNQuery;
import de.lmu.ifi.dbs.elki.database.relation.Relation;
import de.lmu.ifi.dbs.elki.distance.distancefunction.DistanceFunction;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.KNNResult;
import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
+import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
+import de.lmu.ifi.dbs.elki.index.DynamicIndex;
import de.lmu.ifi.dbs.elki.index.KNNIndex;
import de.lmu.ifi.dbs.elki.index.RKNNIndex;
import de.lmu.ifi.dbs.elki.index.RangeIndex;
-import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTree;
-import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.AbstractMkTreeUnified;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.MkTreeSettings;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.query.MTreeQueryUtil;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.query.MkTreeRKNNQuery;
import de.lmu.ifi.dbs.elki.persistent.PageFile;
import de.lmu.ifi.dbs.elki.utilities.exceptions.ExceptionMessages;
+import de.lmu.ifi.dbs.elki.utilities.exceptions.NotImplementedException;
/**
* MkMax tree
*
* @author Elke Achtert
- *
+ *
* @param <O> Object type
* @param <D> Distance type
*/
-public class MkMaxTreeIndex<O, D extends Distance<D>> extends MkMaxTree<O, D> implements RangeIndex<O>, KNNIndex<O>, RKNNIndex<O> {
+public class MkMaxTreeIndex<O, D extends NumberDistance<D, ?>> extends MkMaxTree<O, D> implements RangeIndex<O>, KNNIndex<O>, RKNNIndex<O>, DynamicIndex {
/**
* Relation indexed.
*/
private Relation<O> relation;
-
+
/**
* Constructor.
*
* @param relation Relation
* @param pagefile Page file
- * @param distanceQuery Distance query
- * @param distanceFunction Distance function
- * @param k_max Maximum value for k
+ * @param settings Tree settings
*/
- public MkMaxTreeIndex(Relation<O> relation, PageFile<MkMaxTreeNode<O, D>> pagefile, DistanceQuery<O, D> distanceQuery, DistanceFunction<O, D> distanceFunction, int k_max) {
- super(pagefile, distanceQuery, distanceFunction, k_max);
+ public MkMaxTreeIndex(Relation<O> relation, PageFile<MkMaxTreeNode<O, D>> pagefile, MkTreeSettings<O, D, MkMaxTreeNode<O, D>, MkMaxEntry> settings) {
+ super(relation, pagefile, settings);
this.relation = relation;
- this.initialize();
}
/**
* @return a new MkMaxLeafEntry representing the specified data object
*/
- protected MkMaxLeafEntry<D> createNewLeafEntry(DBID id, O object, D parentDistance) {
- KNNResult<D> knns = knnq.getKNNForObject(object, getKmax() - 1);
- D knnDistance = knns.getKNNDistance();
- return new MkMaxLeafEntry<D>(id, parentDistance, knnDistance);
+ protected MkMaxLeafEntry createNewLeafEntry(DBID id, O object, double parentDistance) {
+ KNNList<D> knns = knnq.getKNNForObject(object, getKmax() - 1);
+ double knnDistance = knns.getKNNDistance().doubleValue();
+ return new MkMaxLeafEntry(id, parentDistance, knnDistance);
+ }
+
+ @Override
+ public void initialize() {
+ super.initialize();
+ insertAll(relation.getDBIDs());
}
@Override
public void insert(DBIDRef id) {
- insert(createNewLeafEntry(DBIDUtil.deref(id), relation.get(id), getDistanceFactory().undefinedDistance()), false);
+ insert(createNewLeafEntry(DBIDUtil.deref(id), relation.get(id), Double.NaN), false);
}
@Override
public void insertAll(DBIDs ids) {
- List<MkMaxEntry<D>> objs = new ArrayList<MkMaxEntry<D>>(ids.size());
+ List<MkMaxEntry> objs = new ArrayList<>(ids.size());
for (DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) {
DBID id = DBIDUtil.deref(iter);
final O object = relation.get(id);
- objs.add(createNewLeafEntry(id, object, getDistanceFactory().undefinedDistance()));
+ objs.add(createNewLeafEntry(id, object, Double.NaN));
}
insertAll(objs);
}
@@ -113,7 +118,7 @@ public class MkMaxTreeIndex<O, D extends Distance<D>> extends MkMaxTree<O, D> im
*/
@Override
public final boolean delete(DBIDRef id) {
- throw new UnsupportedOperationException(ExceptionMessages.UNSUPPORTED_NOT_YET);
+ throw new NotImplementedException(ExceptionMessages.UNSUPPORTED_NOT_YET);
}
/**
@@ -125,78 +130,75 @@ public class MkMaxTreeIndex<O, D extends Distance<D>> extends MkMaxTree<O, D> im
*/
@Override
public void deleteAll(DBIDs ids) {
- throw new UnsupportedOperationException(ExceptionMessages.UNSUPPORTED_NOT_YET);
+ throw new NotImplementedException(ExceptionMessages.UNSUPPORTED_NOT_YET);
}
@SuppressWarnings("unchecked")
@Override
public <S extends Distance<S>> KNNQuery<O, S> getKNNQuery(DistanceQuery<O, S> distanceQuery, Object... hints) {
// Query on the relation we index
- if(distanceQuery.getRelation() != relation) {
+ if (distanceQuery.getRelation() != relation) {
return null;
}
- DistanceFunction<? super O, S> distanceFunction = distanceQuery.getDistanceFunction();
- if(!this.distanceFunction.equals(distanceFunction)) {
- if(getLogger().isDebugging()) {
+ DistanceFunction<? super O, D> distanceFunction = (DistanceFunction<? super O, D>) distanceQuery.getDistanceFunction();
+ if (!this.getDistanceFunction().equals(distanceFunction)) {
+ if (getLogger().isDebugging()) {
getLogger().debug("Distance function not supported by index - or 'equals' not implemented right!");
}
return null;
}
// Bulk is not yet supported
- for(Object hint : hints) {
- if(hint == DatabaseQuery.HINT_BULK) {
+ for (Object hint : hints) {
+ if (hint == DatabaseQuery.HINT_BULK) {
return null;
}
}
- AbstractMTree<O, S, ?, ?> idx = (AbstractMTree<O, S, ?, ?>) this;
- DistanceQuery<O, S> dq = distanceFunction.instantiate(relation);
- return MTreeQueryUtil.getKNNQuery(idx, dq, hints);
+ DistanceQuery<O, D> dq = distanceFunction.instantiate(relation);
+ return (KNNQuery<O, S>) MTreeQueryUtil.getKNNQuery(this, dq, hints);
}
@SuppressWarnings("unchecked")
@Override
public <S extends Distance<S>> RangeQuery<O, S> getRangeQuery(DistanceQuery<O, S> distanceQuery, Object... hints) {
// Query on the relation we index
- if(distanceQuery.getRelation() != relation) {
+ if (distanceQuery.getRelation() != relation) {
return null;
}
- DistanceFunction<? super O, S> distanceFunction = distanceQuery.getDistanceFunction();
- if(!this.distanceFunction.equals(distanceFunction)) {
- if(getLogger().isDebugging()) {
+ DistanceFunction<? super O, D> distanceFunction = (DistanceFunction<? super O, D>) distanceQuery.getDistanceFunction();
+ if (!this.getDistanceFunction().equals(distanceFunction)) {
+ if (getLogger().isDebugging()) {
getLogger().debug("Distance function not supported by index - or 'equals' not implemented right!");
}
return null;
}
// Bulk is not yet supported
- for(Object hint : hints) {
- if(hint == DatabaseQuery.HINT_BULK) {
+ for (Object hint : hints) {
+ if (hint == DatabaseQuery.HINT_BULK) {
return null;
}
}
- AbstractMTree<O, S, ?, ?> idx = (AbstractMTree<O, S, ?, ?>) this;
- DistanceQuery<O, S> dq = distanceFunction.instantiate(relation);
- return MTreeQueryUtil.getRangeQuery(idx, dq);
+ DistanceQuery<O, D> dq = distanceFunction.instantiate(relation);
+ return (RangeQuery<O, S>) MTreeQueryUtil.getRangeQuery(this, dq);
}
@SuppressWarnings("unchecked")
@Override
public <S extends Distance<S>> RKNNQuery<O, S> getRKNNQuery(DistanceQuery<O, S> distanceQuery, Object... hints) {
- DistanceFunction<? super O, S> distanceFunction = distanceQuery.getDistanceFunction();
- if(!this.getDistanceFunction().equals(distanceFunction)) {
- if(getLogger().isDebugging()) {
+ DistanceFunction<? super O, D> distanceFunction = (DistanceFunction<? super O, D>) distanceQuery.getDistanceFunction();
+ if (!this.getDistanceFunction().equals(distanceFunction)) {
+ if (getLogger().isDebugging()) {
getLogger().debug("Distance function not supported by index - or 'equals' not implemented right!");
}
return null;
}
// Bulk is not yet supported
- for(Object hint : hints) {
- if(hint == DatabaseQuery.HINT_BULK) {
+ for (Object hint : hints) {
+ if (hint == DatabaseQuery.HINT_BULK) {
return null;
}
}
- AbstractMkTreeUnified<O, S, ?, ?> idx = (AbstractMkTreeUnified<O, S, ?, ?>) this;
- DistanceQuery<O, S> dq = distanceFunction.instantiate(relation);
- return new MkTreeRKNNQuery<O, S>(idx, dq);
+ DistanceQuery<O, D> dq = distanceFunction.instantiate(relation);
+ return (RKNNQuery<O, S>) new MkTreeRKNNQuery<>(this, dq);
}
@Override
@@ -208,4 +210,4 @@ public class MkMaxTreeIndex<O, D extends Distance<D>> extends MkMaxTree<O, D> im
public String getShortName() {
return "mkmaxtree";
}
-} \ No newline at end of file
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxTreeNode.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxTreeNode.java
index 17f85498..84c8bdc4 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxTreeNode.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxTreeNode.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mkmax;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -24,9 +24,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mkmax;
*/
import de.lmu.ifi.dbs.elki.database.ids.DBID;
-import de.lmu.ifi.dbs.elki.database.query.distance.DistanceQuery;
-import de.lmu.ifi.dbs.elki.distance.DistanceUtil;
-import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
+import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTree;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTreeNode;
@@ -40,7 +38,7 @@ import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTreeNode;
* @param <O> the type of DatabaseObject to be stored in the MkMaxTree
* @param <D> the type of Distance used in the MkMaxTree
*/
-class MkMaxTreeNode<O, D extends Distance<D>> extends AbstractMTreeNode<O, D, MkMaxTreeNode<O, D>, MkMaxEntry<D>> {
+class MkMaxTreeNode<O, D extends NumberDistance<D, ?>> extends AbstractMTreeNode<O, D, MkMaxTreeNode<O, D>, MkMaxEntry> {
/**
* Serial version
*/
@@ -68,14 +66,13 @@ class MkMaxTreeNode<O, D extends Distance<D>> extends AbstractMTreeNode<O, D, Mk
* Determines and returns the k-nearest neighbor distance of this node as the
* maximum of the k-nearest neighbor distances of all entries.
*
- * @param distanceFunction the distance function
* @return the knn distance of this node
*/
- protected D kNNDistance(DistanceQuery<O, D> distanceFunction) {
- D knnDist = distanceFunction.nullDistance();
- for(int i = 0; i < getNumEntries(); i++) {
- MkMaxEntry<D> entry = getEntry(i);
- knnDist = DistanceUtil.max(knnDist, entry.getKnnDistance());
+ protected double kNNDistance() {
+ double knnDist = 0.;
+ for (int i = 0; i < getNumEntries(); i++) {
+ MkMaxEntry entry = getEntry(i);
+ knnDist = Math.max(knnDist, entry.getKnnDistance());
}
return knnDist;
}
@@ -86,10 +83,10 @@ class MkMaxTreeNode<O, D extends Distance<D>> extends AbstractMTreeNode<O, D, Mk
* all its entries.
*/
@Override
- public void adjustEntry(MkMaxEntry<D> entry, DBID routingObjectID, D parentDistance, AbstractMTree<O, D, MkMaxTreeNode<O, D>, MkMaxEntry<D>> mTree) {
+ public void adjustEntry(MkMaxEntry entry, DBID routingObjectID, double parentDistance, AbstractMTree<O, D, MkMaxTreeNode<O, D>, MkMaxEntry, ?> mTree) {
super.adjustEntry(entry, routingObjectID, parentDistance, mTree);
// adjust knn distance
- entry.setKnnDistance(kNNDistance(mTree.getDistanceQuery()));
+ entry.setKnnDistance(kNNDistance());
}
/**
@@ -97,15 +94,13 @@ class MkMaxTreeNode<O, D extends Distance<D>> extends AbstractMTreeNode<O, D, Mk
* node is correctly set.
*/
@Override
- protected void integrityCheckParameters(MkMaxEntry<D> parentEntry, MkMaxTreeNode<O, D> parent, int index, AbstractMTree<O, D, MkMaxTreeNode<O, D>, MkMaxEntry<D>> mTree) {
+ protected void integrityCheckParameters(MkMaxEntry parentEntry, MkMaxTreeNode<O, D> parent, int index, AbstractMTree<O, D, MkMaxTreeNode<O, D>, MkMaxEntry, ?> mTree) {
super.integrityCheckParameters(parentEntry, parent, index, mTree);
// test if knn distance is correctly set
- MkMaxEntry<D> entry = parent.getEntry(index);
- D knnDistance = kNNDistance(mTree.getDistanceQuery());
- if(!entry.getKnnDistance().equals(knnDistance)) {
- String soll = knnDistance.toString();
- String ist = entry.getKnnDistance().toString();
- throw new RuntimeException("Wrong knnDistance in node " + parent.getPageID() + " at index " + index + " (child " + entry + ")" + "\nsoll: " + soll + ",\n ist: " + ist);
+ MkMaxEntry entry = parent.getEntry(index);
+ double knnDistance = kNNDistance();
+ if (Math.abs(entry.getKnnDistance() - knnDistance) > 0) {
+ throw new RuntimeException("Wrong knnDistance in node " + parent.getPageID() + " at index " + index + " (child " + entry + ")" + "\nsoll: " + knnDistance + ",\n ist: " + entry.getKnnDistance());
}
}
}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/package-info.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/package-info.java
index bcde11b4..7bd90d66 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/package-info.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/package-info.java
@@ -5,7 +5,7 @@
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
-Copyright (C) 2012
+Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabDirectoryEntry.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabDirectoryEntry.java
index f8410ad9..9f088448 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabDirectoryEntry.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabDirectoryEntry.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mktab;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -26,11 +26,8 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mktab;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
-import java.util.ArrayList;
-import java.util.List;
import de.lmu.ifi.dbs.elki.database.ids.DBID;
-import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeDirectoryEntry;
/**
@@ -39,20 +36,14 @@ import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeDirectoryEntry
* parameters k <= k_max.
*
* @author Elke Achtert
- *
*/
-class MkTabDirectoryEntry<D extends Distance<D>> extends MTreeDirectoryEntry<D> implements MkTabEntry<D> {
- private static final long serialVersionUID = 1;
-
- /**
- * The maximal number of knn distances to be stored.
- */
- private int k_max;
+class MkTabDirectoryEntry extends MTreeDirectoryEntry implements MkTabEntry {
+ private static final long serialVersionUID = 2;
/**
* The aggregated knn distances of the underlying node.
*/
- private List<D> knnDistances;
+ private double[] knnDistances;
/**
* Empty constructor for serialization purposes.
@@ -71,34 +62,28 @@ class MkTabDirectoryEntry<D extends Distance<D>> extends MTreeDirectoryEntry<D>
* @param coveringRadius the covering radius of the entry
* @param knnDistances the aggregated knn distances of the underlying node
*/
- public MkTabDirectoryEntry(DBID objectID, D parentDistance, Integer nodeID, D coveringRadius, List<D> knnDistances) {
+ public MkTabDirectoryEntry(DBID objectID, double parentDistance, Integer nodeID, double coveringRadius, double[] knnDistances) {
super(objectID, parentDistance, nodeID, coveringRadius);
this.knnDistances = knnDistances;
- this.k_max = knnDistances.size();
}
@Override
- public List<D> getKnnDistances() {
+ public double[] getKnnDistances() {
return knnDistances;
}
@Override
- public void setKnnDistances(List<D> knnDistances) {
+ public void setKnnDistances(double[] knnDistances) {
this.knnDistances = knnDistances;
}
@Override
- public D getKnnDistance(int k) {
- if(k > this.k_max) {
+ public double getKnnDistance(int k) {
+ if (k >= this.knnDistances.length) {
throw new IllegalArgumentException("Parameter k = " + k + " is not supported!");
}
- return knnDistances.get(k - 1);
- }
-
- @Override
- public int getK_max() {
- return k_max;
+ return knnDistances[k - 1];
}
/**
@@ -111,9 +96,10 @@ class MkTabDirectoryEntry<D extends Distance<D>> extends MTreeDirectoryEntry<D>
@Override
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
+ int k_max = knnDistances.length;
out.writeInt(k_max);
- for(int i = 0; i < k_max; i++) {
- out.writeObject(knnDistances.get(i));
+ for (int i = 0; i < k_max; i++) {
+ out.writeDouble(knnDistances[i]);
}
}
@@ -130,10 +116,10 @@ class MkTabDirectoryEntry<D extends Distance<D>> extends MTreeDirectoryEntry<D>
@SuppressWarnings("unchecked")
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
- k_max = in.readInt();
- knnDistances = new ArrayList<D>();
- for(int i = 0; i < k_max; i++) {
- knnDistances.add((D) in.readObject());
+ int k_max = in.readInt();
+ knnDistances = new double[k_max];
+ for (int i = 0; i < k_max; i++) {
+ knnDistances[i] = in.readDouble();
}
}
@@ -148,21 +134,21 @@ class MkTabDirectoryEntry<D extends Distance<D>> extends MTreeDirectoryEntry<D>
@Override
@SuppressWarnings("unchecked")
public boolean equals(Object o) {
- if(this == o) {
+ if (this == o) {
return true;
}
- if(o == null || getClass() != o.getClass()) {
+ if (o == null || getClass() != o.getClass()) {
return false;
}
- if(!super.equals(o)) {
+ if (!super.equals(o)) {
return false;
}
- final MkTabDirectoryEntry<D> that = (MkTabDirectoryEntry<D>) o;
+ final MkTabDirectoryEntry that = (MkTabDirectoryEntry) o;
- if(k_max != that.k_max) {
+ if (knnDistances.length != that.knnDistances.length) {
return false;
}
return !(knnDistances != null ? !knnDistances.equals(that.knnDistances) : that.knnDistances != null);
}
-} \ No newline at end of file
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabEntry.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabEntry.java
index ba938fd3..a741ed5b 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabEntry.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabEntry.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mktab;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -23,46 +23,35 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mktab;
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-import java.util.List;
-
-import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeEntry;
/**
- * Defines the requirements for an entry in an MkCop-Tree node.
- * Additionally to an entry in an M-Tree an MkTabEntry holds a list of knn distances
- * for for parameters k <= k_max of the underlying data object or MkTab-Tree node.
- *
+ * Defines the requirements for an entry in an MkCop-Tree node. Additionally to
+ * an entry in an M-Tree an MkTabEntry holds a list of knn distances for for
+ * parameters k <= k_max of the underlying data object or MkTab-Tree node.
+ *
* @author Elke Achtert
*/
-interface MkTabEntry<D extends Distance<D>> extends MTreeEntry<D> {
+interface MkTabEntry extends MTreeEntry {
/**
* Returns the list of knn distances of the entry.
- *
- * @return the list of knn distances of the entry
+ *
+ * @return the list of knn distances of the entry
*/
- public List<D> getKnnDistances();
+ public double[] getKnnDistances();
/**
* Sets the knn distances of the entry.
- *
+ *
* @param knnDistances the knn distances to be set
*/
- public void setKnnDistances(List<D> knnDistances);
+ public void setKnnDistances(double[] knnDistances);
/**
* Returns the knn distance of the entry for the specified parameter k.
- *
+ *
* @param k the parameter k of the knn distance
* @return the knn distance of the entry
*/
- public D getKnnDistance(int k);
-
- /**
- * Returns the parameter k_max.
- *
- * @return the parameter k_max
- */
- public int getK_max();
-
+ public double getKnnDistance(int k);
}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabLeafEntry.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabLeafEntry.java
index 81446718..969ba781 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabLeafEntry.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabLeafEntry.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mktab;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -26,11 +26,8 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mktab;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
-import java.util.ArrayList;
-import java.util.List;
import de.lmu.ifi.dbs.elki.database.ids.DBID;
-import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeLeafEntry;
/**
@@ -40,18 +37,13 @@ import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeLeafEntry;
*
* @author Elke Achtert
*/
-class MkTabLeafEntry<D extends Distance<D>> extends MTreeLeafEntry<D> implements MkTabEntry<D> {
- private static final long serialVersionUID = 1;
-
- /**
- * The maximal number of knn distances to be stored.
- */
- private int k_max;
+class MkTabLeafEntry extends MTreeLeafEntry implements MkTabEntry {
+ private static final long serialVersionUID = 2;
/**
* The knn distances of the underlying data object.
*/
- private List<D> knnDistances;
+ private double[] knnDistances;
/**
* Empty constructor for serialization purposes.
@@ -68,38 +60,32 @@ class MkTabLeafEntry<D extends Distance<D>> extends MTreeLeafEntry<D> implements
* parent's routing object
* @param knnDistances the knn distances of the underlying data object
*/
- public MkTabLeafEntry(DBID objectID, D parentDistance, List<D> knnDistances) {
+ public MkTabLeafEntry(DBID objectID, double parentDistance, double[] knnDistances) {
super(objectID, parentDistance);
this.knnDistances = knnDistances;
- this.k_max = knnDistances.size();
}
@Override
- public List<D> getKnnDistances() {
+ public double[] getKnnDistances() {
return knnDistances;
}
@Override
- public void setKnnDistances(List<D> knnDistances) {
- if(knnDistances.size() != this.k_max) {
- throw new IllegalArgumentException("Wrong length of knn distances: " + knnDistances.size());
+ public void setKnnDistances(double[] knnDistances) {
+ if (knnDistances.length != this.knnDistances.length) {
+ throw new IllegalArgumentException("Wrong length of knn distances: " + knnDistances.length);
}
this.knnDistances = knnDistances;
}
@Override
- public D getKnnDistance(int k) {
- if(k > this.k_max) {
+ public double getKnnDistance(int k) {
+ if (k >= this.knnDistances.length) {
throw new IllegalArgumentException("Parameter k = " + k + " is not supported!");
}
- return knnDistances.get(k - 1);
- }
-
- @Override
- public int getK_max() {
- return k_max;
+ return knnDistances[k - 1];
}
/**
@@ -112,9 +98,10 @@ class MkTabLeafEntry<D extends Distance<D>> extends MTreeLeafEntry<D> implements
@Override
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
+ int k_max = knnDistances.length;
out.writeInt(k_max);
- for(int i = 0; i < k_max; i++) {
- out.writeObject(knnDistances.get(i));
+ for (int i = 0; i < k_max; i++) {
+ out.writeDouble(knnDistances[i]);
}
}
@@ -131,10 +118,10 @@ class MkTabLeafEntry<D extends Distance<D>> extends MTreeLeafEntry<D> implements
@SuppressWarnings("unchecked")
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
- k_max = in.readInt();
- knnDistances = new ArrayList<D>();
- for(int i = 0; i < k_max; i++) {
- knnDistances.add((D) in.readObject());
+ int k_max = in.readInt();
+ knnDistances = new double[k_max];
+ for (int i = 0; i < k_max; i++) {
+ knnDistances[i] = in.readDouble();
}
}
@@ -148,21 +135,21 @@ class MkTabLeafEntry<D extends Distance<D>> extends MTreeLeafEntry<D> implements
@Override
@SuppressWarnings("unchecked")
public boolean equals(Object o) {
- if(this == o) {
+ if (this == o) {
return true;
}
- if(o == null || getClass() != o.getClass()) {
+ if (o == null || getClass() != o.getClass()) {
return false;
}
- if(!super.equals(o)) {
+ if (!super.equals(o)) {
return false;
}
- final MkTabLeafEntry<D> that = (MkTabLeafEntry<D>) o;
+ final MkTabLeafEntry that = (MkTabLeafEntry) o;
- if(k_max != that.k_max) {
+ if (knnDistances.length != that.knnDistances.length) {
return false;
}
return !(knnDistances != null ? !knnDistances.equals(that.knnDistances) : that.knnDistances != null);
}
-} \ No newline at end of file
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabTree.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabTree.java
index f5410839..481392cb 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabTree.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabTree.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mktab;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -23,22 +23,20 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mktab;
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-import java.util.ArrayList;
-import java.util.List;
import java.util.Map;
import de.lmu.ifi.dbs.elki.database.ids.DBID;
import de.lmu.ifi.dbs.elki.database.ids.DBIDRef;
-import de.lmu.ifi.dbs.elki.database.query.distance.DistanceQuery;
-import de.lmu.ifi.dbs.elki.distance.DistanceUtil;
-import de.lmu.ifi.dbs.elki.distance.distancefunction.DistanceFunction;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.DistanceDBIDResult;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.GenericDistanceDBIDList;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.KNNResult;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.KNNUtil;
-import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
+import de.lmu.ifi.dbs.elki.database.ids.distance.DistanceDBIDList;
+import de.lmu.ifi.dbs.elki.database.ids.distance.DistanceDBIDListIter;
+import de.lmu.ifi.dbs.elki.database.ids.distance.KNNList;
+import de.lmu.ifi.dbs.elki.database.ids.generic.GenericDistanceDBIDList;
+import de.lmu.ifi.dbs.elki.database.relation.Relation;
+import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.AbstractMkTreeUnified;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.MkTreeSettings;
import de.lmu.ifi.dbs.elki.logging.Logging;
+import de.lmu.ifi.dbs.elki.persistent.ByteArrayUtil;
import de.lmu.ifi.dbs.elki.persistent.PageFile;
/**
@@ -54,22 +52,21 @@ import de.lmu.ifi.dbs.elki.persistent.PageFile;
* @param <O> Object type
* @param <D> Distance type
*/
-public class MkTabTree<O, D extends Distance<D>> extends AbstractMkTreeUnified<O, D, MkTabTreeNode<O, D>, MkTabEntry<D>> {
+public class MkTabTree<O, D extends NumberDistance<D, ?>> extends AbstractMkTreeUnified<O, D, MkTabTreeNode<O, D>, MkTabEntry, MkTreeSettings<O, D, MkTabTreeNode<O, D>, MkTabEntry>> {
/**
* The logger for this class.
*/
private static final Logging LOG = Logging.getLogger(MkTabTree.class);
-
+
/**
* Constructor.
*
+ * @param relation Relation
* @param pagefile Page file
- * @param distanceQuery Distance query
- * @param distanceFunction Distance function
- * @param k_max Maximum value for k
+ * @param settings Settings
*/
- public MkTabTree(PageFile<MkTabTreeNode<O, D>> pagefile, DistanceQuery<O, D> distanceQuery, DistanceFunction<O, D> distanceFunction, int k_max) {
- super(pagefile, distanceQuery, distanceFunction, k_max);
+ public MkTabTree(Relation<O> relation, PageFile<MkTabTreeNode<O, D>> pagefile, MkTreeSettings<O, D, MkTabTreeNode<O, D>, MkTabEntry> settings) {
+ super(relation, pagefile, settings);
}
/**
@@ -77,7 +74,7 @@ public class MkTabTree<O, D extends Distance<D>> extends AbstractMkTreeUnified<O
* not supported
*/
@Override
- protected void preInsert(MkTabEntry<D> entry) {
+ protected void preInsert(MkTabEntry entry) {
throw new UnsupportedOperationException("Insertion of single objects is not supported!");
}
@@ -86,17 +83,17 @@ public class MkTabTree<O, D extends Distance<D>> extends AbstractMkTreeUnified<O
* not supported
*/
@Override
- public void insert(MkTabEntry<D> entry, boolean withPreInsert) {
+ public void insert(MkTabEntry entry, boolean withPreInsert) {
throw new UnsupportedOperationException("Insertion of single objects is not supported!");
}
@Override
- public DistanceDBIDResult<D> reverseKNNQuery(DBIDRef id, int k) {
- if(k > this.getKmax()) {
+ public DistanceDBIDList<D> reverseKNNQuery(DBIDRef id, int k) {
+ if (k > this.getKmax()) {
throw new IllegalArgumentException("Parameter k has to be less or equal than " + "parameter kmax of the MkTab-Tree!");
}
- GenericDistanceDBIDList<D> result = new GenericDistanceDBIDList<D>();
+ GenericDistanceDBIDList<D> result = new GenericDistanceDBIDList<>();
doReverseKNNQuery(k, id, null, getRoot(), result);
result.sort();
@@ -104,12 +101,12 @@ public class MkTabTree<O, D extends Distance<D>> extends AbstractMkTreeUnified<O
}
@Override
- protected void initializeCapacities(MkTabEntry<D> exampleLeaf) {
- int distanceSize = exampleLeaf.getParentDistance().externalizableSize();
+ protected void initializeCapacities(MkTabEntry exampleLeaf) {
+ int distanceSize = ByteArrayUtil.SIZE_DOUBLE; // exampleLeaf.getParentDistance().externalizableSize();
// overhead = index(4), numEntries(4), id(4), isLeaf(0.125)
double overhead = 12.125;
- if(getPageSize() - overhead < 0) {
+ if (getPageSize() - overhead < 0) {
throw new RuntimeException("Node size of " + getPageSize() + " Bytes is chosen too small!");
}
@@ -117,11 +114,11 @@ public class MkTabTree<O, D extends Distance<D>> extends AbstractMkTreeUnified<O
// coveringRadius + parentDistance + kmax + kmax * knnDistance) + 1
dirCapacity = (int) (getPageSize() - overhead) / (4 + 4 + distanceSize + distanceSize + 4 + getKmax() * distanceSize) + 1;
- if(dirCapacity <= 1) {
+ if (dirCapacity <= 1) {
throw new RuntimeException("Node size of " + getPageSize() + " Bytes is chosen too small!");
}
- if(dirCapacity < 10) {
+ if (dirCapacity < 10) {
LOG.warning("Page size is choosen too small! Maximum number of entries " + "in a directory node = " + (dirCapacity - 1));
}
@@ -129,30 +126,37 @@ public class MkTabTree<O, D extends Distance<D>> extends AbstractMkTreeUnified<O
// kmax + kmax * knnDistance) + 1
leafCapacity = (int) (getPageSize() - overhead) / (4 + distanceSize + 4 + getKmax() * distanceSize) + 1;
- if(leafCapacity <= 1) {
+ if (leafCapacity <= 1) {
throw new RuntimeException("Node size of " + getPageSize() + " Bytes is chosen too small!");
}
- if(leafCapacity < 10) {
+ if (leafCapacity < 10) {
LOG.warning("Page size is choosen too small! Maximum number of entries " + "in a leaf node = " + (leafCapacity - 1));
}
}
-
+
@Override
- protected void kNNdistanceAdjustment(MkTabEntry<D> entry, Map<DBID, KNNResult<D>> knnLists) {
+ protected void kNNdistanceAdjustment(MkTabEntry entry, Map<DBID, KNNList<D>> knnLists) {
MkTabTreeNode<O, D> node = getNode(entry);
- List<D> knnDistances_node = initKnnDistanceList();
- if(node.isLeaf()) {
- for(int i = 0; i < node.getNumEntries(); i++) {
- MkTabEntry<D> leafEntry = node.getEntry(i);
- leafEntry.setKnnDistances(KNNUtil.asDistanceList(knnLists.get(getPageID(leafEntry))));
+ double[] knnDistances_node = initKnnDistanceList();
+ if (node.isLeaf()) {
+ for (int i = 0; i < node.getNumEntries(); i++) {
+ MkTabEntry leafEntry = node.getEntry(i);
+ KNNList<D> knns = knnLists.get(getPageID(leafEntry));
+ double[] distances = new double[knns.size()];
+ int j = 0;
+ for (DistanceDBIDListIter<D> iter = knns.iter(); iter.valid(); iter.advance(), j++) {
+ distances[i] = iter.getDistance().doubleValue();
+ }
+ leafEntry.setKnnDistances(distances);
+ // FIXME: save copy
knnDistances_node = max(knnDistances_node, leafEntry.getKnnDistances());
}
- }
- else {
- for(int i = 0; i < node.getNumEntries(); i++) {
- MkTabEntry<D> dirEntry = node.getEntry(i);
+ } else {
+ for (int i = 0; i < node.getNumEntries(); i++) {
+ MkTabEntry dirEntry = node.getEntry(i);
kNNdistanceAdjustment(dirEntry, knnLists);
+ // FIXME: save copy
knnDistances_node = max(knnDistances_node, dirEntry.getKnnDistances());
}
}
@@ -161,7 +165,7 @@ public class MkTabTree<O, D extends Distance<D>> extends AbstractMkTreeUnified<O
@Override
protected MkTabTreeNode<O, D> createNewLeafNode() {
- return new MkTabTreeNode<O, D>(leafCapacity, true);
+ return new MkTabTreeNode<>(leafCapacity, true);
}
/**
@@ -171,7 +175,7 @@ public class MkTabTree<O, D extends Distance<D>> extends AbstractMkTreeUnified<O
*/
@Override
protected MkTabTreeNode<O, D> createNewDirectoryNode() {
- return new MkTabTreeNode<O, D>(dirCapacity, false);
+ return new MkTabTreeNode<>(dirCapacity, false);
}
/**
@@ -183,8 +187,8 @@ public class MkTabTree<O, D extends Distance<D>> extends AbstractMkTreeUnified<O
* the routing object of the parent node
*/
@Override
- protected MkTabEntry<D> createNewDirectoryEntry(MkTabTreeNode<O, D> node, DBID routingObjectID, D parentDistance) {
- return new MkTabDirectoryEntry<D>(routingObjectID, parentDistance, node.getPageID(), node.coveringRadius(routingObjectID, this), node.kNNDistances(getDistanceQuery()));
+ protected MkTabEntry createNewDirectoryEntry(MkTabTreeNode<O, D> node, DBID routingObjectID, double parentDistance) {
+ return new MkTabDirectoryEntry(routingObjectID, parentDistance, node.getPageID(), node.coveringRadius(routingObjectID, this), node.kNNDistances());
}
/**
@@ -193,8 +197,8 @@ public class MkTabTree<O, D extends Distance<D>> extends AbstractMkTreeUnified<O
* @return an entry representing the root node
*/
@Override
- protected MkTabEntry<D> createRootEntry() {
- return new MkTabDirectoryEntry<D>(null, null, 0, null, initKnnDistanceList());
+ protected MkTabEntry createRootEntry() {
+ return new MkTabDirectoryEntry(null, 0., 0, 0., initKnnDistanceList());
}
/**
@@ -209,13 +213,13 @@ public class MkTabTree<O, D extends Distance<D>> extends AbstractMkTreeUnified<O
* @param node the root of the subtree
* @param result the list holding the query result
*/
- private void doReverseKNNQuery(int k, DBIDRef q, MkTabEntry<D> node_entry, MkTabTreeNode<O, D> node, GenericDistanceDBIDList<D> result) {
+ private void doReverseKNNQuery(int k, DBIDRef q, MkTabEntry node_entry, MkTabTreeNode<O, D> node, GenericDistanceDBIDList<D> result) {
// data node
- if(node.isLeaf()) {
- for(int i = 0; i < node.getNumEntries(); i++) {
- MkTabEntry<D> entry = node.getEntry(i);
- D distance = getDistanceQuery().distance(entry.getRoutingObjectID(), q);
- if(distance.compareTo(entry.getKnnDistance(k)) <= 0) {
+ if (node.isLeaf()) {
+ for (int i = 0; i < node.getNumEntries(); i++) {
+ MkTabEntry entry = node.getEntry(i);
+ D distance = distance(entry.getRoutingObjectID(), q);
+ if (distance.doubleValue() <= entry.getKnnDistance(k)) {
result.add(distance, entry.getRoutingObjectID());
}
}
@@ -223,14 +227,14 @@ public class MkTabTree<O, D extends Distance<D>> extends AbstractMkTreeUnified<O
// directory node
else {
- for(int i = 0; i < node.getNumEntries(); i++) {
- MkTabEntry<D> entry = node.getEntry(i);
- D node_knnDist = node_entry != null ? node_entry.getKnnDistance(k) : getDistanceQuery().infiniteDistance();
+ for (int i = 0; i < node.getNumEntries(); i++) {
+ MkTabEntry entry = node.getEntry(i);
+ double node_knnDist = node_entry != null ? node_entry.getKnnDistance(k) : Double.POSITIVE_INFINITY;
- D distance = getDistanceQuery().distance(entry.getRoutingObjectID(), q);
- D minDist = entry.getCoveringRadius().compareTo(distance) > 0 ? getDistanceQuery().nullDistance() : distance.minus(entry.getCoveringRadius());
+ double distance = distance(entry.getRoutingObjectID(), q).doubleValue();
+ double minDist = (entry.getCoveringRadius() > distance) ? 0. : distance - entry.getCoveringRadius();
- if(minDist.compareTo(node_knnDist) <= 0) {
+ if (minDist <= node_knnDist) {
MkTabTreeNode<O, D> childNode = getNode(entry);
doReverseKNNQuery(k, q, entry, childNode, result);
}
@@ -247,17 +251,14 @@ public class MkTabTree<O, D extends Distance<D>> extends AbstractMkTreeUnified<O
* @return an array that holds the maximum values of the both specified arrays
* in each index
*/
- private List<D> max(List<D> distances1, List<D> distances2) {
- if(distances1.size() != distances2.size()) {
+ private double[] max(double[] distances1, double[] distances2) {
+ if (distances1.length != distances2.length) {
throw new RuntimeException("different lengths!");
}
- List<D> result = new ArrayList<D>();
-
- for(int i = 0; i < distances1.size(); i++) {
- D d1 = distances1.get(i);
- D d2 = distances2.get(i);
- result.add(DistanceUtil.max(d1, d2));
+ double[] result = new double[distances1.length];
+ for (int i = 0; i < distances1.length; i++) {
+ result[i] = Math.max(distances1[i], distances2[i]);
}
return result;
}
@@ -267,16 +268,13 @@ public class MkTabTree<O, D extends Distance<D>> extends AbstractMkTreeUnified<O
*
* @return a knn distance list with all distances set to null distance
*/
- private List<D> initKnnDistanceList() {
- List<D> knnDistances = new ArrayList<D>(getKmax());
- for(int i = 0; i < getKmax(); i++) {
- knnDistances.add(getDistanceQuery().nullDistance());
- }
+ private double[] initKnnDistanceList() {
+ double[] knnDistances = new double[getKmax()];
return knnDistances;
}
-
+
@Override
protected Logging getLogger() {
return LOG;
}
-} \ No newline at end of file
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabTreeFactory.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabTreeFactory.java
index 2bc6c256..9ede76ad 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabTreeFactory.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabTreeFactory.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mktab;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -24,10 +24,11 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mktab;
*/
import de.lmu.ifi.dbs.elki.database.relation.Relation;
-import de.lmu.ifi.dbs.elki.distance.distancefunction.DistanceFunction;
-import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
+import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.AbstractMkTreeUnifiedFactory;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.MkTreeSettings;
import de.lmu.ifi.dbs.elki.persistent.PageFile;
+import de.lmu.ifi.dbs.elki.persistent.PageFileFactory;
import de.lmu.ifi.dbs.elki.utilities.ClassGenericsUtil;
/**
@@ -41,24 +42,21 @@ import de.lmu.ifi.dbs.elki.utilities.ClassGenericsUtil;
* @param <O> Object type
* @param <D> Distance type
*/
-public class MkTabTreeFactory<O, D extends Distance<D>> extends AbstractMkTreeUnifiedFactory<O, D, MkTabTreeNode<O, D>, MkTabEntry<D>, MkTabTreeIndex<O, D>> {
+public class MkTabTreeFactory<O, D extends NumberDistance<D, ?>> extends AbstractMkTreeUnifiedFactory<O, D, MkTabTreeNode<O, D>, MkTabEntry, MkTabTreeIndex<O, D>, MkTreeSettings<O, D, MkTabTreeNode<O, D>, MkTabEntry>> {
/**
* Constructor.
*
- * @param fileName
- * @param pageSize
- * @param cacheSize
- * @param distanceFunction
- * @param k_max
+ * @param pageFileFactory Data storage
+ * @param settings Tree settings
*/
- public MkTabTreeFactory(String fileName, int pageSize, long cacheSize, DistanceFunction<O, D> distanceFunction, int k_max) {
- super(fileName, pageSize, cacheSize, distanceFunction, k_max);
+ public MkTabTreeFactory(PageFileFactory<?> pageFileFactory, MkTreeSettings<O, D, MkTabTreeNode<O, D>, MkTabEntry> settings) {
+ super(pageFileFactory, settings);
}
@Override
public MkTabTreeIndex<O, D> instantiate(Relation<O> relation) {
PageFile<MkTabTreeNode<O, D>> pagefile = makePageFile(getNodeClass());
- return new MkTabTreeIndex<O, D>(relation, pagefile, distanceFunction.instantiate(relation), distanceFunction, k_max);
+ return new MkTabTreeIndex<>(relation, pagefile, settings);
}
protected Class<MkTabTreeNode<O, D>> getNodeClass() {
@@ -72,10 +70,15 @@ public class MkTabTreeFactory<O, D extends Distance<D>> extends AbstractMkTreeUn
*
* @apiviz.exclude
*/
- public static class Parameterizer<O, D extends Distance<D>> extends AbstractMkTreeUnifiedFactory.Parameterizer<O, D> {
+ public static class Parameterizer<O, D extends NumberDistance<D, ?>> extends AbstractMkTreeUnifiedFactory.Parameterizer<O, D, MkTabTreeNode<O, D>, MkTabEntry, MkTreeSettings<O, D, MkTabTreeNode<O, D>, MkTabEntry>> {
@Override
protected MkTabTreeFactory<O, D> makeInstance() {
- return new MkTabTreeFactory<O, D>(fileName, pageSize, cacheSize, distanceFunction, k_max);
+ return new MkTabTreeFactory<>(pageFileFactory, settings);
+ }
+
+ @Override
+ protected MkTreeSettings<O, D, MkTabTreeNode<O, D>, MkTabEntry> makeSettings() {
+ return new MkTreeSettings<>();
}
}
-} \ No newline at end of file
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabTreeIndex.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabTreeIndex.java
index b12ac059..150f03e8 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabTreeIndex.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabTreeIndex.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mktab;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -28,9 +28,9 @@ import java.util.List;
import de.lmu.ifi.dbs.elki.database.ids.DBID;
import de.lmu.ifi.dbs.elki.database.ids.DBIDIter;
-import de.lmu.ifi.dbs.elki.database.ids.DBIDRef;
import de.lmu.ifi.dbs.elki.database.ids.DBIDUtil;
-import de.lmu.ifi.dbs.elki.database.ids.DBIDs;
+import de.lmu.ifi.dbs.elki.database.ids.distance.DistanceDBIDListIter;
+import de.lmu.ifi.dbs.elki.database.ids.distance.KNNList;
import de.lmu.ifi.dbs.elki.database.query.DatabaseQuery;
import de.lmu.ifi.dbs.elki.database.query.distance.DistanceQuery;
import de.lmu.ifi.dbs.elki.database.query.knn.KNNQuery;
@@ -38,18 +38,15 @@ import de.lmu.ifi.dbs.elki.database.query.range.RangeQuery;
import de.lmu.ifi.dbs.elki.database.query.rknn.RKNNQuery;
import de.lmu.ifi.dbs.elki.database.relation.Relation;
import de.lmu.ifi.dbs.elki.distance.distancefunction.DistanceFunction;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.KNNResult;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.KNNUtil;
import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
+import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
import de.lmu.ifi.dbs.elki.index.KNNIndex;
import de.lmu.ifi.dbs.elki.index.RKNNIndex;
import de.lmu.ifi.dbs.elki.index.RangeIndex;
-import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTree;
-import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.AbstractMkTreeUnified;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.MkTreeSettings;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.query.MTreeQueryUtil;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.query.MkTreeRKNNQuery;
import de.lmu.ifi.dbs.elki.persistent.PageFile;
-import de.lmu.ifi.dbs.elki.utilities.exceptions.ExceptionMessages;
/**
* MkTabTree used as database index.
@@ -59,12 +56,7 @@ import de.lmu.ifi.dbs.elki.utilities.exceptions.ExceptionMessages;
* @param <O> Object type
* @param <D> Distance type
*/
-public class MkTabTreeIndex<O, D extends Distance<D>> extends MkTabTree<O, D> implements RangeIndex<O>, KNNIndex<O>, RKNNIndex<O> {
- /**
- * The knn query we use internally.
- */
- private final KNNQuery<O, D> knnQuery;
-
+public class MkTabTreeIndex<O, D extends NumberDistance<D, ?>> extends MkTabTree<O, D> implements RangeIndex<O>, KNNIndex<O>, RKNNIndex<O> {
/**
* The relation indexed.
*/
@@ -75,15 +67,11 @@ public class MkTabTreeIndex<O, D extends Distance<D>> extends MkTabTree<O, D> im
*
* @param relation Relation indexed
* @param pagefile Page file
- * @param distanceQuery Distance query
- * @param distanceFunction Distance function
- * @param k_max Maximum value for k
+ * @param settings Tree settings
*/
- public MkTabTreeIndex(Relation<O> relation, PageFile<MkTabTreeNode<O, D>> pagefile, DistanceQuery<O, D> distanceQuery, DistanceFunction<O, D> distanceFunction, int k_max) {
- super(pagefile, distanceQuery, distanceFunction, k_max);
+ public MkTabTreeIndex(Relation<O> relation, PageFile<MkTabTreeNode<O, D>> pagefile, MkTreeSettings<O, D, MkTabTreeNode<O, D>, MkTabEntry> settings) {
+ super(relation, pagefile, settings);
this.relation = relation;
- this.knnQuery = this.getKNNQuery(getDistanceQuery());
- this.initialize();
}
/**
@@ -94,8 +82,8 @@ public class MkTabTreeIndex<O, D extends Distance<D>> extends MkTabTree<O, D> im
* @param parentDistance the distance from the object to the routing object of
* the parent node
*/
- protected MkTabEntry<D> createNewLeafEntry(DBID id, O object, D parentDistance) {
- return new MkTabLeafEntry<D>(id, parentDistance, knnDistances(object));
+ protected MkTabEntry createNewLeafEntry(DBID id, O object, double parentDistance) {
+ return new MkTabLeafEntry(id, parentDistance, knnDistances(object));
}
/**
@@ -104,120 +92,94 @@ public class MkTabTreeIndex<O, D extends Distance<D>> extends MkTabTree<O, D> im
* @param object the query object
* @return the knn distance of the object with the specified id
*/
- private List<D> knnDistances(O object) {
- KNNResult<D> knns = knnQuery.getKNNForObject(object, getKmax() - 1);
- return KNNUtil.asDistanceList(knns);
- }
-
- @Override
- public void insert(DBIDRef id) {
- throw new UnsupportedOperationException("Insertion of single objects is not supported!");
+ private double[] knnDistances(O object) {
+ KNNList<D> knns = knnq.getKNNForObject(object, getKmax() - 1);
+ double[] distances = new double[getKmax()];
+ int i = 0;
+ for (DistanceDBIDListIter<D> iter = knns.iter(); iter.valid() && i < getKmax(); iter.advance(), i++) {
+ distances[i] = iter.getDistance().doubleValue();
+ }
+ return distances;
}
@Override
- public void insertAll(DBIDs ids) {
- List<MkTabEntry<D>> objs = new ArrayList<MkTabEntry<D>>(ids.size());
- for (DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) {
- DBID id = DBIDUtil.deref(iter);
+ public void initialize() {
+ super.initialize();
+ List<MkTabEntry> objs = new ArrayList<>(relation.size());
+ for (DBIDIter iter = relation.iterDBIDs(); iter.valid(); iter.advance()) {
+ DBID id = DBIDUtil.deref(iter); // FIXME: expensive
final O object = relation.get(id);
- objs.add(createNewLeafEntry(id, object, getDistanceFactory().undefinedDistance()));
+ objs.add(createNewLeafEntry(id, object, Double.NaN));
}
insertAll(objs);
}
- /**
- * Throws an UnsupportedOperationException since deletion of objects is not
- * yet supported by an M-Tree.
- *
- * @throws UnsupportedOperationException thrown, since deletions aren't
- * implemented yet.
- */
- @Override
- public final boolean delete(DBIDRef id) {
- throw new UnsupportedOperationException(ExceptionMessages.UNSUPPORTED_NOT_YET);
- }
-
- /**
- * Throws an UnsupportedOperationException since deletion of objects is not
- * yet supported by an M-Tree.
- *
- * @throws UnsupportedOperationException thrown, since deletions aren't
- * implemented yet.
- */
- @Override
- public void deleteAll(DBIDs ids) {
- throw new UnsupportedOperationException(ExceptionMessages.UNSUPPORTED_NOT_YET);
- }
-
@SuppressWarnings("unchecked")
@Override
public <S extends Distance<S>> KNNQuery<O, S> getKNNQuery(DistanceQuery<O, S> distanceQuery, Object... hints) {
// Query on the relation we index
- if(distanceQuery.getRelation() != relation) {
+ if (distanceQuery.getRelation() != relation) {
return null;
}
- DistanceFunction<? super O, S> distanceFunction = distanceQuery.getDistanceFunction();
- if(!this.distanceFunction.equals(distanceFunction)) {
- if(getLogger().isDebugging()) {
+ DistanceFunction<? super O, D> distanceFunction = (DistanceFunction<? super O, D>) distanceQuery.getDistanceFunction();
+ if (!this.getDistanceFunction().equals(distanceFunction)) {
+ if (getLogger().isDebugging()) {
getLogger().debug("Distance function not supported by index - or 'equals' not implemented right!");
}
return null;
}
// Bulk is not yet supported
- for(Object hint : hints) {
- if(hint == DatabaseQuery.HINT_BULK) {
+ for (Object hint : hints) {
+ if (hint == DatabaseQuery.HINT_BULK) {
return null;
}
}
- AbstractMTree<O, S, ?, ?> idx = (AbstractMTree<O, S, ?, ?>) this;
- DistanceQuery<O, S> dq = distanceFunction.instantiate(relation);
- return MTreeQueryUtil.getKNNQuery(idx, dq, hints);
+ DistanceQuery<O, D> dq = distanceFunction.instantiate(relation);
+ return (KNNQuery<O, S>) MTreeQueryUtil.getKNNQuery(this, dq, hints);
}
@SuppressWarnings("unchecked")
@Override
public <S extends Distance<S>> RangeQuery<O, S> getRangeQuery(DistanceQuery<O, S> distanceQuery, Object... hints) {
// Query on the relation we index
- if(distanceQuery.getRelation() != relation) {
+ if (distanceQuery.getRelation() != relation) {
return null;
}
- DistanceFunction<? super O, S> distanceFunction = distanceQuery.getDistanceFunction();
- if(!this.distanceFunction.equals(distanceFunction)) {
- if(getLogger().isDebugging()) {
+ DistanceFunction<? super O, D> distanceFunction = (DistanceFunction<? super O, D>) distanceQuery.getDistanceFunction();
+ if (!this.getDistanceFunction().equals(distanceFunction)) {
+ if (getLogger().isDebugging()) {
getLogger().debug("Distance function not supported by index - or 'equals' not implemented right!");
}
return null;
}
// Bulk is not yet supported
- for(Object hint : hints) {
- if(hint == DatabaseQuery.HINT_BULK) {
+ for (Object hint : hints) {
+ if (hint == DatabaseQuery.HINT_BULK) {
return null;
}
}
- AbstractMTree<O, S, ?, ?> idx = (AbstractMTree<O, S, ?, ?>) this;
- DistanceQuery<O, S> dq = distanceFunction.instantiate(relation);
- return MTreeQueryUtil.getRangeQuery(idx, dq);
+ DistanceQuery<O, D> dq = distanceFunction.instantiate(relation);
+ return (RangeQuery<O, S>) MTreeQueryUtil.getRangeQuery(this, dq);
}
@SuppressWarnings("unchecked")
@Override
public <S extends Distance<S>> RKNNQuery<O, S> getRKNNQuery(DistanceQuery<O, S> distanceQuery, Object... hints) {
- DistanceFunction<? super O, S> distanceFunction = distanceQuery.getDistanceFunction();
- if(!this.getDistanceFunction().equals(distanceFunction)) {
- if(getLogger().isDebugging()) {
+ DistanceFunction<? super O, D> distanceFunction = (DistanceFunction<? super O, D>) distanceQuery.getDistanceFunction();
+ if (!this.getDistanceFunction().equals(distanceFunction)) {
+ if (getLogger().isDebugging()) {
getLogger().debug("Distance function not supported by index - or 'equals' not implemented right!");
}
return null;
}
// Bulk is not yet supported
- for(Object hint : hints) {
- if(hint == DatabaseQuery.HINT_BULK) {
+ for (Object hint : hints) {
+ if (hint == DatabaseQuery.HINT_BULK) {
return null;
}
}
- AbstractMkTreeUnified<O, S, ?, ?> idx = (AbstractMkTreeUnified<O, S, ?, ?>) this;
- DistanceQuery<O, S> dq = distanceFunction.instantiate(relation);
- return new MkTreeRKNNQuery<O, S>(idx, dq);
+ DistanceQuery<O, D> dq = distanceFunction.instantiate(relation);
+ return (RKNNQuery<O, S>) new MkTreeRKNNQuery<>(this, dq);
}
@Override
@@ -229,4 +191,4 @@ public class MkTabTreeIndex<O, D extends Distance<D>> extends MkTabTree<O, D> im
public String getShortName() {
return "mktabtree";
}
-} \ No newline at end of file
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabTreeNode.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabTreeNode.java
index b09ac314..1942a78b 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabTreeNode.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabTreeNode.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mktab;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -23,13 +23,8 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.mktab;
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-import java.util.ArrayList;
-import java.util.List;
-
import de.lmu.ifi.dbs.elki.database.ids.DBID;
-import de.lmu.ifi.dbs.elki.database.query.distance.DistanceQuery;
-import de.lmu.ifi.dbs.elki.distance.DistanceUtil;
-import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
+import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTree;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTreeNode;
@@ -43,8 +38,8 @@ import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTreeNode;
* @param <O> object type
* @param <D> distance type
*/
-class MkTabTreeNode<O, D extends Distance<D>> extends AbstractMTreeNode<O, D, MkTabTreeNode<O, D>, MkTabEntry<D>> {
- private static final long serialVersionUID = 1;
+class MkTabTreeNode<O, D extends NumberDistance<D, ?>> extends AbstractMTreeNode<O, D, MkTabTreeNode<O, D>, MkTabEntry> {
+ private static final long serialVersionUID = 2;
/**
* Empty constructor for Externalizable interface.
@@ -68,22 +63,17 @@ class MkTabTreeNode<O, D extends Distance<D>> extends AbstractMTreeNode<O, D, Mk
* Determines and returns the knn distance of this node as the maximum knn
* distance of all entries.
*
- * @param distanceFunction the distance function
* @return the knn distance of this node
*/
- protected List<D> kNNDistances(DistanceQuery<O, D> distanceFunction) {
- int k = getEntry(0).getK_max();
+ protected double[] kNNDistances() {
+ int k = getEntry(0).getKnnDistances().length;
- List<D> result = new ArrayList<D>();
- for(int i = 0; i < k; i++) {
- result.add(distanceFunction.nullDistance());
- }
+ double[] result = new double[k];
- for(int i = 0; i < getNumEntries(); i++) {
- for(int j = 0; j < k; j++) {
- MkTabEntry<D> entry = getEntry(i);
- D kDist = result.remove(j);
- result.add(j, DistanceUtil.max(kDist, entry.getKnnDistance(j + 1)));
+ for (int i = 0; i < getNumEntries(); i++) {
+ for (int j = 0; j < k; j++) {
+ MkTabEntry entry = getEntry(i);
+ result[j] = Math.max(result[j], entry.getKnnDistance(j + 1));
}
}
@@ -91,10 +81,10 @@ class MkTabTreeNode<O, D extends Distance<D>> extends AbstractMTreeNode<O, D, Mk
}
@Override
- public void adjustEntry(MkTabEntry<D> entry, DBID routingObjectID, D parentDistance, AbstractMTree<O, D, MkTabTreeNode<O, D>, MkTabEntry<D>> mTree) {
+ public void adjustEntry(MkTabEntry entry, DBID routingObjectID, double parentDistance, AbstractMTree<O, D, MkTabTreeNode<O, D>, MkTabEntry, ?> mTree) {
super.adjustEntry(entry, routingObjectID, parentDistance, mTree);
// adjust knn distances
- entry.setKnnDistances(kNNDistances(mTree.getDistanceQuery()));
+ entry.setKnnDistances(kNNDistances());
}
/**
@@ -106,12 +96,12 @@ class MkTabTreeNode<O, D extends Distance<D>> extends AbstractMTreeNode<O, D, Mk
* @param mTree the underlying M-Tree
*/
@Override
- protected void integrityCheckParameters(MkTabEntry<D> parentEntry, MkTabTreeNode<O, D> parent, int index, AbstractMTree<O, D, MkTabTreeNode<O, D>, MkTabEntry<D>> mTree) {
+ protected void integrityCheckParameters(MkTabEntry parentEntry, MkTabTreeNode<O, D> parent, int index, AbstractMTree<O, D, MkTabTreeNode<O, D>, MkTabEntry, ?> mTree) {
super.integrityCheckParameters(parentEntry, parent, index, mTree);
// test knn distances
- MkTabEntry<D> entry = parent.getEntry(index);
- List<D> knnDistances = kNNDistances(mTree.getDistanceQuery());
- if(!entry.getKnnDistances().equals(knnDistances)) {
+ MkTabEntry entry = parent.getEntry(index);
+ double[] knnDistances = kNNDistances();
+ if (!entry.getKnnDistances().equals(knnDistances)) {
String soll = knnDistances.toString();
String ist = entry.getKnnDistances().toString();
throw new RuntimeException("Wrong knnDistances in node " + parent.getPageID() + " at index " + index + " (child " + entry + ")" + "\nsoll: " + soll + ",\n ist: " + ist);
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/package-info.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/package-info.java
index 353acaa5..ed3e24d3 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/package-info.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/package-info.java
@@ -5,7 +5,7 @@
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
-Copyright (C) 2012
+Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/package-info.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/package-info.java
index 201d57c3..13b23e16 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/package-info.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/package-info.java
@@ -7,7 +7,7 @@
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
-Copyright (C) 2012
+Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mtree/MTree.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mtree/MTree.java
index 4276329c..1b3d1481 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mtree/MTree.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mtree/MTree.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mtree;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -24,12 +24,11 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mtree;
*/
import de.lmu.ifi.dbs.elki.database.ids.DBID;
-import de.lmu.ifi.dbs.elki.database.query.distance.DistanceQuery;
-import de.lmu.ifi.dbs.elki.distance.distancefunction.DistanceFunction;
-import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
+import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTree;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeDirectoryEntry;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeEntry;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeSettings;
import de.lmu.ifi.dbs.elki.logging.Logging;
import de.lmu.ifi.dbs.elki.persistent.PageFile;
import de.lmu.ifi.dbs.elki.utilities.documentation.Description;
@@ -41,6 +40,14 @@ import de.lmu.ifi.dbs.elki.utilities.documentation.Title;
* Apart from organizing the objects it also provides several methods to search
* for certain object in the structure. Persistence is not yet ensured.
*
+ * Reference:
+ * <p>
+ * P. Ciaccia, M. Patella, P. Zezula<br />
+ * M-tree: An Efficient Access Method for Similarity Search in Metric Spaces<br />
+ * In Proceedings of 23rd International Conference on Very Large Data Bases
+ * (VLDB'97), August 25-29, 1997, Athens, Greece
+ * </p>
+ *
* @author Elke Achtert
*
* @apiviz.has MTreeNode oneway - - contains
@@ -51,7 +58,7 @@ import de.lmu.ifi.dbs.elki.utilities.documentation.Title;
@Title("M-Tree")
@Description("Efficient Access Method for Similarity Search in Metric Spaces")
@Reference(authors = "P. Ciaccia, M. Patella, P. Zezula", title = "M-tree: An Efficient Access Method for Similarity Search in Metric Spaces", booktitle = "VLDB'97, Proceedings of 23rd International Conference on Very Large Data Bases, August 25-29, 1997, Athens, Greece", url = "http://www.vldb.org/conf/1997/P426.PDF")
-public class MTree<O, D extends Distance<D>> extends AbstractMTree<O, D, MTreeNode<O, D>, MTreeEntry<D>> {
+abstract public class MTree<O, D extends NumberDistance<D, ?>> extends AbstractMTree<O, D, MTreeNode<O, D>, MTreeEntry, MTreeSettings<O, D, MTreeNode<O, D>, MTreeEntry>> {
/**
* The logger for this class.
*/
@@ -61,77 +68,26 @@ public class MTree<O, D extends Distance<D>> extends AbstractMTree<O, D, MTreeNo
* Constructor.
*
* @param pagefile Page file
- * @param distanceQuery Distance query
- * @param distanceFunction Distance function
+ * @param settings Tree settings
*/
- public MTree(PageFile<MTreeNode<O, D>> pagefile, DistanceQuery<O, D> distanceQuery, DistanceFunction<O, D> distanceFunction) {
- super(pagefile, distanceQuery, distanceFunction);
+ public MTree(PageFile<MTreeNode<O, D>> pagefile, MTreeSettings<O, D, MTreeNode<O, D>, MTreeEntry> settings) {
+ super(pagefile, settings);
}
/**
* Does nothing because no operations are necessary before inserting an entry.
*/
@Override
- protected void preInsert(MTreeEntry<D> entry) {
+ protected void preInsert(MTreeEntry entry) {
// do nothing
}
- @Override
- protected void initializeCapacities(MTreeEntry<D> exampleLeaf) {
- int distanceSize = exampleLeaf.getParentDistance().externalizableSize();
-
- // FIXME: simulate a proper feature size!
- int featuresize = 0; // RelationUtil.dimensionality(relation);
-
- // overhead = index(4), numEntries(4), id(4), isLeaf(0.125)
- double overhead = 12.125;
- if(getPageSize() - overhead < 0) {
- throw new RuntimeException("Node size of " + getPageSize() + " Bytes is chosen too small!");
- }
-
- // dirCapacity = (pageSize - overhead) / (nodeID + objectID +
- // coveringRadius + parentDistance) + 1
- // dirCapacity = (int) (pageSize - overhead) / (4 + 4 + distanceSize +
- // distanceSize) + 1;
-
- // dirCapacity = (pageSize - overhead) / (nodeID + **object feature size** +
- // coveringRadius + parentDistance) + 1
- dirCapacity = (int) (getPageSize() - overhead) / (4 + featuresize + distanceSize + distanceSize) + 1;
-
- if(dirCapacity <= 2) {
- throw new RuntimeException("Node size of " + getPageSize() + " Bytes is chosen too small!");
- }
-
- if(dirCapacity < 10) {
- LOG.warning("Page size is choosen too small! Maximum number of entries " + "in a directory node = " + (dirCapacity - 1));
- }
- // leafCapacity = (pageSize - overhead) / (objectID + parentDistance) +
- // 1
- // leafCapacity = (int) (pageSize - overhead) / (4 + distanceSize) + 1;
- // leafCapacity = (pageSize - overhead) / (objectID + ** object size ** +
- // parentDistance) +
- // 1
- leafCapacity = (int) (getPageSize() - overhead) / (4 + featuresize + distanceSize) + 1;
-
- if(leafCapacity <= 1) {
- throw new RuntimeException("Node size of " + getPageSize() + " Bytes is chosen too small!");
- }
-
- if(leafCapacity < 10) {
- LOG.warning("Page size is choosen too small! Maximum number of entries " + "in a leaf node = " + (leafCapacity - 1));
- }
-
- if(LOG.isVerbose()) {
- LOG.verbose("Directory Capacity: " + (dirCapacity - 1) + "\nLeaf Capacity: " + (leafCapacity - 1));
- }
- }
-
/**
* @return a new MTreeDirectoryEntry representing the specified node
*/
@Override
- protected MTreeEntry<D> createNewDirectoryEntry(MTreeNode<O, D> node, DBID routingObjectID, D parentDistance) {
- return new MTreeDirectoryEntry<D>(routingObjectID, parentDistance, node.getPageID(), node.coveringRadius(routingObjectID, this));
+ protected MTreeEntry createNewDirectoryEntry(MTreeNode<O, D> node, DBID routingObjectID, double parentDistance) {
+ return new MTreeDirectoryEntry(routingObjectID, parentDistance, node.getPageID(), node.coveringRadius(routingObjectID, this));
}
/**
@@ -139,8 +95,8 @@ public class MTree<O, D extends Distance<D>> extends AbstractMTree<O, D, MTreeNo
* <code>new MTreeDirectoryEntry<D>(null, null, 0, null)</code>
*/
@Override
- protected MTreeEntry<D> createRootEntry() {
- return new MTreeDirectoryEntry<D>(null, null, 0, null);
+ protected MTreeEntry createRootEntry() {
+ return new MTreeDirectoryEntry(null, 0., 0, 0.);
}
/**
@@ -148,7 +104,7 @@ public class MTree<O, D extends Distance<D>> extends AbstractMTree<O, D, MTreeNo
*/
@Override
protected MTreeNode<O, D> createNewLeafNode() {
- return new MTreeNode<O, D>(leafCapacity, true);
+ return new MTreeNode<>(leafCapacity, true);
}
/**
@@ -156,11 +112,11 @@ public class MTree<O, D extends Distance<D>> extends AbstractMTree<O, D, MTreeNo
*/
@Override
protected MTreeNode<O, D> createNewDirectoryNode() {
- return new MTreeNode<O, D>(dirCapacity, false);
+ return new MTreeNode<>(dirCapacity, false);
}
@Override
protected Logging getLogger() {
return LOG;
}
-} \ No newline at end of file
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mtree/MTreeFactory.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mtree/MTreeFactory.java
index 5c5aac04..dbc27511 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mtree/MTreeFactory.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mtree/MTreeFactory.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mtree;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -24,11 +24,13 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mtree;
*/
import de.lmu.ifi.dbs.elki.database.relation.Relation;
-import de.lmu.ifi.dbs.elki.distance.distancefunction.DistanceFunction;
-import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
+import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTreeFactory;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeEntry;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeSettings;
import de.lmu.ifi.dbs.elki.persistent.PageFile;
+import de.lmu.ifi.dbs.elki.persistent.PageFileFactory;
+import de.lmu.ifi.dbs.elki.utilities.Alias;
import de.lmu.ifi.dbs.elki.utilities.ClassGenericsUtil;
/**
@@ -42,23 +44,22 @@ import de.lmu.ifi.dbs.elki.utilities.ClassGenericsUtil;
* @param <O> Object type
* @param <D> Distance type
*/
-public class MTreeFactory<O, D extends Distance<D>> extends AbstractMTreeFactory<O, D, MTreeNode<O, D>, MTreeEntry<D>, MTreeIndex<O, D>> {
+@Alias({ "mtree", "m" })
+public class MTreeFactory<O, D extends NumberDistance<D, ?>> extends AbstractMTreeFactory<O, D, MTreeNode<O, D>, MTreeEntry, MTreeIndex<O, D>, MTreeSettings<O, D, MTreeNode<O, D>, MTreeEntry>> {
/**
* Constructor.
*
- * @param fileName file name
- * @param pageSize page size
- * @param cacheSize cache size
- * @param distanceFunction Distance function
+ * @param pageFileFactory Data storage
+ * @param settings Tree settings
*/
- public MTreeFactory(String fileName, int pageSize, long cacheSize, DistanceFunction<O, D> distanceFunction) {
- super(fileName, pageSize, cacheSize, distanceFunction);
+ public MTreeFactory(PageFileFactory<?> pageFileFactory, MTreeSettings<O, D, MTreeNode<O, D>, MTreeEntry> settings) {
+ super(pageFileFactory, settings);
}
@Override
public MTreeIndex<O, D> instantiate(Relation<O> relation) {
PageFile<MTreeNode<O, D>> pagefile = makePageFile(getNodeClass());
- return new MTreeIndex<O, D>(relation, pagefile, distanceFunction.instantiate(relation), distanceFunction);
+ return new MTreeIndex<>(relation, pagefile, settings);
}
protected Class<MTreeNode<O, D>> getNodeClass() {
@@ -72,10 +73,15 @@ public class MTreeFactory<O, D extends Distance<D>> extends AbstractMTreeFactory
*
* @apiviz.exclude
*/
- public static class Parameterizer<O, D extends Distance<D>> extends AbstractMTreeFactory.Parameterizer<O, D> {
+ public static class Parameterizer<O, D extends NumberDistance<D, ?>> extends AbstractMTreeFactory.Parameterizer<O, D, MTreeNode<O, D>, MTreeEntry, MTreeSettings<O, D, MTreeNode<O, D>, MTreeEntry>> {
@Override
protected MTreeFactory<O, D> makeInstance() {
- return new MTreeFactory<O, D>(fileName, pageSize, cacheSize, distanceFunction);
+ return new MTreeFactory<>(pageFileFactory, settings);
+ }
+
+ @Override
+ protected MTreeSettings<O, D, MTreeNode<O, D>, MTreeEntry> makeSettings() {
+ return new MTreeSettings<>();
}
}
-} \ No newline at end of file
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mtree/MTreeIndex.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mtree/MTreeIndex.java
index 8afe1f2a..32908a1e 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mtree/MTreeIndex.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mtree/MTreeIndex.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mtree;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -26,6 +26,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mtree;
import java.util.ArrayList;
import java.util.List;
+import de.lmu.ifi.dbs.elki.data.FeatureVector;
import de.lmu.ifi.dbs.elki.database.ids.DBID;
import de.lmu.ifi.dbs.elki.database.ids.DBIDIter;
import de.lmu.ifi.dbs.elki.database.ids.DBIDRef;
@@ -36,64 +37,137 @@ import de.lmu.ifi.dbs.elki.database.query.distance.DistanceQuery;
import de.lmu.ifi.dbs.elki.database.query.knn.KNNQuery;
import de.lmu.ifi.dbs.elki.database.query.range.RangeQuery;
import de.lmu.ifi.dbs.elki.database.relation.Relation;
+import de.lmu.ifi.dbs.elki.database.relation.RelationUtil;
import de.lmu.ifi.dbs.elki.distance.distancefunction.DistanceFunction;
import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
+import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
+import de.lmu.ifi.dbs.elki.index.DynamicIndex;
import de.lmu.ifi.dbs.elki.index.KNNIndex;
import de.lmu.ifi.dbs.elki.index.RangeIndex;
-import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTree;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeEntry;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeLeafEntry;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeSettings;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.query.MTreeQueryUtil;
+import de.lmu.ifi.dbs.elki.persistent.ByteArrayUtil;
import de.lmu.ifi.dbs.elki.persistent.PageFile;
import de.lmu.ifi.dbs.elki.utilities.exceptions.ExceptionMessages;
+import de.lmu.ifi.dbs.elki.utilities.exceptions.NotImplementedException;
/**
* Class for using an m-tree as database index.
*
* @author Erich Schubert
- *
+ *
* @param <O> Object type
* @param <D> Distance type
*/
-public class MTreeIndex<O, D extends Distance<D>> extends MTree<O, D> implements RangeIndex<O>, KNNIndex<O> {
+public class MTreeIndex<O, D extends NumberDistance<D, ?>> extends MTree<O, D> implements RangeIndex<O>, KNNIndex<O>, DynamicIndex {
/**
* The relation indexed.
*/
private Relation<O> relation;
/**
+ * The distance query.
+ */
+ protected DistanceQuery<O, D> distanceQuery;
+
+ /**
* Constructor.
- *
+ *
* @param relation Relation indexed
* @param pagefile Page file
- * @param distanceQuery Distance query
- * @param distanceFunction Distance function
+ * @param settings Tree settings
*/
- public MTreeIndex(Relation<O> relation, PageFile<MTreeNode<O, D>> pagefile, DistanceQuery<O, D> distanceQuery, DistanceFunction<O, D> distanceFunction) {
- super(pagefile, distanceQuery, distanceFunction);
+ public MTreeIndex(Relation<O> relation, PageFile<MTreeNode<O, D>> pagefile, MTreeSettings<O, D, MTreeNode<O, D>, MTreeEntry> settings) {
+ super(pagefile, settings);
this.relation = relation;
- this.initialize();
+ this.distanceQuery = getDistanceFunction().instantiate(relation);
+ }
+
+ @Override
+ public D distance(DBIDRef id1, DBIDRef id2) {
+ if (id1 == null || id2 == null) {
+ return getDistanceFactory().undefinedDistance();
+ }
+ statistics.countDistanceCalculation();
+ return distanceQuery.distance(id1, id2);
+ }
+
+ @Override
+ protected void initializeCapacities(MTreeEntry exampleLeaf) {
+ int distanceSize = ByteArrayUtil.SIZE_DOUBLE; // exampleLeaf.getParentDistance().externalizableSize();
+
+ // FIXME: simulate a proper feature size!
+ @SuppressWarnings("unchecked")
+ int featuresize = 8 * RelationUtil.dimensionality((Relation<? extends FeatureVector<?>>) relation);
+ if (featuresize <= 0) {
+ getLogger().warning("Relation does not have a dimensionality -- simulating M-tree as external index!");
+ featuresize = 0;
+ }
+
+ // overhead = index(4), numEntries(4), id(4), isLeaf(0.125)
+ double overhead = 12.125;
+ if (getPageSize() - overhead < 0) {
+ throw new RuntimeException("Node size of " + getPageSize() + " Bytes is chosen too small!");
+ }
+
+ // dirCapacity = (pageSize - overhead) / (nodeID + objectID + coveringRadius
+ // + parentDistance) + 1
+ // dirCapacity = (int) (pageSize - overhead) / (4 + 4 + distanceSize +
+ // distanceSize) + 1;
+
+ // dirCapacity = (pageSize - overhead) / (nodeID + **object feature size** +
+ // coveringRadius + parentDistance) + 1
+ dirCapacity = (int) (getPageSize() - overhead) / (4 + featuresize + distanceSize + distanceSize) + 1;
+
+ if (dirCapacity <= 2) {
+ throw new RuntimeException("Node size of " + getPageSize() + " Bytes is chosen too small!");
+ }
+
+ if (dirCapacity < 10) {
+ getLogger().warning("Page size is choosen too small! Maximum number of entries " + "in a directory node = " + (dirCapacity - 1));
+ }
+ // leafCapacity = (pageSize - overhead) / (objectID + parentDistance) + 1
+ // leafCapacity = (int) (pageSize - overhead) / (4 + distanceSize) + 1;
+ // leafCapacity = (pageSize - overhead) / (objectID + ** object size ** +
+ // parentDistance) + 1
+ leafCapacity = (int) (getPageSize() - overhead) / (4 + featuresize + distanceSize) + 1;
+
+ if (leafCapacity <= 1) {
+ throw new RuntimeException("Node size of " + getPageSize() + " Bytes is chosen too small!");
+ }
+
+ if (leafCapacity < 10) {
+ getLogger().warning("Page size is choosen too small! Maximum number of entries " + "in a leaf node = " + (leafCapacity - 1));
+ }
}
/**
* @return a new MTreeLeafEntry representing the specified data object
*/
- protected MTreeEntry<D> createNewLeafEntry(DBID id, O object, D parentDistance) {
- return new MTreeLeafEntry<D>(id, parentDistance);
+ protected MTreeEntry createNewLeafEntry(DBID id, O object, double parentDistance) {
+ return new MTreeLeafEntry(id, parentDistance);
+ }
+
+ @Override
+ public void initialize() {
+ super.initialize();
+ insertAll(relation.getDBIDs());
}
@Override
public void insert(DBIDRef id) {
- insert(createNewLeafEntry(DBIDUtil.deref(id), relation.get(id), getDistanceFactory().undefinedDistance()), false);
+ insert(createNewLeafEntry(DBIDUtil.deref(id), relation.get(id), Double.NaN), false);
}
@Override
public void insertAll(DBIDs ids) {
- List<MTreeEntry<D>> objs = new ArrayList<MTreeEntry<D>>(ids.size());
+ List<MTreeEntry> objs = new ArrayList<>(ids.size());
for (DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) {
DBID id = DBIDUtil.deref(iter);
final O object = relation.get(id);
- objs.add(createNewLeafEntry(id, object, getDistanceFactory().undefinedDistance()));
+ objs.add(createNewLeafEntry(id, object, Double.NaN));
}
insertAll(objs);
}
@@ -107,7 +181,7 @@ public class MTreeIndex<O, D extends Distance<D>> extends MTree<O, D> implements
*/
@Override
public final boolean delete(DBIDRef id) {
- throw new UnsupportedOperationException(ExceptionMessages.UNSUPPORTED_NOT_YET);
+ throw new NotImplementedException(ExceptionMessages.UNSUPPORTED_NOT_YET);
}
/**
@@ -119,57 +193,55 @@ public class MTreeIndex<O, D extends Distance<D>> extends MTree<O, D> implements
*/
@Override
public void deleteAll(DBIDs ids) {
- throw new UnsupportedOperationException(ExceptionMessages.UNSUPPORTED_NOT_YET);
+ throw new NotImplementedException(ExceptionMessages.UNSUPPORTED_NOT_YET);
}
@SuppressWarnings("unchecked")
@Override
public <S extends Distance<S>> KNNQuery<O, S> getKNNQuery(DistanceQuery<O, S> distanceQuery, Object... hints) {
// Query on the relation we index
- if(distanceQuery.getRelation() != relation) {
+ if (distanceQuery.getRelation() != relation) {
return null;
}
- DistanceFunction<? super O, S> distanceFunction = distanceQuery.getDistanceFunction();
- if(!this.distanceFunction.equals(distanceFunction)) {
- if(getLogger().isDebugging()) {
+ DistanceFunction<? super O, D> distanceFunction = (DistanceFunction<? super O, D>) distanceQuery.getDistanceFunction();
+ if (!this.getDistanceFunction().equals(distanceFunction)) {
+ if (getLogger().isDebugging()) {
getLogger().debug("Distance function not supported by index - or 'equals' not implemented right!");
}
return null;
}
// Bulk is not yet supported
- for(Object hint : hints) {
- if(hint == DatabaseQuery.HINT_BULK) {
+ for (Object hint : hints) {
+ if (hint == DatabaseQuery.HINT_BULK) {
return null;
}
}
- AbstractMTree<O, S, ?, ?> idx = (AbstractMTree<O, S, ?, ?>) this;
- DistanceQuery<O, S> dq = distanceFunction.instantiate(relation);
- return MTreeQueryUtil.getKNNQuery(idx, dq, hints);
+ DistanceQuery<O, D> dq = distanceFunction.instantiate(relation);
+ return (KNNQuery<O, S>) MTreeQueryUtil.getKNNQuery(this, dq, hints);
}
@SuppressWarnings("unchecked")
@Override
public <S extends Distance<S>> RangeQuery<O, S> getRangeQuery(DistanceQuery<O, S> distanceQuery, Object... hints) {
// Query on the relation we index
- if(distanceQuery.getRelation() != relation) {
+ if (distanceQuery.getRelation() != relation) {
return null;
}
- DistanceFunction<? super O, S> distanceFunction = distanceQuery.getDistanceFunction();
- if(!this.distanceFunction.equals(distanceFunction)) {
- if(getLogger().isDebugging()) {
+ DistanceFunction<? super O, D> distanceFunction = (DistanceFunction<? super O, D>) distanceQuery.getDistanceFunction();
+ if (!this.getDistanceFunction().equals(distanceFunction)) {
+ if (getLogger().isDebugging()) {
getLogger().debug("Distance function not supported by index - or 'equals' not implemented right!");
}
return null;
}
// Bulk is not yet supported
- for(Object hint : hints) {
- if(hint == DatabaseQuery.HINT_BULK) {
+ for (Object hint : hints) {
+ if (hint == DatabaseQuery.HINT_BULK) {
return null;
}
}
- AbstractMTree<O, S, ?, ?> idx = (AbstractMTree<O, S, ?, ?>) this;
- DistanceQuery<O, S> dq = distanceFunction.instantiate(relation);
- return MTreeQueryUtil.getRangeQuery(idx, dq);
+ DistanceQuery<O, D> dq = distanceFunction.instantiate(relation);
+ return (RangeQuery<O, S>) MTreeQueryUtil.getRangeQuery(this, dq);
}
@Override
@@ -181,4 +253,4 @@ public class MTreeIndex<O, D extends Distance<D>> extends MTree<O, D> implements
public String getShortName() {
return "mtree";
}
-} \ No newline at end of file
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mtree/MTreeNode.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mtree/MTreeNode.java
index 017e7d6c..b3aa77fb 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mtree/MTreeNode.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mtree/MTreeNode.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mtree;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -23,7 +23,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mtree;
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
+import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTreeNode;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeEntry;
@@ -34,7 +34,7 @@ import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeEntry;
* @param <O> Object type
* @param <D> Distance type
*/
-public class MTreeNode<O, D extends Distance<D>> extends AbstractMTreeNode<O, D, MTreeNode<O, D>, MTreeEntry<D>> {
+public class MTreeNode<O, D extends NumberDistance<D, ?>> extends AbstractMTreeNode<O, D, MTreeNode<O, D>, MTreeEntry> {
/**
* Serial version
*/
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mtree/package-info.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mtree/package-info.java
index a34162a8..c10d683b 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mtree/package-info.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mtree/package-info.java
@@ -5,7 +5,7 @@
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
-Copyright (C) 2012
+Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/package-info.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/package-info.java
index b30d1193..03a4a4d6 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/package-info.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/package-info.java
@@ -5,7 +5,7 @@
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
-Copyright (C) 2012
+Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/DoubleDistanceMetricalIndexKNNQuery.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/DoubleDistanceMetricalIndexKNNQuery.java
index 52f777ba..9eb72178 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/DoubleDistanceMetricalIndexKNNQuery.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/DoubleDistanceMetricalIndexKNNQuery.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.query;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -23,24 +23,20 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.query;
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-import java.util.List;
-
-import de.lmu.ifi.dbs.elki.database.ids.ArrayDBIDs;
import de.lmu.ifi.dbs.elki.database.ids.DBID;
-import de.lmu.ifi.dbs.elki.database.ids.DBIDRef;
+import de.lmu.ifi.dbs.elki.database.ids.DBIDUtil;
+import de.lmu.ifi.dbs.elki.database.ids.distance.DoubleDistanceKNNHeap;
+import de.lmu.ifi.dbs.elki.database.ids.distance.KNNList;
import de.lmu.ifi.dbs.elki.database.query.distance.DistanceQuery;
import de.lmu.ifi.dbs.elki.database.query.knn.AbstractDistanceKNNQuery;
import de.lmu.ifi.dbs.elki.distance.distancefunction.PrimitiveDoubleDistanceFunction;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.DoubleDistanceKNNHeap;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.KNNResult;
import de.lmu.ifi.dbs.elki.distance.distancevalue.DoubleDistance;
import de.lmu.ifi.dbs.elki.index.tree.DirectoryEntry;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTree;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTreeNode;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeEntry;
import de.lmu.ifi.dbs.elki.index.tree.query.DoubleMTreeDistanceSearchCandidate;
-import de.lmu.ifi.dbs.elki.utilities.datastructures.heap.Heap;
-import de.lmu.ifi.dbs.elki.utilities.exceptions.ExceptionMessages;
+import de.lmu.ifi.dbs.elki.utilities.datastructures.heap.ComparableMinHeap;
/**
* Instance of a KNN query for a particular spatial index.
@@ -55,7 +51,7 @@ public class DoubleDistanceMetricalIndexKNNQuery<O> extends AbstractDistanceKNNQ
/**
* The index to use
*/
- protected final AbstractMTree<O, DoubleDistance, ?, ?> index;
+ protected final AbstractMTree<O, DoubleDistance, ?, ?, ?> index;
/**
* Distance function
@@ -69,22 +65,23 @@ public class DoubleDistanceMetricalIndexKNNQuery<O> extends AbstractDistanceKNNQ
* @param distanceQuery Distance query used
* @param distf Distance function
*/
- public DoubleDistanceMetricalIndexKNNQuery(AbstractMTree<O, DoubleDistance, ?, ?> index, DistanceQuery<O, DoubleDistance> distanceQuery, PrimitiveDoubleDistanceFunction<? super O> distf) {
+ public DoubleDistanceMetricalIndexKNNQuery(AbstractMTree<O, DoubleDistance, ?, ?, ?> index, DistanceQuery<O, DoubleDistance> distanceQuery, PrimitiveDoubleDistanceFunction<? super O> distf) {
super(distanceQuery);
this.index = index;
this.distf = distf;
}
@Override
- public KNNResult<DoubleDistance> getKNNForObject(O q, int k) {
+ public KNNList<DoubleDistance> getKNNForObject(O q, int k) {
if (k < 1) {
throw new IllegalArgumentException("At least one object has to be requested!");
}
+ index.statistics.countKNNQuery();
- DoubleDistanceKNNHeap knnList = new DoubleDistanceKNNHeap(k);
+ DoubleDistanceKNNHeap knnList = (DoubleDistanceKNNHeap) DBIDUtil.newHeap(DoubleDistance.FACTORY, k);
double d_k = Double.POSITIVE_INFINITY;
- final Heap<DoubleMTreeDistanceSearchCandidate> pq = new Heap<DoubleMTreeDistanceSearchCandidate>();
+ final ComparableMinHeap<DoubleMTreeDistanceSearchCandidate> pq = new ComparableMinHeap<>();
// Push the root node
pq.add(new DoubleMTreeDistanceSearchCandidate(0, index.getRootID(), null, 0));
@@ -104,15 +101,16 @@ public class DoubleDistanceMetricalIndexKNNQuery<O> extends AbstractDistanceKNNQ
// directory node
if (!node.isLeaf()) {
for (int i = 0; i < node.getNumEntries(); i++) {
- final MTreeEntry<DoubleDistance> entry = node.getEntry(i);
+ final MTreeEntry entry = node.getEntry(i);
final DBID id_i = entry.getRoutingObjectID();
- double or_i = entry.getCoveringRadius().doubleValue();
- double d2 = id_p != null ? entry.getParentDistance().doubleValue() : 0;
+ double or_i = entry.getCoveringRadius();
+ double d2 = id_p != null ? entry.getParentDistance() : 0;
double diff = Math.abs(d1 - d2);
if (diff <= d_k + or_i) {
final O ob_i = relation.get(id_i);
double d3 = distf.doubleDistance(ob_i, q);
+ index.statistics.countDistanceCalculation();
double d_min = Math.max(d3 - or_i, 0);
if (d_min <= d_k) {
pq.add(new DoubleMTreeDistanceSearchCandidate(d_min, ((DirectoryEntry) entry).getPageID(), id_i, d3));
@@ -123,14 +121,15 @@ public class DoubleDistanceMetricalIndexKNNQuery<O> extends AbstractDistanceKNNQ
// data node
else {
for (int i = 0; i < node.getNumEntries(); i++) {
- final MTreeEntry<DoubleDistance> entry = node.getEntry(i);
+ final MTreeEntry entry = node.getEntry(i);
final DBID id_i = entry.getRoutingObjectID();
- double d2 = id_p != null ? entry.getParentDistance().doubleValue() : 0;
+ double d2 = id_p != null ? entry.getParentDistance() : 0;
double diff = Math.abs(d1 - d2);
if (diff <= d_k) {
final O o_i = relation.get(id_i);
double d3 = distf.doubleDistance(o_i, q);
+ index.statistics.countDistanceCalculation();
if (d3 <= d_k) {
knnList.add(d3, id_i);
d_k = knnList.doubleKNNDistance();
@@ -141,15 +140,4 @@ public class DoubleDistanceMetricalIndexKNNQuery<O> extends AbstractDistanceKNNQ
}
return knnList.toKNNList();
}
-
- @Override
- public KNNResult<DoubleDistance> getKNNForDBID(DBIDRef id, int k) {
- return getKNNForObject(relation.get(id), k);
- }
-
- @Override
- public List<KNNResult<DoubleDistance>> getKNNForBulkDBIDs(ArrayDBIDs ids, int k) {
- // TODO: implement
- throw new UnsupportedOperationException(ExceptionMessages.UNSUPPORTED_NOT_YET);
- }
}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/DoubleDistanceMetricalIndexRangeQuery.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/DoubleDistanceMetricalIndexRangeQuery.java
index c3680111..714498d4 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/DoubleDistanceMetricalIndexRangeQuery.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/DoubleDistanceMetricalIndexRangeQuery.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.query;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -24,12 +24,12 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.query;
*/
import de.lmu.ifi.dbs.elki.database.ids.DBID;
-import de.lmu.ifi.dbs.elki.database.ids.DBIDRef;
+import de.lmu.ifi.dbs.elki.database.ids.distance.DistanceDBIDList;
+import de.lmu.ifi.dbs.elki.database.ids.distance.DoubleDistanceDBIDPairList;
+import de.lmu.ifi.dbs.elki.database.ids.distance.ModifiableDoubleDistanceDBIDList;
import de.lmu.ifi.dbs.elki.database.query.distance.DistanceQuery;
import de.lmu.ifi.dbs.elki.database.query.range.AbstractDistanceRangeQuery;
import de.lmu.ifi.dbs.elki.distance.distancefunction.PrimitiveDoubleDistanceFunction;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.DistanceDBIDResult;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.DoubleDistanceDBIDList;
import de.lmu.ifi.dbs.elki.distance.distancevalue.DoubleDistance;
import de.lmu.ifi.dbs.elki.index.tree.DirectoryEntry;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTree;
@@ -47,7 +47,7 @@ public class DoubleDistanceMetricalIndexRangeQuery<O> extends AbstractDistanceRa
/**
* The index to use
*/
- protected final AbstractMTree<O, DoubleDistance, ?, ?> index;
+ protected final AbstractMTree<O, DoubleDistance, ?, ?, ?> index;
/**
* Distance function
@@ -61,7 +61,7 @@ public class DoubleDistanceMetricalIndexRangeQuery<O> extends AbstractDistanceRa
* @param distanceQuery Distance query used
* @param distf Distance function
*/
- public DoubleDistanceMetricalIndexRangeQuery(AbstractMTree<O, DoubleDistance, ?, ?> index, DistanceQuery<O, DoubleDistance> distanceQuery, PrimitiveDoubleDistanceFunction<? super O> distf) {
+ public DoubleDistanceMetricalIndexRangeQuery(AbstractMTree<O, DoubleDistance, ?, ?, ?> index, DistanceQuery<O, DoubleDistance> distanceQuery, PrimitiveDoubleDistanceFunction<? super O> distf) {
super(distanceQuery);
this.index = index;
this.distf = distf;
@@ -78,15 +78,19 @@ public class DoubleDistanceMetricalIndexRangeQuery<O> extends AbstractDistanceRa
* @param r_q the query range
* @param result the list holding the query results
*/
- private void doRangeQuery(DBID id_p, AbstractMTreeNode<O, DoubleDistance, ?, ?> node, O q, double r_q, DoubleDistanceDBIDList result) {
+ private void doRangeQuery(DBID id_p, AbstractMTreeNode<O, DoubleDistance, ?, ?> node, O q, double r_q, ModifiableDoubleDistanceDBIDList result) {
final O o_p = id_p != null ? relation.get(id_p) : null;
- double d1 = id_p != null ? distf.doubleDistance(o_p, q) : 0;
+ double d1 = 0.;
+ if (id_p != null) {
+ d1 = distf.doubleDistance(o_p, q);
+ index.statistics.countDistanceCalculation();
+ }
if (!node.isLeaf()) {
for (int i = 0; i < node.getNumEntries(); i++) {
- MTreeEntry<DoubleDistance> entry = node.getEntry(i);
+ MTreeEntry entry = node.getEntry(i);
- double r_or = entry.getCoveringRadius().doubleValue();
- double d2 = id_p != null ? entry.getParentDistance().doubleValue() : 0;
+ double r_or = entry.getCoveringRadius();
+ double d2 = id_p != null ? entry.getParentDistance() : 0;
double diff = Math.abs(d1 - d2);
double sum = r_q + r_or;
@@ -94,6 +98,7 @@ public class DoubleDistanceMetricalIndexRangeQuery<O> extends AbstractDistanceRa
if (diff <= sum) {
DBID id_r = entry.getRoutingObjectID();
double d3 = distf.doubleDistance(relation.get(id_r), q);
+ index.statistics.countDistanceCalculation();
if (d3 <= sum) {
AbstractMTreeNode<O, DoubleDistance, ?, ?> child = index.getNode(((DirectoryEntry) entry).getPageID());
doRangeQuery(id_r, child, q, r_q, result);
@@ -102,15 +107,16 @@ public class DoubleDistanceMetricalIndexRangeQuery<O> extends AbstractDistanceRa
}
} else {
for (int i = 0; i < node.getNumEntries(); i++) {
- MTreeEntry<DoubleDistance> entry = node.getEntry(i);
+ MTreeEntry entry = node.getEntry(i);
- double d2 = id_p != null ? entry.getParentDistance().doubleValue() : 0;
+ double d2 = id_p != null ? entry.getParentDistance() : 0;
double diff = Math.abs(d1 - d2);
if (diff <= r_q) {
DBID id_j = entry.getRoutingObjectID();
O o_j = relation.get(id_j);
double d3 = distf.doubleDistance(o_j, q);
+ index.statistics.countDistanceCalculation();
if (d3 <= r_q) {
result.add(d3, id_j);
}
@@ -120,16 +126,12 @@ public class DoubleDistanceMetricalIndexRangeQuery<O> extends AbstractDistanceRa
}
@Override
- public DistanceDBIDResult<DoubleDistance> getRangeForObject(O obj, DoubleDistance range) {
- final DoubleDistanceDBIDList result = new DoubleDistanceDBIDList();
+ public DistanceDBIDList<DoubleDistance> getRangeForObject(O obj, DoubleDistance range) {
+ final DoubleDistanceDBIDPairList result = new DoubleDistanceDBIDPairList();
doRangeQuery(null, index.getRoot(), obj, range.doubleValue(), result);
+ index.statistics.countRangeQuery();
result.sort();
return result;
}
-
- @Override
- public DistanceDBIDResult<DoubleDistance> getRangeForDBID(DBIDRef id, DoubleDistance range) {
- return getRangeForObject(relation.get(id), range);
- }
}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/MTreeQueryUtil.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/MTreeQueryUtil.java
index 34980542..cc27b383 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/MTreeQueryUtil.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/MTreeQueryUtil.java
@@ -5,15 +5,15 @@ import de.lmu.ifi.dbs.elki.database.query.knn.KNNQuery;
import de.lmu.ifi.dbs.elki.database.query.range.RangeQuery;
import de.lmu.ifi.dbs.elki.distance.distancefunction.DistanceFunction;
import de.lmu.ifi.dbs.elki.distance.distancefunction.PrimitiveDoubleDistanceFunction;
-import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
import de.lmu.ifi.dbs.elki.distance.distancevalue.DoubleDistance;
+import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTree;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -50,17 +50,17 @@ public final class MTreeQueryUtil {
* @return Query object
*/
@SuppressWarnings({ "cast", "unchecked" })
- public static <O, D extends Distance<D>> KNNQuery<O, D> getKNNQuery(AbstractMTree<O, D, ?, ?> tree, DistanceQuery<O, D> distanceQuery, Object... hints) {
+ public static <O, D extends NumberDistance<D, ?>> KNNQuery<O, D> getKNNQuery(AbstractMTree<O, D, ?, ?, ?> tree, DistanceQuery<O, D> distanceQuery, Object... hints) {
DistanceFunction<? super O, D> df = distanceQuery.getDistanceFunction();
// Can we use an optimized query?
- if(df instanceof PrimitiveDoubleDistanceFunction) {
+ if (df instanceof PrimitiveDoubleDistanceFunction) {
PrimitiveDoubleDistanceFunction<? super O> dfc = (PrimitiveDoubleDistanceFunction<? super O>) df;
- AbstractMTree<O, DoubleDistance, ?, ?> treec = (AbstractMTree<O, DoubleDistance, ?, ?>) tree;
+ AbstractMTree<O, DoubleDistance, ?, ?, ?> treec = (AbstractMTree<O, DoubleDistance, ?, ?, ?>) tree;
DistanceQuery<O, DoubleDistance> dqc = (DistanceQuery<O, DoubleDistance>) distanceQuery;
- KNNQuery<O, ?> q = new DoubleDistanceMetricalIndexKNNQuery<O>(treec, dqc, dfc);
+ KNNQuery<O, ?> q = new DoubleDistanceMetricalIndexKNNQuery<>(treec, dqc, dfc);
return (KNNQuery<O, D>) q;
}
- return new MetricalIndexKNNQuery<O, D>(tree, distanceQuery);
+ return new MetricalIndexKNNQuery<>(tree, distanceQuery);
}
/**
@@ -75,16 +75,16 @@ public final class MTreeQueryUtil {
* @return Query object
*/
@SuppressWarnings({ "cast", "unchecked" })
- public static <O, D extends Distance<D>> RangeQuery<O, D> getRangeQuery(AbstractMTree<O, D, ?, ?> tree, DistanceQuery<O, D> distanceQuery, Object... hints) {
+ public static <O, D extends NumberDistance<D, ?>> RangeQuery<O, D> getRangeQuery(AbstractMTree<O, D, ?, ?, ?> tree, DistanceQuery<O, D> distanceQuery, Object... hints) {
DistanceFunction<? super O, D> df = distanceQuery.getDistanceFunction();
// Can we use an optimized query?
- if(df instanceof PrimitiveDoubleDistanceFunction) {
+ if (df instanceof PrimitiveDoubleDistanceFunction) {
PrimitiveDoubleDistanceFunction<? super O> dfc = (PrimitiveDoubleDistanceFunction<? super O>) df;
- AbstractMTree<O, DoubleDistance, ?, ?> treec = (AbstractMTree<O, DoubleDistance, ?, ?>) tree;
+ AbstractMTree<O, DoubleDistance, ?, ?, ?> treec = (AbstractMTree<O, DoubleDistance, ?, ?, ?>) tree;
DistanceQuery<O, DoubleDistance> dqc = (DistanceQuery<O, DoubleDistance>) distanceQuery;
- RangeQuery<O, ?> q = new DoubleDistanceMetricalIndexRangeQuery<O>(treec, dqc, dfc);
+ RangeQuery<O, ?> q = new DoubleDistanceMetricalIndexRangeQuery<>(treec, dqc, dfc);
return (RangeQuery<O, D>) q;
}
- return new MetricalIndexRangeQuery<O, D>(tree, distanceQuery);
+ return new MetricalIndexRangeQuery<>(tree, distanceQuery);
}
}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/MetricalIndexKNNQuery.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/MetricalIndexKNNQuery.java
index c2fafdae..f40e001b 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/MetricalIndexKNNQuery.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/MetricalIndexKNNQuery.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.query;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -23,25 +23,19 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.query;
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-import java.util.List;
-
-import de.lmu.ifi.dbs.elki.database.ids.ArrayDBIDs;
import de.lmu.ifi.dbs.elki.database.ids.DBID;
-import de.lmu.ifi.dbs.elki.database.ids.DBIDRef;
+import de.lmu.ifi.dbs.elki.database.ids.DBIDUtil;
+import de.lmu.ifi.dbs.elki.database.ids.distance.KNNHeap;
+import de.lmu.ifi.dbs.elki.database.ids.distance.KNNList;
import de.lmu.ifi.dbs.elki.database.query.distance.DistanceQuery;
import de.lmu.ifi.dbs.elki.database.query.knn.AbstractDistanceKNNQuery;
-import de.lmu.ifi.dbs.elki.distance.DistanceUtil;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.KNNHeap;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.KNNResult;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.KNNUtil;
-import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
+import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
import de.lmu.ifi.dbs.elki.index.tree.DirectoryEntry;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTree;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTreeNode;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeEntry;
-import de.lmu.ifi.dbs.elki.index.tree.query.GenericMTreeDistanceSearchCandidate;
-import de.lmu.ifi.dbs.elki.utilities.datastructures.heap.Heap;
-import de.lmu.ifi.dbs.elki.utilities.exceptions.ExceptionMessages;
+import de.lmu.ifi.dbs.elki.index.tree.query.DoubleMTreeDistanceSearchCandidate;
+import de.lmu.ifi.dbs.elki.utilities.datastructures.heap.ComparableMinHeap;
/**
* Instance of a KNN query for a particular spatial index.
@@ -53,11 +47,11 @@ import de.lmu.ifi.dbs.elki.utilities.exceptions.ExceptionMessages;
* @param <O> Object type
* @param <D> Distance type
*/
-public class MetricalIndexKNNQuery<O, D extends Distance<D>> extends AbstractDistanceKNNQuery<O, D> {
+public class MetricalIndexKNNQuery<O, D extends NumberDistance<D, ?>> extends AbstractDistanceKNNQuery<O, D> {
/**
* The index to use
*/
- protected final AbstractMTree<O, D, ?, ?> index;
+ protected final AbstractMTree<O, D, ?, ?, ?> index;
/**
* Constructor.
@@ -65,55 +59,56 @@ public class MetricalIndexKNNQuery<O, D extends Distance<D>> extends AbstractDis
* @param index Index to use
* @param distanceQuery Distance query used
*/
- public MetricalIndexKNNQuery(AbstractMTree<O, D, ?, ?> index, DistanceQuery<O, D> distanceQuery) {
+ public MetricalIndexKNNQuery(AbstractMTree<O, D, ?, ?, ?> index, DistanceQuery<O, D> distanceQuery) {
super(distanceQuery);
this.index = index;
}
@Override
- public KNNResult<D> getKNNForObject(O q, int k) {
+ public KNNList<D> getKNNForObject(O q, int k) {
if (k < 1) {
throw new IllegalArgumentException("At least one object has to be requested!");
}
+ index.statistics.countKNNQuery();
- final D nullDistance = index.getDistanceFactory().nullDistance();
- KNNHeap<D> knnList = KNNUtil.newHeap(distanceQuery.getDistanceFactory(), k);
+ KNNHeap<D> knnList = DBIDUtil.newHeap(distanceQuery.getDistanceFactory(), k);
D d_k = knnList.getKNNDistance();
- final Heap<GenericMTreeDistanceSearchCandidate<D>> pq = new Heap<GenericMTreeDistanceSearchCandidate<D>>();
+ final ComparableMinHeap<DoubleMTreeDistanceSearchCandidate> pq = new ComparableMinHeap<>();
// push root
- pq.add(new GenericMTreeDistanceSearchCandidate<D>(nullDistance, index.getRootID(), null, nullDistance));
+ pq.add(new DoubleMTreeDistanceSearchCandidate(0., index.getRootID(), null, 0.));
// search in tree
while (!pq.isEmpty()) {
- GenericMTreeDistanceSearchCandidate<D> pqNode = pq.poll();
+ DoubleMTreeDistanceSearchCandidate pqNode = pq.poll();
- if (knnList.size() >= k && pqNode.mindist.compareTo(d_k) > 0) {
+ if (knnList.size() >= k && pqNode.mindist > d_k.doubleValue()) {
break;
}
AbstractMTreeNode<?, D, ?, ?> node = index.getNode(pqNode.nodeID);
DBID id_p = pqNode.routingObjectID;
- D d1 = pqNode.routingDistance;
+ double d1 = pqNode.routingDistance;
// directory node
if (!node.isLeaf()) {
for (int i = 0; i < node.getNumEntries(); i++) {
- MTreeEntry<D> entry = node.getEntry(i);
+ MTreeEntry entry = node.getEntry(i);
DBID o_r = entry.getRoutingObjectID();
- D r_or = entry.getCoveringRadius();
- D d2 = id_p != null ? entry.getParentDistance() : nullDistance;
+ double r_or = entry.getCoveringRadius();
+ double d2 = id_p != null ? entry.getParentDistance() : 0.;
- D diff = d1.compareTo(d2) > 0 ? d1.minus(d2) : d2.minus(d1);
+ double diff = Math.abs(d1 - d2);
- D sum = d_k.plus(r_or);
+ double sum = d_k.doubleValue() + r_or;
- if (diff.compareTo(sum) <= 0) {
- D d3 = distanceQuery.distance(o_r, q);
- D d_min = DistanceUtil.max(d3.minus(r_or), index.getDistanceFactory().nullDistance());
- if (d_min.compareTo(d_k) <= 0) {
- pq.add(new GenericMTreeDistanceSearchCandidate<D>(d_min, ((DirectoryEntry) entry).getPageID(), o_r, d3));
+ if (diff <= sum) {
+ double d3 = distanceQuery.distance(o_r, q).doubleValue();
+ index.statistics.countDistanceCalculation();
+ double d_min = Math.max(d3 - r_or, 0.);
+ if (d_min <= d_k.doubleValue()) {
+ pq.add(new DoubleMTreeDistanceSearchCandidate(d_min, ((DirectoryEntry) entry).getPageID(), o_r, d3));
}
}
}
@@ -121,15 +116,16 @@ public class MetricalIndexKNNQuery<O, D extends Distance<D>> extends AbstractDis
// data node
else {
for (int i = 0; i < node.getNumEntries(); i++) {
- MTreeEntry<D> entry = node.getEntry(i);
+ MTreeEntry entry = node.getEntry(i);
DBID o_j = entry.getRoutingObjectID();
- D d2 = id_p != null ? entry.getParentDistance() : nullDistance;
+ double d2 = id_p != null ? entry.getParentDistance() : 0.;
- D diff = (d1.compareTo(d2) > 0) ? d1.minus(d2) : d2.minus(d1);
+ double diff = Math.abs(d1 - d2);
- if (diff.compareTo(d_k) <= 0) {
+ if (diff <= d_k.doubleValue()) {
D d3 = distanceQuery.distance(o_j, q);
+ index.statistics.countDistanceCalculation();
if (d3.compareTo(d_k) <= 0) {
knnList.add(d3, o_j);
d_k = knnList.getKNNDistance();
@@ -140,15 +136,4 @@ public class MetricalIndexKNNQuery<O, D extends Distance<D>> extends AbstractDis
}
return knnList.toKNNList();
}
-
- @Override
- public KNNResult<D> getKNNForDBID(DBIDRef id, int k) {
- return getKNNForObject(relation.get(id), k);
- }
-
- @Override
- public List<KNNResult<D>> getKNNForBulkDBIDs(ArrayDBIDs ids, int k) {
- // TODO: implement
- throw new UnsupportedOperationException(ExceptionMessages.UNSUPPORTED_NOT_YET);
- }
}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/MetricalIndexRangeQuery.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/MetricalIndexRangeQuery.java
index 2ca19877..fedf8ddb 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/MetricalIndexRangeQuery.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/MetricalIndexRangeQuery.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.query;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -24,12 +24,11 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.query;
*/
import de.lmu.ifi.dbs.elki.database.ids.DBID;
-import de.lmu.ifi.dbs.elki.database.ids.DBIDRef;
+import de.lmu.ifi.dbs.elki.database.ids.distance.DistanceDBIDList;
+import de.lmu.ifi.dbs.elki.database.ids.generic.GenericDistanceDBIDList;
import de.lmu.ifi.dbs.elki.database.query.distance.DistanceQuery;
import de.lmu.ifi.dbs.elki.database.query.range.AbstractDistanceRangeQuery;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.DistanceDBIDResult;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.GenericDistanceDBIDList;
-import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
+import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
import de.lmu.ifi.dbs.elki.index.tree.DirectoryEntry;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTree;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTreeNode;
@@ -42,11 +41,11 @@ import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeEntry;
*
* @apiviz.uses AbstractMTree
*/
-public class MetricalIndexRangeQuery<O, D extends Distance<D>> extends AbstractDistanceRangeQuery<O, D> {
+public class MetricalIndexRangeQuery<O, D extends NumberDistance<D, ?>> extends AbstractDistanceRangeQuery<O, D> {
/**
* The index to use
*/
- protected final AbstractMTree<O, D, ?, ?> index;
+ protected final AbstractMTree<O, D, ?, ?, ?> index;
/**
* Constructor.
@@ -54,7 +53,7 @@ public class MetricalIndexRangeQuery<O, D extends Distance<D>> extends AbstractD
* @param index Index to use
* @param distanceQuery Distance query used
*/
- public MetricalIndexRangeQuery(AbstractMTree<O, D, ?, ?> index, DistanceQuery<O, D> distanceQuery) {
+ public MetricalIndexRangeQuery(AbstractMTree<O, D, ?, ?, ?> index, DistanceQuery<O, D> distanceQuery) {
super(distanceQuery);
this.index = index;
}
@@ -71,22 +70,26 @@ public class MetricalIndexRangeQuery<O, D extends Distance<D>> extends AbstractD
* @param result the list holding the query results
*/
private void doRangeQuery(DBID o_p, AbstractMTreeNode<O, D, ?, ?> node, O q, D r_q, GenericDistanceDBIDList<D> result) {
- final D nullDistance = distanceQuery.nullDistance();
- D d1 = o_p != null ? distanceQuery.distance(o_p, q) : nullDistance;
+ double d1 = 0.;
+ if (o_p != null) {
+ d1 = distanceQuery.distance(o_p, q).doubleValue();
+ index.statistics.countDistanceCalculation();
+ }
if (!node.isLeaf()) {
for (int i = 0; i < node.getNumEntries(); i++) {
- MTreeEntry<D> entry = node.getEntry(i);
+ MTreeEntry entry = node.getEntry(i);
DBID o_r = entry.getRoutingObjectID();
- D r_or = entry.getCoveringRadius();
- D d2 = o_p != null ? entry.getParentDistance() : nullDistance;
- D diff = d1.compareTo(d2) > 0 ? d1.minus(d2) : d2.minus(d1);
+ double r_or = entry.getCoveringRadius();
+ double d2 = o_p != null ? entry.getParentDistance() : 0.;
+ double diff = Math.abs(d1 - d2);
- D sum = r_q.plus(r_or);
+ double sum = r_q.doubleValue() + r_or;
- if (diff.compareTo(sum) <= 0) {
+ if (diff <= sum) {
D d3 = distanceQuery.distance(o_r, q);
- if (d3.compareTo(sum) <= 0) {
+ index.statistics.countDistanceCalculation();
+ if (d3.doubleValue() <= sum) {
AbstractMTreeNode<O, D, ?, ?> child = index.getNode(((DirectoryEntry) entry).getPageID());
doRangeQuery(o_r, child, q, r_q, result);
}
@@ -94,15 +97,16 @@ public class MetricalIndexRangeQuery<O, D extends Distance<D>> extends AbstractD
}
} else {
for (int i = 0; i < node.getNumEntries(); i++) {
- MTreeEntry<D> entry = node.getEntry(i);
+ MTreeEntry entry = node.getEntry(i);
DBID o_j = entry.getRoutingObjectID();
- D d2 = o_p != null ? entry.getParentDistance() : nullDistance;
+ double d2 = o_p != null ? entry.getParentDistance() : 0.;
- D diff = d1.compareTo(d2) > 0 ? d1.minus(d2) : d2.minus(d1);
+ double diff = Math.abs(d1 - d2);
- if (diff.compareTo(r_q) <= 0) {
+ if (diff <= r_q.doubleValue()) {
D d3 = distanceQuery.distance(o_j, q);
+ index.statistics.countDistanceCalculation();
if (d3.compareTo(r_q) <= 0) {
result.add(d3, o_j);
}
@@ -112,18 +116,14 @@ public class MetricalIndexRangeQuery<O, D extends Distance<D>> extends AbstractD
}
@Override
- public DistanceDBIDResult<D> getRangeForObject(O obj, D range) {
- final GenericDistanceDBIDList<D> result = new GenericDistanceDBIDList<D>();
+ public DistanceDBIDList<D> getRangeForObject(O obj, D range) {
+ final GenericDistanceDBIDList<D> result = new GenericDistanceDBIDList<>();
doRangeQuery(null, index.getRoot(), obj, range, result);
+ index.statistics.countRangeQuery();
// sort the result according to the distances
result.sort();
return result;
}
-
- @Override
- public DistanceDBIDResult<D> getRangeForDBID(DBIDRef id, D range) {
- return getRangeForObject(relation.get(id), range);
- }
}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/MkTreeRKNNQuery.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/MkTreeRKNNQuery.java
index e3f35c50..c8cec69f 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/MkTreeRKNNQuery.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/MkTreeRKNNQuery.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.query;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -27,13 +27,14 @@ import java.util.List;
import de.lmu.ifi.dbs.elki.database.ids.ArrayDBIDs;
import de.lmu.ifi.dbs.elki.database.ids.DBIDRef;
+import de.lmu.ifi.dbs.elki.database.ids.distance.DistanceDBIDList;
import de.lmu.ifi.dbs.elki.database.query.distance.DistanceQuery;
import de.lmu.ifi.dbs.elki.database.query.rknn.AbstractRKNNQuery;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.DistanceDBIDResult;
-import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
+import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.mktrees.AbstractMkTree;
import de.lmu.ifi.dbs.elki.utilities.exceptions.AbortException;
import de.lmu.ifi.dbs.elki.utilities.exceptions.ExceptionMessages;
+import de.lmu.ifi.dbs.elki.utilities.exceptions.NotImplementedException;
/**
* Instance of a rKNN query for a particular spatial index.
@@ -42,11 +43,11 @@ import de.lmu.ifi.dbs.elki.utilities.exceptions.ExceptionMessages;
*
* @apiviz.uses AbstractMkTree
*/
-public class MkTreeRKNNQuery<O, D extends Distance<D>> extends AbstractRKNNQuery<O, D> {
+public class MkTreeRKNNQuery<O, D extends NumberDistance<D, ?>> extends AbstractRKNNQuery<O, D> {
/**
* The index to use
*/
- protected final AbstractMkTree<O, D, ?, ?> index;
+ protected final AbstractMkTree<O, D, ?, ?, ?> index;
/**
* Constructor.
@@ -54,24 +55,24 @@ public class MkTreeRKNNQuery<O, D extends Distance<D>> extends AbstractRKNNQuery
* @param index Index to use
* @param distanceQuery Distance query used
*/
- public MkTreeRKNNQuery(AbstractMkTree<O, D, ?, ?> index, DistanceQuery<O, D> distanceQuery) {
+ public MkTreeRKNNQuery(AbstractMkTree<O, D, ?, ?, ?> index, DistanceQuery<O, D> distanceQuery) {
super(distanceQuery);
this.index = index;
}
@Override
- public DistanceDBIDResult<D> getRKNNForObject(O obj, int k) {
+ public DistanceDBIDList<D> getRKNNForObject(O obj, int k) {
throw new AbortException("Preprocessor KNN query only supports ID queries.");
}
@Override
- public DistanceDBIDResult<D> getRKNNForDBID(DBIDRef id, int k) {
+ public DistanceDBIDList<D> getRKNNForDBID(DBIDRef id, int k) {
return index.reverseKNNQuery(id, k);
}
@Override
- public List<? extends DistanceDBIDResult<D>> getRKNNForBulkDBIDs(ArrayDBIDs ids, int k) {
+ public List<? extends DistanceDBIDList<D>> getRKNNForBulkDBIDs(ArrayDBIDs ids, int k) {
// TODO: implement
- throw new UnsupportedOperationException(ExceptionMessages.UNSUPPORTED_NOT_YET);
+ throw new NotImplementedException(ExceptionMessages.UNSUPPORTED_NOT_YET);
}
} \ No newline at end of file
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/package-info.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/package-info.java
index fa7e6248..a975fdff 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/package-info.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/package-info.java
@@ -6,7 +6,7 @@
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
-Copyright (C) 2012
+Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/split/MTreeSplit.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/split/MTreeSplit.java
deleted file mode 100644
index f9a3c248..00000000
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/split/MTreeSplit.java
+++ /dev/null
@@ -1,138 +0,0 @@
-package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.split;
-
-/*
- This file is part of ELKI:
- Environment for Developing KDD-Applications Supported by Index-Structures
-
- Copyright (C) 2012
- Ludwig-Maximilians-Universität München
- Lehr- und Forschungseinheit für Datenbanksysteme
- ELKI Development Team
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import de.lmu.ifi.dbs.elki.database.ids.DBID;
-import de.lmu.ifi.dbs.elki.database.query.distance.DistanceQuery;
-import de.lmu.ifi.dbs.elki.distance.DistanceUtil;
-import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
-import de.lmu.ifi.dbs.elki.index.tree.DistanceEntry;
-import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTreeNode;
-import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeEntry;
-
-/**
- * Abstract super class for splitting a node in an M-Tree.
- *
- * @author Elke Achtert
- *
- * @apiviz.composedOf Assignments
- *
- * @param <O> the type of DatabaseObject to be stored in the M-Tree
- * @param <D> the type of Distance used in the M-Tree
- * @param <N> the type of AbstractMTreeNode used in the M-Tree
- * @param <E> the type of MetricalEntry used in the M-Tree
- */
-public abstract class MTreeSplit<O, D extends Distance<D>, N extends AbstractMTreeNode<O, D, N, E>, E extends MTreeEntry<D>> {
- /**
- * Encapsulates the two promotion objects and their assignments.
- */
- Assignments<D, E> assignments;
-
- /**
- * Creates a balanced partition of the entries of the specified node.
- *
- * @param node the node to be split
- * @param routingObject1 the id of the first routing object
- * @param routingObject2 the id of the second routing object
- * @param distanceFunction the distance function to compute the distances
- * @return an assignment that holds a balanced partition of the entries of the
- * specified node
- */
- Assignments<D, E> balancedPartition(N node, DBID routingObject1, DBID routingObject2, DistanceQuery<O, D> distanceFunction) {
- HashSet<E> assigned1 = new HashSet<E>();
- HashSet<E> assigned2 = new HashSet<E>();
-
- D currentCR1 = distanceFunction.nullDistance();
- D currentCR2 = distanceFunction.nullDistance();
-
- // determine the nearest neighbors
- List<DistanceEntry<D, E>> list1 = new ArrayList<DistanceEntry<D, E>>();
- List<DistanceEntry<D, E>> list2 = new ArrayList<DistanceEntry<D, E>>();
- for(int i = 0; i < node.getNumEntries(); i++) {
- DBID id = node.getEntry(i).getRoutingObjectID();
- // determine the distance of o to o1 / o2
- D d1 = distanceFunction.distance(routingObject1, id);
- D d2 = distanceFunction.distance(routingObject2, id);
-
- list1.add(new DistanceEntry<D, E>(node.getEntry(i), d1, i));
- list2.add(new DistanceEntry<D, E>(node.getEntry(i), d2, i));
- }
- Collections.sort(list1);
- Collections.sort(list2);
-
- for(int i = 0; i < node.getNumEntries(); i++) {
- if(i % 2 == 0) {
- currentCR1 = assignNN(assigned1, assigned2, list1, currentCR1, node.isLeaf());
- }
- else {
- currentCR2 = assignNN(assigned2, assigned1, list2, currentCR2, node.isLeaf());
- }
- }
- return new Assignments<D, E>(routingObject1, routingObject2, currentCR1, currentCR2, assigned1, assigned2);
- }
-
- /**
- * Assigns the first object of the specified list to the first assignment that
- * it is not yet assigned to the second assignment.
- *
- * @param assigned1 the first assignment
- * @param assigned2 the second assignment
- * @param list the list, the first object should be assigned
- * @param currentCR the current covering radius
- * @param isLeaf true, if the node of the entries to be assigned is a leaf,
- * false otherwise
- * @return the new covering radius
- */
- private D assignNN(Set<E> assigned1, Set<E> assigned2, List<DistanceEntry<D, E>> list, D currentCR, boolean isLeaf) {
- DistanceEntry<D, E> distEntry = list.remove(0);
- while(assigned2.contains(distEntry.getEntry())) {
- distEntry = list.remove(0);
- }
- // Update the parent distance.
- distEntry.getEntry().setParentDistance(distEntry.getDistance());
- assigned1.add(distEntry.getEntry());
-
- if(isLeaf) {
- return DistanceUtil.max(currentCR, distEntry.getDistance());
- }
- else {
- return DistanceUtil.max(currentCR, distEntry.getDistance().plus((distEntry.getEntry()).getCoveringRadius()));
- }
- }
-
- /**
- * Returns the assignments of this split.
- *
- * @return the assignments of this split
- */
- public Assignments<D, E> getAssignments() {
- return assignments;
- }
-}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/split/package-info.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/split/package-info.java
deleted file mode 100644
index ed13ae73..00000000
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/split/package-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/**
- * <p>Splitting strategies of nodes in an M-Tree (and variants).</p>
- */
-/*
-This file is part of ELKI:
-Environment for Developing KDD-Applications Supported by Index-Structures
-
-Copyright (C) 2012
-Ludwig-Maximilians-Universität München
-Lehr- und Forschungseinheit für Datenbanksysteme
-ELKI Development Team
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU Affero General Public License for more details.
-
-You should have received a copy of the GNU Affero General Public License
-along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.split; \ No newline at end of file
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/insert/MTreeInsert.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/insert/MTreeInsert.java
new file mode 100644
index 00000000..65fc3768
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/insert/MTreeInsert.java
@@ -0,0 +1,50 @@
+package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.strategies.insert;
+
+/*
+ This file is part of ELKI:
+ Environment for Developing KDD-Applications Supported by Index-Structures
+
+ Copyright (C) 2013
+ Ludwig-Maximilians-Universität München
+ Lehr- und Forschungseinheit für Datenbanksysteme
+ ELKI Development Team
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
+import de.lmu.ifi.dbs.elki.index.tree.IndexTreePath;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTree;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTreeNode;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeEntry;
+
+/**
+ * Default insertion strategy for the M-tree.
+ *
+ * <b>Warning:</b> as of now, insertion strategies <b>will already modify the
+ * tree</b>, i.e. adjust cover radiuses.
+ *
+ * FIXME: move this to the actual insert.
+ *
+ * @author Erich Schubert
+ */
+public interface MTreeInsert<O, D extends NumberDistance<D, ?>, N extends AbstractMTreeNode<O, D, N, E>, E extends MTreeEntry> {
+ /**
+ * Choose the subpath to insert into.
+ *
+ * @param tree Tree to process
+ * @param object Object to insert
+ * @return Path to insertion node
+ */
+ IndexTreePath<E> choosePath(AbstractMTree<O, D, N, E, ?> tree, E object);
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/insert/MinimumEnlargementInsert.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/insert/MinimumEnlargementInsert.java
new file mode 100644
index 00000000..f848f5f4
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/insert/MinimumEnlargementInsert.java
@@ -0,0 +1,117 @@
+package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.strategies.insert;
+
+/*
+ This file is part of ELKI:
+ Environment for Developing KDD-Applications Supported by Index-Structures
+
+ Copyright (C) 2013
+ Ludwig-Maximilians-Universität München
+ Lehr- und Forschungseinheit für Datenbanksysteme
+ ELKI Development Team
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
+import de.lmu.ifi.dbs.elki.index.tree.IndexTreePath;
+import de.lmu.ifi.dbs.elki.index.tree.TreeIndexPathComponent;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTree;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTreeNode;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeEntry;
+import de.lmu.ifi.dbs.elki.utilities.documentation.Reference;
+
+/**
+ * Default insertion strategy for the M-tree.
+ *
+ * Reference:
+ * <p>
+ * P. Ciaccia, M. Patella, P. Zezula<br />
+ * M-tree: An Efficient Access Method for Similarity Search in Metric Spaces<br />
+ * In Proceedings of 23rd International Conference on Very Large Data Bases
+ * (VLDB'97), August 25-29, 1997, Athens, Greece
+ * </p>
+ *
+ * @author Erich Schubert
+ */
+@Reference(authors = "P. Ciaccia, M. Patella, P. Zezula", title = "M-tree: An Efficient Access Method for Similarity Search in Metric Spaces", booktitle = "VLDB'97, Proceedings of 23rd International Conference on Very Large Data Bases, August 25-29, 1997, Athens, Greece", url = "http://www.vldb.org/conf/1997/P426.PDF")
+public class MinimumEnlargementInsert<O, D extends NumberDistance<D, ?>, N extends AbstractMTreeNode<O, D, N, E>, E extends MTreeEntry> implements MTreeInsert<O, D, N, E> {
+ @Override
+ public IndexTreePath<E> choosePath(AbstractMTree<O, D, N, E, ?> tree, E object) {
+ return choosePath(tree, object, tree.getRootPath());
+ }
+
+ /**
+ * Chooses the best path of the specified subtree for insertion of the given
+ * object.
+ *
+ * @param tree the tree to insert into
+ * @param object the entry to search
+ * @param subtree the subtree to be tested for insertion
+ * @return the path of the appropriate subtree to insert the given object
+ */
+ private IndexTreePath<E> choosePath(AbstractMTree<O, D, N, E, ?> tree, E object, IndexTreePath<E> subtree) {
+ N node = tree.getNode(subtree.getLastPathComponent().getEntry());
+
+ // leaf
+ if (node.isLeaf()) {
+ return subtree;
+ }
+
+ double bestDistance;
+ int bestIdx;
+ E bestEntry;
+ double enlarge; // Track best enlargement - null for no enlargement needed.
+ // Initialize from first:
+ {
+ bestIdx = 0;
+ bestEntry = node.getEntry(0);
+ bestDistance = tree.distance(object.getRoutingObjectID(), bestEntry.getRoutingObjectID()).doubleValue();
+ if (bestDistance <= bestEntry.getCoveringRadius()) {
+ enlarge = 0.;
+ } else {
+ enlarge = bestDistance - bestEntry.getCoveringRadius();
+ }
+ }
+
+ // Iterate over remaining
+ for (int i = 1; i < node.getNumEntries(); i++) {
+ E entry = node.getEntry(i);
+ double distance = tree.distance(object.getRoutingObjectID(), entry.getRoutingObjectID()).doubleValue();
+
+ if (distance <= entry.getCoveringRadius()) {
+ if (enlarge > 0. || distance < bestDistance) {
+ bestIdx = i;
+ bestEntry = entry;
+ bestDistance = distance;
+ enlarge = 0.;
+ }
+ } else if (enlarge > 0.) {
+ double enlrg = distance - entry.getCoveringRadius();
+ if (enlrg < enlarge) {
+ bestIdx = i;
+ bestEntry = entry;
+ bestDistance = distance;
+ enlarge = enlrg;
+ }
+ }
+ }
+
+ // FIXME: move this to the actual insertion procedure!
+ // Apply enlargement
+ if (enlarge > 0) {
+ bestEntry.setCoveringRadius(bestEntry.getCoveringRadius() + enlarge);
+ }
+
+ return choosePath(tree, object, subtree.pathByAddingChild(new TreeIndexPathComponent<>(bestEntry, bestIdx)));
+ }
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/insert/package-info.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/insert/package-info.java
new file mode 100644
index 00000000..64a85c2d
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/insert/package-info.java
@@ -0,0 +1,26 @@
+/**
+ * <p>Insertion (choose path) strategies of nodes in an M-Tree (and variants).</p>
+ */
+/*
+ This file is part of ELKI:
+ Environment for Developing KDD-Applications Supported by Index-Structures
+
+ Copyright (C) 2013
+ Ludwig-Maximilians-Universität München
+ Lehr- und Forschungseinheit für Datenbanksysteme
+ ELKI Development Team
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.strategies.insert; \ No newline at end of file
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/package-info.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/package-info.java
new file mode 100644
index 00000000..0d019cf3
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/package-info.java
@@ -0,0 +1,26 @@
+/**
+ * <p>Strategies for M-Trees (and variants).</p>
+ */
+/*
+ This file is part of ELKI:
+ Environment for Developing KDD-Applications Supported by Index-Structures
+
+ Copyright (C) 2013
+ Ludwig-Maximilians-Universität München
+ Lehr- und Forschungseinheit für Datenbanksysteme
+ ELKI Development Team
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.strategies; \ No newline at end of file
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/split/Assignments.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/Assignments.java
index 5cb6c794..1079a141 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/split/Assignments.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/Assignments.java
@@ -1,10 +1,10 @@
-package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.split;
+package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.strategies.split;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -23,22 +23,21 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.split;
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+import java.util.List;
+
import de.lmu.ifi.dbs.elki.database.ids.DBID;
-import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeEntry;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
-
/**
* Encapsulates the attributes of an assignment during a split.
*
* @author Elke Achtert
- * @param <D> the type of Distance used in the M-Tree
+ *
+ * @apiviz.composedOf DistanceEntry
+ *
* @param <E> the type of MetricalEntry used in the M-Tree
*/
-public class Assignments<D extends Distance<D>, E extends MTreeEntry<D>> {
+public class Assignments<E extends MTreeEntry> {
/**
* The id of the first routing object.
*/
@@ -52,22 +51,22 @@ public class Assignments<D extends Distance<D>, E extends MTreeEntry<D>> {
/**
* The first covering radius.
*/
- private D firstCoveringRadius;
+ private double firstCoveringRadius;
/**
* The second covering radius.
*/
- private D secondCoveringRadius;
+ private double secondCoveringRadius;
/**
* The assignments to the first routing object.
*/
- private List<E> firstAssignments;
+ private List<DistanceEntry<E>> firstAssignments;
/**
* The assignments to the second routing object.
*/
- private List<E> secondAssignments;
+ private List<DistanceEntry<E>> secondAssignments;
/**
* Provides an assignment during a split of an MTree node.
@@ -79,13 +78,13 @@ public class Assignments<D extends Distance<D>, E extends MTreeEntry<D>> {
* @param firstAssignments the assignments to the first routing object
* @param secondAssignments the assignments to the second routing object
*/
- public Assignments(DBID id1, DBID id2, D firstCoveringRadius, D secondCoveringRadius, Set<E> firstAssignments, Set<E> secondAssignments) {
+ public Assignments(DBID id1, DBID id2, double firstCoveringRadius, double secondCoveringRadius, List<DistanceEntry<E>> firstAssignments, List<DistanceEntry<E>> secondAssignments) {
this.id1 = id1;
this.id2 = id2;
this.firstCoveringRadius = firstCoveringRadius;
this.secondCoveringRadius = secondCoveringRadius;
- this.firstAssignments = new ArrayList<E>(firstAssignments);
- this.secondAssignments = new ArrayList<E>(secondAssignments);
+ this.firstAssignments = firstAssignments;
+ this.secondAssignments = secondAssignments;
}
/**
@@ -111,7 +110,7 @@ public class Assignments<D extends Distance<D>, E extends MTreeEntry<D>> {
*
* @return the first covering radius
*/
- public D getFirstCoveringRadius() {
+ public double getFirstCoveringRadius() {
return firstCoveringRadius;
}
@@ -120,7 +119,7 @@ public class Assignments<D extends Distance<D>, E extends MTreeEntry<D>> {
*
* @return the second covering radius
*/
- public D getSecondCoveringRadius() {
+ public double getSecondCoveringRadius() {
return secondCoveringRadius;
}
@@ -129,7 +128,7 @@ public class Assignments<D extends Distance<D>, E extends MTreeEntry<D>> {
*
* @return the assignments to the first routing object
*/
- public List<E> getFirstAssignments() {
+ public List<DistanceEntry<E>> getFirstAssignments() {
return firstAssignments;
}
@@ -138,7 +137,7 @@ public class Assignments<D extends Distance<D>, E extends MTreeEntry<D>> {
*
* @return the assignments to the second routing object
*/
- public List<E> getSecondAssignments() {
+ public List<DistanceEntry<E>> getSecondAssignments() {
return secondAssignments;
}
}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/DistanceEntry.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/DistanceEntry.java
new file mode 100644
index 00000000..642e5a63
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/DistanceEntry.java
@@ -0,0 +1,123 @@
+package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.strategies.split;
+
+import de.lmu.ifi.dbs.elki.index.tree.Entry;
+
+/*
+ This file is part of ELKI:
+ Environment for Developing KDD-Applications Supported by Index-Structures
+
+ Copyright (C) 2013
+ Ludwig-Maximilians-Universität München
+ Lehr- und Forschungseinheit für Datenbanksysteme
+ ELKI Development Team
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * Helper class: encapsulates an entry in an Index and a distance value
+ * belonging to this entry.
+ *
+ * @author Elke Achtert
+ *
+ * @apiviz.uses Entry
+ *
+ * @param <E> the type of Entry used in the index
+ */
+public class DistanceEntry<E extends Entry> implements Comparable<DistanceEntry<E>> {
+ /**
+ * The entry of the Index.
+ */
+ private E entry;
+
+ /**
+ * The distance value belonging to the entry.
+ */
+ private double distance;
+
+ /**
+ * The index of the entry in its parent's child array.
+ */
+ private int index;
+
+ /**
+ * Constructs a new DistanceEntry object with the specified parameters.
+ *
+ * @param entry the entry of the Index
+ * @param distance the distance value belonging to the entry
+ * @param index the index of the entry in its parent' child array
+ */
+ public DistanceEntry(E entry, double distance, int index) {
+ this.entry = entry;
+ this.distance = distance;
+ this.index = index;
+ }
+
+ /**
+ * Returns the entry of the Index.
+ *
+ * @return the entry of the Index
+ */
+ public E getEntry() {
+ return entry;
+ }
+
+ /**
+ * Returns the distance value belonging to the entry.
+ *
+ * @return the distance value belonging to the entry
+ */
+ public double getDistance() {
+ return distance;
+ }
+
+ /**
+ * Returns the index of this entry in its parents child array.
+ *
+ * @return the index of this entry in its parents child array
+ */
+ public int getIndex() {
+ return index;
+ }
+
+ /**
+ * Compares this object with the specified object for order.
+ *
+ * @param o the Object to be compared.
+ * @return a negative integer, zero, or a positive integer as this object is
+ * less than, equal to, or greater than the specified object.
+ * @throws ClassCastException if the specified object's type prevents it from
+ * being compared to this Object.
+ */
+ @Override
+ public int compareTo(DistanceEntry<E> o) {
+ int comp = Double.compare(distance, o.distance);
+ if (comp != 0) {
+ return comp;
+ }
+
+ // return entry.getEntryID().compareTo(o.entry.getEntryID());
+ return 0;
+ }
+
+ /**
+ * Returns a string representation of the object.
+ *
+ * @return a string representation of the object.
+ */
+ @Override
+ public String toString() {
+ return "" + entry.toString() + "(" + distance + ")";
+ }
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/split/MLBDistSplit.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/MLBDistSplit.java
index f4da4a1a..d294d5b3 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/split/MLBDistSplit.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/MLBDistSplit.java
@@ -1,10 +1,10 @@
-package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.split;
+package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.strategies.split;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -23,37 +23,39 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.split;
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
import de.lmu.ifi.dbs.elki.database.ids.DBID;
-import de.lmu.ifi.dbs.elki.database.query.distance.DistanceQuery;
-import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
-import de.lmu.ifi.dbs.elki.index.tree.DistanceEntry;
+import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTree;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTreeNode;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeEntry;
+import de.lmu.ifi.dbs.elki.utilities.documentation.Reference;
/**
* Encapsulates the required methods for a split of a node in an M-Tree. The
* routing objects are chosen according to the M_LB_DIST strategy.
*
+ * Reference:
+ * <p>
+ * P. Ciaccia, M. Patella, P. Zezula<br />
+ * M-tree: An Efficient Access Method for Similarity Search in Metric Spaces<br />
+ * In Proceedings of 23rd International Conference on Very Large Data Bases
+ * (VLDB'97), August 25-29, 1997, Athens, Greece
+ * </p>
+ *
* @author Elke Achtert
+ *
* @param <O> the type of DatabaseObject to be stored in the M-Tree
* @param <D> the type of Distance used in the M-Tree
* @param <N> the type of AbstractMTreeNode used in the M-Tree
* @param <E> the type of MetricalEntry used in the M-Tree
*/
-public class MLBDistSplit<O, D extends Distance<D>, N extends AbstractMTreeNode<O, D, N, E>, E extends MTreeEntry<D>> extends MTreeSplit<O, D, N, E> {
+@Reference(authors = "P. Ciaccia, M. Patella, P. Zezula", title = "M-tree: An Efficient Access Method for Similarity Search in Metric Spaces", booktitle = "VLDB'97, Proceedings of 23rd International Conference on Very Large Data Bases, August 25-29, 1997, Athens, Greece", url = "http://www.vldb.org/conf/1997/P426.PDF")
+public class MLBDistSplit<O, D extends NumberDistance<D, ?>, N extends AbstractMTreeNode<O, D, N, E>, E extends MTreeEntry> extends MTreeSplit<O, D, N, E> {
/**
* Creates a new split object.
- *
- * @param node the node to be split
- * @param distanceFunction the distance function
*/
- public MLBDistSplit(N node, DistanceQuery<O, D> distanceFunction) {
+ public MLBDistSplit() {
super();
- promote(node, distanceFunction);
}
/**
@@ -64,22 +66,23 @@ public class MLBDistSplit<O, D extends Distance<D>, N extends AbstractMTreeNode<
* This strategy considers all possible pairs of objects and chooses the pair
* of objects for which the distance is maximum.
*
+ * @param tree Tree to use
* @param node the node to be split
- * @param distanceFunction the distance function
*/
- private void promote(N node, DistanceQuery<O, D> distanceFunction) {
+ @Override
+ public Assignments<E> split(AbstractMTree<O, D, N, E, ?> tree, N node) {
DBID firstPromoted = null;
DBID secondPromoted = null;
// choose first and second routing object
- D currentMaxDist = distanceFunction.nullDistance();
- for(int i = 0; i < node.getNumEntries(); i++) {
+ double currentMaxDist = 0.;
+ for (int i = 0; i < node.getNumEntries(); i++) {
DBID id1 = node.getEntry(i).getRoutingObjectID();
- for(int j = i + 1; j < node.getNumEntries(); j++) {
+ for (int j = i + 1; j < node.getNumEntries(); j++) {
DBID id2 = node.getEntry(j).getRoutingObjectID();
- D distance = distanceFunction.distance(id1, id2);
- if(distance.compareTo(currentMaxDist) >= 0) {
+ double distance = tree.distance(id1, id2).doubleValue();
+ if (distance >= currentMaxDist) {
firstPromoted = id1;
secondPromoted = id2;
currentMaxDist = distance;
@@ -87,20 +90,6 @@ public class MLBDistSplit<O, D extends Distance<D>, N extends AbstractMTreeNode<
}
}
- // partition the entries
- List<DistanceEntry<D, E>> list1 = new ArrayList<DistanceEntry<D, E>>();
- List<DistanceEntry<D, E>> list2 = new ArrayList<DistanceEntry<D, E>>();
- for(int i = 0; i < node.getNumEntries(); i++) {
- DBID id = node.getEntry(i).getRoutingObjectID();
- D d1 = distanceFunction.distance(firstPromoted, id);
- D d2 = distanceFunction.distance(secondPromoted, id);
-
- list1.add(new DistanceEntry<D, E>(node.getEntry(i), d1, i));
- list2.add(new DistanceEntry<D, E>(node.getEntry(i), d2, i));
- }
- Collections.sort(list1);
- Collections.sort(list2);
-
- assignments = balancedPartition(node, firstPromoted, secondPromoted, distanceFunction);
+ return balancedPartition(tree, node, firstPromoted, secondPromoted);
}
}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/MMRadSplit.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/MMRadSplit.java
new file mode 100644
index 00000000..232df088
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/MMRadSplit.java
@@ -0,0 +1,88 @@
+package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.strategies.split;
+
+/*
+ This file is part of ELKI:
+ Environment for Developing KDD-Applications Supported by Index-Structures
+
+ Copyright (C) 2013
+ Ludwig-Maximilians-Universität München
+ Lehr- und Forschungseinheit für Datenbanksysteme
+ ELKI Development Team
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTree;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTreeNode;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeEntry;
+import de.lmu.ifi.dbs.elki.utilities.documentation.Reference;
+
+/**
+ * Encapsulates the required methods for a split of a node in an M-Tree. The
+ * routing objects are chosen according to the mM_rad strategy.
+ *
+ * Reference:
+ * <p>
+ * P. Ciaccia, M. Patella, P. Zezula<br />
+ * M-tree: An Efficient Access Method for Similarity Search in Metric Spaces<br />
+ * In Proceedings of 23rd International Conference on Very Large Data Bases
+ * (VLDB'97), August 25-29, 1997, Athens, Greece
+ * </p>
+ *
+ * @author Elke Achtert
+ *
+ * @param <O> the type of DatabaseObject to be stored in the M-Tree
+ * @param <D> the type of Distance used in the M-Tree
+ * @param <N> the type of AbstractMTreeNode used in the M-Tree
+ * @param <E> the type of MetricalEntry used in the M-Tree
+ */
+@Reference(authors = "P. Ciaccia, M. Patella, P. Zezula", title = "M-tree: An Efficient Access Method for Similarity Search in Metric Spaces", booktitle = "VLDB'97, Proceedings of 23rd International Conference on Very Large Data Bases, August 25-29, 1997, Athens, Greece", url = "http://www.vldb.org/conf/1997/P426.PDF")
+public class MMRadSplit<O, D extends NumberDistance<D, ?>, N extends AbstractMTreeNode<O, D, N, E>, E extends MTreeEntry> extends MTreeSplit<O, D, N, E> {
+ /**
+ * Creates a new split object.
+ */
+ public MMRadSplit() {
+ super();
+ }
+
+ /**
+ * Selects two objects of the specified node to be promoted and stored into
+ * the parent node. The mM-RAD strategy considers all possible pairs of
+ * objects and, after partitioning the set of entries, promotes the pair of
+ * objects for which the larger of the two covering radiuses is minimum.
+ *
+ * @param tree Tree to use
+ * @param node the node to be split
+ */
+ @Override
+ public Assignments<E> split(AbstractMTree<O, D, N, E, ?> tree, N node) {
+ double miSumCR = Double.POSITIVE_INFINITY;
+ double[] distanceMatrix = computeDistanceMatrix(tree, node);
+
+ Assignments<E> bestAssignment = null;
+ for (int i = 0; i < node.getNumEntries(); i++) {
+ for (int j = i + 1; j < node.getNumEntries(); j++) {
+ Assignments<E> currentAssignments = balancedPartition(tree, node, i, j, distanceMatrix);
+
+ double maxCR = Math.max(currentAssignments.getFirstCoveringRadius(), currentAssignments.getSecondCoveringRadius());
+ if (maxCR < miSumCR) {
+ miSumCR = maxCR;
+ bestAssignment = currentAssignments;
+ }
+ }
+ }
+ return bestAssignment;
+ }
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/split/MRadSplit.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/MRadSplit.java
index 5d6c985c..5de15356 100644
--- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/split/MRadSplit.java
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/MRadSplit.java
@@ -1,10 +1,10 @@
-package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.split;
+package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.strategies.split;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -23,32 +23,38 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.split;
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-import de.lmu.ifi.dbs.elki.database.ids.DBID;
-import de.lmu.ifi.dbs.elki.database.query.distance.DistanceQuery;
-import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
+import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTree;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTreeNode;
import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeEntry;
+import de.lmu.ifi.dbs.elki.utilities.documentation.Reference;
/**
* Encapsulates the required methods for a split of a node in an M-Tree. The
* routing objects are chosen according to the M_rad strategy.
*
+ * Reference:
+ * <p>
+ * P. Ciaccia, M. Patella, P. Zezula<br />
+ * M-tree: An Efficient Access Method for Similarity Search in Metric Spaces<br />
+ * In Proceedings of 23rd International Conference on Very Large Data Bases
+ * (VLDB'97), August 25-29, 1997, Athens, Greece
+ * </p>
+ *
* @author Elke Achtert
+ *
* @param <O> the type of DatabaseObject to be stored in the M-Tree
* @param <D> the type of Distance used in the M-Tree
* @param <N> the type of AbstractMTreeNode used in the M-Tree
* @param <E> the type of MetricalEntry used in the M-Tree
*/
-public class MRadSplit<O, D extends Distance<D>, N extends AbstractMTreeNode<O, D, N, E>, E extends MTreeEntry<D>> extends MTreeSplit<O, D, N, E> {
+@Reference(authors = "P. Ciaccia, M. Patella, P. Zezula", title = "M-tree: An Efficient Access Method for Similarity Search in Metric Spaces", booktitle = "VLDB'97, Proceedings of 23rd International Conference on Very Large Data Bases, August 25-29, 1997, Athens, Greece", url = "http://www.vldb.org/conf/1997/P426.PDF")
+public class MRadSplit<O, D extends NumberDistance<D, ?>, N extends AbstractMTreeNode<O, D, N, E>, E extends MTreeEntry> extends MTreeSplit<O, D, N, E> {
/**
* Creates a new split object.
- *
- * @param node the node to be split
- * @param distanceFunction the distance function
*/
- public MRadSplit(N node, DistanceQuery<O, D> distanceFunction) {
+ public MRadSplit() {
super();
- promote(node, distanceFunction);
}
/**
@@ -57,26 +63,26 @@ public class MRadSplit<O, D extends Distance<D>, N extends AbstractMTreeNode<O,
* and, after partitioning the set of entries, promotes the pair of objects
* for which the sum of covering radiuses is minimum.
*
+ * @param tree Tree to use
* @param node the node to be split
- * @param distanceFunction the distance function
*/
- private void promote(N node, DistanceQuery<O, D> distanceFunction) {
- D miSumCR = distanceFunction.infiniteDistance();
-
- for(int i = 0; i < node.getNumEntries(); i++) {
- DBID id1 = node.getEntry(i).getRoutingObjectID();
+ @Override
+ public Assignments<E> split(AbstractMTree<O, D, N, E, ?> tree, N node) {
+ double miSumCR = Double.POSITIVE_INFINITY;
+ double[] distanceMatrix = computeDistanceMatrix(tree, node);
- for(int j = i + 1; j < node.getNumEntries(); j++) {
- DBID id2 = node.getEntry(i).getRoutingObjectID();
- // ... for each pair do testPartition...
- Assignments<D, E> currentAssignments = balancedPartition(node, id1, id2, distanceFunction);
+ Assignments<E> bestAssignment = null;
+ for (int i = 0; i < node.getNumEntries(); i++) {
+ for (int j = i + 1; j < node.getNumEntries(); j++) {
+ Assignments<E> currentAssignments = balancedPartition(tree, node, i, j, distanceMatrix);
- D sumCR = currentAssignments.getFirstCoveringRadius().plus(currentAssignments.getSecondCoveringRadius());
- if(sumCR.compareTo(miSumCR) < 0) {
+ double sumCR = currentAssignments.getFirstCoveringRadius() + currentAssignments.getSecondCoveringRadius();
+ if (sumCR < miSumCR) {
miSumCR = sumCR;
- assignments = currentAssignments;
+ bestAssignment = currentAssignments;
}
}
}
+ return bestAssignment;
}
}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/MTreeSplit.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/MTreeSplit.java
new file mode 100644
index 00000000..167b5368
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/MTreeSplit.java
@@ -0,0 +1,223 @@
+package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.strategies.split;
+
+/*
+ This file is part of ELKI:
+ Environment for Developing KDD-Applications Supported by Index-Structures
+
+ Copyright (C) 2013
+ Ludwig-Maximilians-Universität München
+ Lehr- und Forschungseinheit für Datenbanksysteme
+ ELKI Development Team
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.Collections;
+import java.util.List;
+
+import de.lmu.ifi.dbs.elki.database.ids.DBID;
+import de.lmu.ifi.dbs.elki.database.ids.DBIDUtil;
+import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTree;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTreeNode;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeEntry;
+
+/**
+ * Abstract super class for splitting a node in an M-Tree.
+ *
+ * @author Elke Achtert
+ *
+ * @apiviz.composedOf Assignments
+ *
+ * @param <O> the type of DatabaseObject to be stored in the M-Tree
+ * @param <D> the type of Distance used in the M-Tree
+ * @param <N> the type of AbstractMTreeNode used in the M-Tree
+ * @param <E> the type of MetricalEntry used in the M-Tree
+ */
+public abstract class MTreeSplit<O, D extends NumberDistance<D, ?>, N extends AbstractMTreeNode<O, D, N, E>, E extends MTreeEntry> {
+ /**
+ * Compute the pairwise distances in the given node.
+ *
+ * @param tree Tree
+ * @param node Node
+ * @return Distance matrix
+ */
+ protected double[] computeDistanceMatrix(AbstractMTree<O, D, N, E, ?> tree, N node) {
+ final int n = node.getNumEntries();
+ double[] distancematrix = new double[n * n];
+ // Build distance matrix
+ for (int i = 0; i < n; i++) {
+ E ei = node.getEntry(i);
+ for (int j = 0; j < n; j++) {
+ if (i == j) {
+ distancematrix[i * n + j] = 0.0;
+ } else if (i < j) {
+ distancematrix[i * n + j] = tree.distance(ei, node.getEntry(j)).doubleValue();
+ } else { // i > j
+ distancematrix[i * n + j] = distancematrix[j * n + i];
+ }
+ }
+ }
+ return distancematrix;
+ }
+
+ /**
+ * Creates a balanced partition of the entries of the specified node.
+ *
+ * @param tree the tree to perform the split in
+ * @param node the node to be split
+ * @param routingObject1 the id of the first routing object
+ * @param routingObject2 the id of the second routing object
+ * @return an assignment that holds a balanced partition of the entries of the
+ * specified node
+ */
+ Assignments<E> balancedPartition(AbstractMTree<O, D, N, E, ?> tree, N node, DBID routingObject1, DBID routingObject2) {
+ BitSet assigned = new BitSet(node.getNumEntries());
+ List<DistanceEntry<E>> assigned1 = new ArrayList<>(node.getCapacity());
+ List<DistanceEntry<E>> assigned2 = new ArrayList<>(node.getCapacity());
+
+ double currentCR1 = 0.;
+ double currentCR2 = 0.;
+
+ List<DistanceEntry<E>> list1 = new ArrayList<>();
+ List<DistanceEntry<E>> list2 = new ArrayList<>();
+
+ // determine the nearest neighbors
+ for (int i = 0; i < node.getNumEntries(); i++) {
+ final E ent = node.getEntry(i);
+ DBID id = ent.getRoutingObjectID();
+ if (DBIDUtil.equal(id, routingObject1)) {
+ assigned1.add(new DistanceEntry<>(ent, 0., i));
+ continue;
+ }
+ if (DBIDUtil.equal(id, routingObject2)) {
+ assigned2.add(new DistanceEntry<>(ent, 0., i));
+ continue;
+ }
+ // determine the distance of o to o1 / o2
+ double d1 = tree.distance(routingObject1, id).doubleValue();
+ double d2 = tree.distance(routingObject2, id).doubleValue();
+
+ list1.add(new DistanceEntry<>(ent, d1, i));
+ list2.add(new DistanceEntry<>(ent, d2, i));
+ }
+ Collections.sort(list1, Collections.reverseOrder());
+ Collections.sort(list2, Collections.reverseOrder());
+
+ for (int i = 2; i < node.getNumEntries(); i++) {
+ currentCR1 = assignNN(assigned, assigned1, list1, currentCR1, node.isLeaf());
+ i++;
+ if (i < node.getNumEntries()) {
+ currentCR2 = assignNN(assigned, assigned2, list2, currentCR2, node.isLeaf());
+ }
+ }
+ return new Assignments<>(routingObject1, routingObject2, currentCR1, currentCR2, assigned1, assigned2);
+ }
+
+ /**
+ * Creates a balanced partition of the entries of the specified node.
+ *
+ * @param tree the tree to perform the split in
+ * @param node the node to be split
+ * @param routingEntNum1 the entry number of the first routing object
+ * @param routingEntNum2 the entry number of the second routing object
+ * @param distanceMatrix precomputed distance matrix to use
+ * @return an assignment that holds a balanced partition of the entries of the
+ * specified node
+ */
+ Assignments<E> balancedPartition(AbstractMTree<O, D, N, E, ?> tree, N node, int routingEntNum1, int routingEntNum2, double[] distanceMatrix) {
+ final int n = node.getNumEntries();
+ BitSet assigned = new BitSet(node.getNumEntries());
+ List<DistanceEntry<E>> assigned1 = new ArrayList<>(node.getCapacity());
+ List<DistanceEntry<E>> assigned2 = new ArrayList<>(node.getCapacity());
+
+ double currentCR1 = 0.;
+ double currentCR2 = 0.;
+
+ List<DistanceEntry<E>> list1 = new ArrayList<>();
+ List<DistanceEntry<E>> list2 = new ArrayList<>();
+
+ DBID routingObject1 = null, routingObject2 = null;
+ // determine the nearest neighbors
+ for (int i = 0; i < node.getNumEntries(); i++) {
+ final E ent = node.getEntry(i);
+ if (i == routingEntNum1) {
+ routingObject1 = ent.getRoutingObjectID();
+ assigned1.add(new DistanceEntry<>(ent, 0., i));
+ continue;
+ }
+ if (i == routingEntNum2) {
+ routingObject2 = ent.getRoutingObjectID();
+ assigned2.add(new DistanceEntry<>(ent, 0., i));
+ continue;
+ }
+ // Look up the distances of o to o1 / o2
+ double d1 = distanceMatrix[i * n + routingEntNum1];
+ double d2 = distanceMatrix[i * n + routingEntNum2];
+
+ list1.add(new DistanceEntry<>(ent, d1, i));
+ list2.add(new DistanceEntry<>(ent, d2, i));
+ }
+ Collections.sort(list1, Collections.reverseOrder());
+ Collections.sort(list2, Collections.reverseOrder());
+
+ for (int i = 2; i < node.getNumEntries(); i++) {
+ currentCR1 = assignNN(assigned, assigned1, list1, currentCR1, node.isLeaf());
+ i++;
+ if (i < node.getNumEntries()) {
+ currentCR2 = assignNN(assigned, assigned2, list2, currentCR2, node.isLeaf());
+ }
+ }
+ return new Assignments<>(routingObject1, routingObject2, currentCR1, currentCR2, assigned1, assigned2);
+ }
+
+ /**
+ * Assigns the first object of the specified list to the first assignment that
+ * it is not yet assigned to the second assignment.
+ *
+ * @param assigned List of already assigned objects
+ * @param assigned1 the first assignment
+ * @param list the list, the first object should be assigned
+ * @param currentCR the current covering radius
+ * @param isLeaf true, if the node of the entries to be assigned is a leaf,
+ * false otherwise
+ * @return the new covering radius
+ */
+ private double assignNN(BitSet assigned, List<DistanceEntry<E>> assigned1, List<DistanceEntry<E>> list, double currentCR, boolean isLeaf) {
+ // Remove last unassigned:
+ DistanceEntry<E> distEntry = list.remove(list.size() - 1);
+ while (assigned.get(distEntry.getIndex())) {
+ distEntry = list.remove(list.size() - 1);
+ }
+ assigned1.add(distEntry);
+ assigned.set(distEntry.getIndex());
+
+ if (isLeaf) {
+ return Math.max(currentCR, distEntry.getDistance());
+ } else {
+ return Math.max(currentCR, distEntry.getDistance() + (distEntry.getEntry()).getCoveringRadius());
+ }
+ }
+
+ /**
+ * Returns the assignments of this split.
+ *
+ * @param tree Tree to use
+ * @param node Node to split
+ * @return the assignments of this split
+ */
+ abstract public Assignments<E> split(AbstractMTree<O, D, N, E, ?> tree, N node);
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/RandomSplit.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/RandomSplit.java
new file mode 100644
index 00000000..faf2acc2
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/RandomSplit.java
@@ -0,0 +1,136 @@
+package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.strategies.split;
+
+/*
+ This file is part of ELKI:
+ Environment for Developing KDD-Applications Supported by Index-Structures
+
+ Copyright (C) 2013
+ Ludwig-Maximilians-Universität München
+ Lehr- und Forschungseinheit für Datenbanksysteme
+ ELKI Development Team
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import java.util.Random;
+
+import de.lmu.ifi.dbs.elki.database.ids.DBID;
+import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTree;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.AbstractMTreeNode;
+import de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.MTreeEntry;
+import de.lmu.ifi.dbs.elki.utilities.RandomFactory;
+import de.lmu.ifi.dbs.elki.utilities.documentation.Reference;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.AbstractParameterizer;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.RandomParameter;
+
+/**
+ * Encapsulates the required methods for a split of a node in an M-Tree. The
+ * routing objects are chosen according to the RANDOM strategy.
+ *
+ * Note: only the routing objects are chosen at random, this is not a random
+ * assignment!
+ *
+ * Reference:
+ * <p>
+ * P. Ciaccia, M. Patella, P. Zezula<br />
+ * M-tree: An Efficient Access Method for Similarity Search in Metric Spaces<br />
+ * In Proceedings of 23rd International Conference on Very Large Data Bases
+ * (VLDB'97), August 25-29, 1997, Athens, Greece
+ * </p>
+ *
+ * @author Elke Achtert
+ *
+ * @param <O> the type of DatabaseObject to be stored in the M-Tree
+ * @param <D> the type of Distance used in the M-Tree
+ * @param <N> the type of AbstractMTreeNode used in the M-Tree
+ * @param <E> the type of MetricalEntry used in the M-Tree
+ */
+@Reference(authors = "P. Ciaccia, M. Patella, P. Zezula", title = "M-tree: An Efficient Access Method for Similarity Search in Metric Spaces", booktitle = "VLDB'97, Proceedings of 23rd International Conference on Very Large Data Bases, August 25-29, 1997, Athens, Greece", url = "http://www.vldb.org/conf/1997/P426.PDF")
+public class RandomSplit<O, D extends NumberDistance<D, ?>, N extends AbstractMTreeNode<O, D, N, E>, E extends MTreeEntry> extends MTreeSplit<O, D, N, E> {
+ /**
+ * Random generator.
+ */
+ private Random random;
+
+ /**
+ * Creates a new split object.
+ */
+ public RandomSplit(RandomFactory rnd) {
+ super();
+ this.random = rnd.getRandom();
+ }
+
+ /**
+ * Selects two objects of the specified node to be promoted and stored into
+ * the parent node. The m-RAD strategy considers all possible pairs of objects
+ * and, after partitioning the set of entries, promotes the pair of objects
+ * for which the sum of covering radiuses is minimum.
+ *
+ * @param tree Tree to use
+ * @param node the node to be split
+ */
+ @Override
+ public Assignments<E> split(AbstractMTree<O, D, N, E, ?> tree, N node) {
+ int pos1 = random.nextInt(node.getNumEntries());
+ int pos2 = random.nextInt(node.getNumEntries() - 1);
+ if (pos2 >= pos1) {
+ ++pos2;
+ }
+ DBID id1 = node.getEntry(pos1).getRoutingObjectID();
+ DBID id2 = node.getEntry(pos2).getRoutingObjectID();
+
+ return balancedPartition(tree, node, id1, id2);
+ }
+
+ /**
+ * Parameterization class.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.exclude
+ *
+ * @param <O> the type of DatabaseObject to be stored in the M-Tree
+ * @param <D> the type of Distance used in the M-Tree
+ * @param <N> the type of AbstractMTreeNode used in the M-Tree
+ * @param <E> the type of MetricalEntry used in the M-Tree
+ */
+ public static class Parameterizer<O, D extends NumberDistance<D, ?>, N extends AbstractMTreeNode<O, D, N, E>, E extends MTreeEntry> extends AbstractParameterizer {
+ /**
+ * Option ID for the random generator.
+ */
+ public static final OptionID RANDOM_ID = new OptionID("mtree.randomsplit.random", "Random generator / seed for the randomized split.");
+
+ /**
+ * Random generator
+ */
+ RandomFactory rnd = RandomFactory.DEFAULT;
+
+ @Override
+ protected void makeOptions(Parameterization config) {
+ super.makeOptions(config);
+ RandomParameter rndP = new RandomParameter(RANDOM_ID);
+ if (config.grab(rndP)) {
+ rnd = rndP.getValue();
+ }
+ }
+
+ @Override
+ protected RandomSplit<O, D, N, E> makeInstance() {
+ return new RandomSplit<>(rnd);
+ }
+ }
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/package-info.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/package-info.java
new file mode 100644
index 00000000..ed0fd729
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/package-info.java
@@ -0,0 +1,26 @@
+/**
+ * <p>Splitting strategies of nodes in an M-Tree (and variants).</p>
+ */
+/*
+ This file is part of ELKI:
+ Environment for Developing KDD-Applications Supported by Index-Structures
+
+ Copyright (C) 2013
+ Ludwig-Maximilians-Universität München
+ Lehr- und Forschungseinheit für Datenbanksysteme
+ ELKI Development Team
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package de.lmu.ifi.dbs.elki.index.tree.metrical.mtreevariants.strategies.split; \ No newline at end of file