diff options
Diffstat (limited to 'src/de/lmu/ifi/dbs/elki/index/tree')
167 files changed, 4088 insertions, 3170 deletions
diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/AbstractDirectoryEntry.java b/src/de/lmu/ifi/dbs/elki/index/tree/AbstractDirectoryEntry.java index 03572b35..a75a49eb 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/AbstractDirectoryEntry.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/AbstractDirectoryEntry.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree; 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/AbstractLeafEntry.java b/src/de/lmu/ifi/dbs/elki/index/tree/AbstractLeafEntry.java index ea5fd6de..15c8c589 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/AbstractLeafEntry.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/AbstractLeafEntry.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree; 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/AbstractNode.java b/src/de/lmu/ifi/dbs/elki/index/tree/AbstractNode.java index 4f2c6d04..2748b76e 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/AbstractNode.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/AbstractNode.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree; 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 @@ -98,7 +98,7 @@ public abstract class AbstractNode<E extends Entry> extends AbstractExternalizab public IndexTreePath<E> nextElement() { synchronized(AbstractNode.this) { if(count < numEntries) { - return parentPath.pathByAddingChild(new TreeIndexPathComponent<E>(entries[count], count++)); + return parentPath.pathByAddingChild(new TreeIndexPathComponent<>(entries[count], count++)); } } throw new NoSuchElementException(); @@ -284,7 +284,7 @@ public abstract class AbstractNode<E extends Entry> extends AbstractExternalizab */ @Deprecated public final List<E> getEntries() { - List<E> result = new ArrayList<E>(numEntries); + List<E> result = new ArrayList<>(numEntries); for(E entry : entries) { if(entry != null) { result.add(entry); diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/BreadthFirstEnumeration.java b/src/de/lmu/ifi/dbs/elki/index/tree/BreadthFirstEnumeration.java index 6f43de11..ec33050b 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/BreadthFirstEnumeration.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/BreadthFirstEnumeration.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree; 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 @@ -74,7 +74,7 @@ public class BreadthFirstEnumeration<N extends Node<E>, E extends Entry> impleme */ public BreadthFirstEnumeration(final IndexTree<N, E> index, final IndexTreePath<E> rootPath) { super(); - this.queue = new LinkedList<Enumeration<IndexTreePath<E>>>(); + this.queue = new LinkedList<>(); this.index = index; Enumeration<IndexTreePath<E>> root_enum = new Enumeration<IndexTreePath<E>>() { diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/DirectoryEntry.java b/src/de/lmu/ifi/dbs/elki/index/tree/DirectoryEntry.java index 68924cae..c7d74f13 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/DirectoryEntry.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/DirectoryEntry.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree; 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,12 @@ package de.lmu.ifi.dbs.elki.index.tree; along with this program. If not, see <http://www.gnu.org/licenses/>. */ - /** * Directory Entry * * @author Erich Schubert + * + * @apiviz.excludeSubtypes */ public interface DirectoryEntry extends Entry { /** @@ -42,4 +43,4 @@ public interface DirectoryEntry extends Entry { * Get the page ID of this leaf entry. */ public Integer getPageID(); -}
\ No newline at end of file +} diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/Entry.java b/src/de/lmu/ifi/dbs/elki/index/tree/Entry.java index 77c13d8e..c9c5e90a 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/Entry.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/Entry.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree; 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 @@ -30,6 +30,7 @@ import java.io.Externalizable; * represent a node or a data object. * * @author Elke Achtert + * @apiviz.excludeSubtypes */ public interface Entry extends Externalizable { /** diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/IndexTree.java b/src/de/lmu/ifi/dbs/elki/index/tree/IndexTree.java index 13e91151..ee3bd5d6 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/IndexTree.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/IndexTree.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree; 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,8 +24,8 @@ package de.lmu.ifi.dbs.elki.index.tree; */ import de.lmu.ifi.dbs.elki.logging.Logging; +import de.lmu.ifi.dbs.elki.logging.statistics.LongStatistic; import de.lmu.ifi.dbs.elki.persistent.PageFile; -import de.lmu.ifi.dbs.elki.persistent.PageFileStatistics; import de.lmu.ifi.dbs.elki.utilities.exceptions.AbortException; /** @@ -36,6 +36,7 @@ import de.lmu.ifi.dbs.elki.utilities.exceptions.AbortException; * @apiviz.composedOf PageFile * @apiviz.has Node oneway - - contains * @apiviz.has TreeIndexHeader oneway + * @apiviz.excludeSubtypes * * @param <N> the type of Node used in the index * @param <E> the type of Entry used in the index @@ -91,10 +92,9 @@ public abstract class IndexTree<N extends Node<E>, E extends Entry> { /** * Initialize the tree if the page file already existed. */ - // FIXME: ensure this is called in all the appropriate places! public void initialize() { TreeIndexHeader header = createHeader(); - if(this.file.initialize(header)) { + if (this.file.initialize(header)) { initializeFromFile(header, file); } rootEntry = createRootEntry(); @@ -115,7 +115,7 @@ public abstract class IndexTree<N extends Node<E>, E extends Entry> { public final E getRootEntry() { return rootEntry; } - + /** * Page ID of the root entry. * @@ -124,7 +124,7 @@ public abstract class IndexTree<N extends Node<E>, E extends Entry> { public final int getRootID() { return getPageID(rootEntry); } - + /** * Reads the root node of this index from the file. * @@ -133,7 +133,7 @@ public abstract class IndexTree<N extends Node<E>, E extends Entry> { public N getRoot() { return file.readPage(getPageID(rootEntry)); } - + /** * Test if a given ID is the root. * @@ -154,7 +154,7 @@ public abstract class IndexTree<N extends Node<E>, E extends Entry> { if (entry.isLeafEntry()) { throw new AbortException("Leafs do not have page ids!"); } - return ((DirectoryEntry)entry).getPageID(); + return ((DirectoryEntry) entry).getPageID(); } /** @@ -164,10 +164,9 @@ public abstract class IndexTree<N extends Node<E>, E extends Entry> { * @return the node with the specified id */ public N getNode(int nodeID) { - if(nodeID == getPageID(rootEntry)) { + if (nodeID == getPageID(rootEntry)) { return getRoot(); - } - else { + } else { return file.readPage(nodeID); } } @@ -181,7 +180,7 @@ public abstract class IndexTree<N extends Node<E>, E extends Entry> { public final N getNode(E entry) { return getNode(getPageID(entry)); } - + /** * Write a node to the backing storage. * @@ -223,7 +222,7 @@ public abstract class IndexTree<N extends Node<E>, E extends Entry> { this.dirMinimum = header.getDirMinimum(); this.leafMinimum = header.getLeafMinimum(); - if(getLogger().isDebugging()) { + if (getLogger().isDebugging()) { StringBuilder msg = new StringBuilder(); msg.append(getClass()); msg.append("\n file = ").append(file.getClass()); @@ -244,16 +243,13 @@ public abstract class IndexTree<N extends Node<E>, E extends Entry> { // create empty root createEmptyRoot(exampleLeaf); - if(getLogger().isDebugging()) { - StringBuilder msg = new StringBuilder(); - msg.append(getClass()).append("\n"); - msg.append(" file = ").append(file.getClass()).append("\n"); - msg.append(" maximum number of dir entries = ").append((dirCapacity - 1)).append("\n"); - msg.append(" minimum number of dir entries = ").append(dirMinimum).append("\n"); - msg.append(" maximum number of leaf entries = ").append((leafCapacity - 1)).append("\n"); - msg.append(" minimum number of leaf entries = ").append(leafMinimum).append("\n"); - msg.append(" root = ").append(getRoot()); - getLogger().debugFine(msg.toString()); + final Logging log = getLogger(); + if (log.isStatistics()) { + String cls = this.getClass().getName(); + log.statistics(new LongStatistic(cls + ".directory.capacity", dirCapacity)); + log.statistics(new LongStatistic(cls + ".directory.minfill", dirMinimum)); + log.statistics(new LongStatistic(cls + ".leaf.capacity", leafCapacity)); + log.statistics(new LongStatistic(cls + ".leaf.minfill", leafMinimum)); } initialized = true; @@ -265,7 +261,7 @@ public abstract class IndexTree<N extends Node<E>, E extends Entry> { * @return the path to the root of this tree */ public final IndexTreePath<E> getRootPath() { - return new IndexTreePath<E>(new TreeIndexPathComponent<E>(rootEntry, null)); + return new IndexTreePath<>(new TreeIndexPathComponent<>(rootEntry, null)); } /** @@ -322,14 +318,12 @@ public abstract class IndexTree<N extends Node<E>, E extends Entry> { } /** - * Get the index file page access statistics. - * - * @return access statistics + * Log some statistics, if enabled. */ - public PageFileStatistics getPageFileStatistics() { - return file; + public void logStatistics() { + file.logStatistics(); } - + /** * Get the page size of the backing storage. * @@ -348,4 +342,4 @@ public abstract class IndexTree<N extends Node<E>, E extends Entry> { protected PageFile<N> getFile() { return file; } -}
\ No newline at end of file +} diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/IndexTreePath.java b/src/de/lmu/ifi/dbs/elki/index/tree/IndexTreePath.java index 2634ae07..d9534e91 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/IndexTreePath.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/IndexTreePath.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree; 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 @@ -63,7 +63,7 @@ public class IndexTreePath<E extends Entry> { } lastPathComponent = path.get(path.size() - 1); if(path.size() > 1) { - parentPath = new IndexTreePath<E>(path, path.size() - 1); + parentPath = new IndexTreePath<>(path, path.size() - 1); } } @@ -106,7 +106,7 @@ public class IndexTreePath<E extends Entry> { protected IndexTreePath(List<TreeIndexPathComponent<E>> path, int length) { lastPathComponent = path.get(length - 1); if(length > 1) { - parentPath = new IndexTreePath<E>(path, length - 1); + parentPath = new IndexTreePath<>(path, length - 1); } } @@ -117,7 +117,7 @@ public class IndexTreePath<E extends Entry> { * @return an array of IndexPathComponent representing the IndexPath */ public List<TreeIndexPathComponent<E>> getPath() { - List<TreeIndexPathComponent<E>> result = new ArrayList<TreeIndexPathComponent<E>>(); + List<TreeIndexPathComponent<E>> result = new ArrayList<>(); for(IndexTreePath<E> path = this; path != null; path = path.parentPath) { result.add(path.lastPathComponent); @@ -262,8 +262,7 @@ public class IndexTreePath<E extends Entry> { if(child == null) { throw new NullPointerException("Null child not allowed"); } - - return new IndexTreePath<E>(this, child); + return new IndexTreePath<>(this, child); } /** diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/LeafEntry.java b/src/de/lmu/ifi/dbs/elki/index/tree/LeafEntry.java index c6eb1269..d020c8b1 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/LeafEntry.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/LeafEntry.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree; 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,6 +29,8 @@ import de.lmu.ifi.dbs.elki.database.ids.DBID; * Leaf entry * * @author Erich Schubert + * + * @apiviz.excludeSubtypes */ public interface LeafEntry extends Entry { /** diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/Node.java b/src/de/lmu/ifi/dbs/elki/index/tree/Node.java index c288a1fe..9f393f52 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/Node.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/Node.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree; 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 @@ -35,6 +35,7 @@ import de.lmu.ifi.dbs.elki.persistent.Page; * @author Elke Achtert * * @apiviz.composedOf Entry + * @apiviz.excludeSubtypes * * @param <E> the type of Entry used in the index */ diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/TreeIndexFactory.java b/src/de/lmu/ifi/dbs/elki/index/tree/TreeIndexFactory.java deleted file mode 100644 index c40effe5..00000000 --- a/src/de/lmu/ifi/dbs/elki/index/tree/TreeIndexFactory.java +++ /dev/null @@ -1,184 +0,0 @@ -package de.lmu.ifi.dbs.elki.index.tree; - -/* - 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 de.lmu.ifi.dbs.elki.database.relation.Relation; -import de.lmu.ifi.dbs.elki.index.Index; -import de.lmu.ifi.dbs.elki.index.IndexFactory; -import de.lmu.ifi.dbs.elki.persistent.ExternalizablePage; -import de.lmu.ifi.dbs.elki.persistent.LRUCache; -import de.lmu.ifi.dbs.elki.persistent.MemoryPageFile; -import de.lmu.ifi.dbs.elki.persistent.PageFile; -import de.lmu.ifi.dbs.elki.persistent.PersistentPageFile; -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.constraints.GreaterConstraint; -import de.lmu.ifi.dbs.elki.utilities.optionhandling.constraints.GreaterEqualConstraint; -import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization; -import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.FileParameter; -import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.IntParameter; -import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.LongParameter; - -/** - * Abstract base class for tree-based indexes. - * - * @author Erich Schubert - * - * @apiviz.stereotype factory,interface - * @apiviz.has Index oneway - - «create» - * - * @param <O> Object type - * @param <I> Index type - */ -// TODO: actually, this class should be called PagedIndexFactory? -public abstract class TreeIndexFactory<O, I extends Index> implements IndexFactory<O, I> { - /** - * Optional parameter that specifies the name of the file storing the index. - * If this parameter is not set the index is hold in the main memory. - * <p> - * Key: {@code -treeindex.file} - * </p> - */ - public static final OptionID FILE_ID = new OptionID("treeindex.file", "The name of the file storing the index. " + "If this parameter is not set the index is hold in the main memory."); - - /** - * Parameter to specify the size of a page in bytes, must be an integer - * greater than 0. - * <p> - * Default value: {@code 4000} - * </p> - * <p> - * Key: {@code -treeindex.pagesize} - * </p> - */ - public static final OptionID PAGE_SIZE_ID = new OptionID("treeindex.pagesize", "The size of a page in bytes."); - - /** - * Parameter to specify the size of the cache in bytes, must be an integer - * equal to or greater than 0. - * <p> - * Default value: {@link Integer#MAX_VALUE} - * </p> - * <p> - * Key: {@code -treeindex.cachesize} - * </p> - */ - public static final OptionID CACHE_SIZE_ID = new OptionID("treeindex.cachesize", "The size of the cache in bytes."); - - /** - * Holds the name of the file storing the index specified by {@link #FILE_ID}, - * null if {@link #FILE_ID} is not specified. - */ - protected String fileName = null; - - /** - * Holds the value of {@link #PAGE_SIZE_ID}. - */ - protected int pageSize; - - /** - * Holds the value of {@link #CACHE_SIZE_ID}. - */ - protected long cacheSize; - - /** - * Constructor. - * - * @param fileName - * @param pageSize - * @param cacheSize - */ - public TreeIndexFactory(String fileName, int pageSize, long cacheSize) { - super(); - this.fileName = fileName; - this.pageSize = pageSize; - this.cacheSize = cacheSize; - } - - /** - * Make the page file for this index. - * - * @param <N> page type - * @param cls Class information - * @return Page file - */ - // FIXME: make this single-shot when filename is set! - protected <N extends ExternalizablePage> PageFile<N> makePageFile(Class<N> cls) { - final PageFile<N> inner; - if (fileName == null) { - inner = new MemoryPageFile<N>(pageSize); - } else { - inner = new PersistentPageFile<N>(pageSize, fileName, cls); - } - if (cacheSize >= Integer.MAX_VALUE) { - return inner; - } - return new LRUCache<N>(cacheSize, inner); - } - - @Override - abstract public I instantiate(Relation<O> relation); - - /** - * Parameterization class. - * - * @author Erich Schubert - * - * @apiviz.exclude - */ - public abstract static class Parameterizer<O> extends AbstractParameterizer { - protected String fileName = null; - - protected int pageSize; - - protected long cacheSize; - - @Override - protected void makeOptions(Parameterization config) { - super.makeOptions(config); - FileParameter fileNameP = new FileParameter(FILE_ID, FileParameter.FileType.OUTPUT_FILE, true); - if (config.grab(fileNameP)) { - fileName = fileNameP.getValue().getPath(); - } else { - fileName = null; - } - - final IntParameter pageSizeP = new IntParameter(PAGE_SIZE_ID, 4000); - pageSizeP.addConstraint(new GreaterConstraint(0)); - if (config.grab(pageSizeP)) { - pageSize = pageSizeP.getValue(); - } - - // FIXME: long, but limited to int values?!? - LongParameter cacheSizeP = new LongParameter(CACHE_SIZE_ID, Integer.MAX_VALUE); - cacheSizeP.addConstraint(new GreaterEqualConstraint(0)); - if (config.grab(cacheSizeP)) { - cacheSize = cacheSizeP.getValue(); - } - } - - @Override - protected abstract TreeIndexFactory<O, ?> makeInstance(); - } -} diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/TreeIndexHeader.java b/src/de/lmu/ifi/dbs/elki/index/tree/TreeIndexHeader.java index 017c3571..42688ef0 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/TreeIndexHeader.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/TreeIndexHeader.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree; 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 @@ -250,7 +250,7 @@ public class TreeIndexHeader extends DefaultPageHeader { @SuppressWarnings("unchecked") public Stack<Integer> readEmptyPages(RandomAccessFile file) throws IOException, ClassNotFoundException { if(emptyPagesSize == 0) { - return new Stack<Integer>(); + return new Stack<>(); } byte[] bytes = new byte[emptyPagesSize]; file.seek(file.length() - emptyPagesSize); diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/TreeIndexPathComponent.java b/src/de/lmu/ifi/dbs/elki/index/tree/TreeIndexPathComponent.java index d2800d54..1ef146cf 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/TreeIndexPathComponent.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/TreeIndexPathComponent.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree; 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/MetricalIndexTree.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/MetricalIndexTree.java index b98841aa..2494eb39 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/MetricalIndexTree.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/MetricalIndexTree.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical; 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,7 +25,6 @@ package de.lmu.ifi.dbs.elki.index.tree.metrical; import java.util.List; -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.index.tree.Entry; @@ -61,13 +60,6 @@ public abstract class MetricalIndexTree<O, D extends Distance<D>, N extends Node public abstract DistanceFunction<? super O, D> getDistanceFunction(); /** - * Returns the distance function of this metrical index. - * - * @return the distance function of this metrical index - */ - public abstract DistanceQuery<O, D> getDistanceQuery(); - - /** * Returns a list of entries pointing to the leaf nodes of this spatial index. * * @return a list of entries pointing to the leaf nodes of this spatial index 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/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/DistanceEntry.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/DistanceEntry.java index 3cf6dfb9..642e5a63 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/DistanceEntry.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/DistanceEntry.java @@ -1,10 +1,12 @@ -package de.lmu.ifi.dbs.elki.index.tree; +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) 2012 + Copyright (C) 2013 Ludwig-Maximilians-Universität München Lehr- und Forschungseinheit für Datenbanksysteme ELKI Development Team @@ -23,21 +25,17 @@ package de.lmu.ifi.dbs.elki.index.tree; along with this program. If not, see <http://www.gnu.org/licenses/>. */ -import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance; - /** * Helper class: encapsulates an entry in an Index and a distance value * belonging to this entry. * * @author Elke Achtert * - * @apiviz.composedOf Distance * @apiviz.uses Entry * * @param <E> the type of Entry used in the index - * @param <D> the type of Distance used */ -public class DistanceEntry<D extends Distance<D>, E extends Entry> implements Comparable<DistanceEntry<D, E>> { +public class DistanceEntry<E extends Entry> implements Comparable<DistanceEntry<E>> { /** * The entry of the Index. */ @@ -46,7 +44,7 @@ public class DistanceEntry<D extends Distance<D>, E extends Entry> implements Co /** * The distance value belonging to the entry. */ - private D distance; + private double distance; /** * The index of the entry in its parent's child array. @@ -60,7 +58,7 @@ public class DistanceEntry<D extends Distance<D>, E extends Entry> implements Co * @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, D distance, int index) { + public DistanceEntry(E entry, double distance, int index) { this.entry = entry; this.distance = distance; this.index = index; @@ -80,7 +78,7 @@ public class DistanceEntry<D extends Distance<D>, E extends Entry> implements Co * * @return the distance value belonging to the entry */ - public D getDistance() { + public double getDistance() { return distance; } @@ -103,13 +101,13 @@ public class DistanceEntry<D extends Distance<D>, E extends Entry> implements Co * being compared to this Object. */ @Override - public int compareTo(DistanceEntry<D, E> o) { - int comp = distance.compareTo(o.distance); - if(comp != 0) { + 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 entry.getEntryID().compareTo(o.entry.getEntryID()); return 0; } @@ -122,4 +120,4 @@ public class DistanceEntry<D extends Distance<D>, E extends Entry> implements Co public String toString() { return "" + entry.toString() + "(" + distance + ")"; } -}
\ No newline at end of file +} 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 diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/package-info.java b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/package-info.java index 2ca4396c..b1a76d8b 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/package-info.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/metrical/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/package-info.java b/src/de/lmu/ifi/dbs/elki/index/tree/package-info.java index 3ba785f2..6c34473f 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/package-info.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/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/query/DoubleDistanceSearchCandidate.java b/src/de/lmu/ifi/dbs/elki/index/tree/query/DoubleDistanceSearchCandidate.java index 1a3fc948..fd9ee2f9 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/query/DoubleDistanceSearchCandidate.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/query/DoubleDistanceSearchCandidate.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.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 @@ -38,7 +38,7 @@ public class DoubleDistanceSearchCandidate implements Comparable<DoubleDistanceS /** * Page id */ - public Integer nodeID; + public int nodeID; /** * Constructor. @@ -46,7 +46,7 @@ public class DoubleDistanceSearchCandidate implements Comparable<DoubleDistanceS * @param mindist The minimum distance to this candidate * @param pagenr The page number of this candidate */ - public DoubleDistanceSearchCandidate(final double mindist, final Integer pagenr) { + public DoubleDistanceSearchCandidate(final double mindist, final int pagenr) { super(); this.mindist = mindist; this.nodeID = pagenr; diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/query/DoubleMTreeDistanceSearchCandidate.java b/src/de/lmu/ifi/dbs/elki/index/tree/query/DoubleMTreeDistanceSearchCandidate.java index c26ac801..3be9ff09 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/query/DoubleMTreeDistanceSearchCandidate.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/query/DoubleMTreeDistanceSearchCandidate.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.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 @@ -54,7 +54,7 @@ public class DoubleMTreeDistanceSearchCandidate extends DoubleDistanceSearchCand * @param routingDistance the distance from the query object to the query * object */ - public DoubleMTreeDistanceSearchCandidate(final double mindist, final Integer nodeID, final DBID routingObjectID, double routingDistance) { + public DoubleMTreeDistanceSearchCandidate(final double mindist, final int nodeID, final DBID routingObjectID, double routingDistance) { super(mindist, nodeID); this.routingObjectID = routingObjectID; this.routingDistance = routingDistance; diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/query/GenericDistanceSearchCandidate.java b/src/de/lmu/ifi/dbs/elki/index/tree/query/GenericDistanceSearchCandidate.java index dd764990..278dec60 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/query/GenericDistanceSearchCandidate.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/query/GenericDistanceSearchCandidate.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.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 @@ -41,7 +41,7 @@ public class GenericDistanceSearchCandidate<D extends Distance<D>> implements Co /** * Page id */ - public Integer nodeID; + public int nodeID; /** * Constructor. @@ -49,7 +49,7 @@ public class GenericDistanceSearchCandidate<D extends Distance<D>> implements Co * @param mindist The minimum distance to this candidate * @param pagenr The page number of this candidate */ - public GenericDistanceSearchCandidate(final D mindist, final Integer pagenr) { + public GenericDistanceSearchCandidate(final D mindist, final int pagenr) { super(); this.mindist = mindist; this.nodeID = pagenr; diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/query/GenericMTreeDistanceSearchCandidate.java b/src/de/lmu/ifi/dbs/elki/index/tree/query/GenericMTreeDistanceSearchCandidate.java index 94335860..cbe0451e 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/query/GenericMTreeDistanceSearchCandidate.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/query/GenericMTreeDistanceSearchCandidate.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.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,7 +24,6 @@ package de.lmu.ifi.dbs.elki.index.tree.query; */ import de.lmu.ifi.dbs.elki.database.ids.DBID; -import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance; /** * Encapsulates the attributes for a object that can be stored in a heap. The @@ -33,20 +32,25 @@ import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance; * holds the id of the routing object of the underlying M-Tree node and its * covering radius. * - * @author Elke Achtert + * FIXME: Class naming in this package is inconsistent. * - * @param <D> the type of Distance used in the M-Tree + * @author Elke Achtert */ -public class GenericMTreeDistanceSearchCandidate<D extends Distance<D>> extends GenericDistanceSearchCandidate<D> { +public class GenericMTreeDistanceSearchCandidate implements Comparable<GenericMTreeDistanceSearchCandidate> { /** * The id of the routing object. */ public DBID routingObjectID; - + + /** + * Minimum distance. + */ + public double mindist; + /** - * The distance from the query to the routing object. + * Node ID. */ - public D routingDistance; + public int nodeID; /** * Creates a new heap node with the specified parameters. @@ -54,11 +58,35 @@ public class GenericMTreeDistanceSearchCandidate<D extends Distance<D>> extends * @param mindist the minimum distance of the node * @param nodeID the id of the node * @param routingObjectID the id of the routing object of the node - * @param routingDistance the distance from query to routing object */ - public GenericMTreeDistanceSearchCandidate(final D mindist, final Integer nodeID, final DBID routingObjectID, final D routingDistance) { - super(mindist, nodeID); + public GenericMTreeDistanceSearchCandidate(final double mindist, final int nodeID, final DBID routingObjectID) { + this.mindist = mindist; + this.nodeID = nodeID; this.routingObjectID = routingObjectID; - this.routingDistance = routingDistance; } -}
\ No newline at end of file + + @Override + public int hashCode() { + return nodeID; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + GenericMTreeDistanceSearchCandidate other = (GenericMTreeDistanceSearchCandidate) obj; + return nodeID == other.nodeID; + } + + @Override + public int compareTo(GenericMTreeDistanceSearchCandidate o) { + return Double.compare(this.mindist, o.mindist); + } +} diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/query/package-info.java b/src/de/lmu/ifi/dbs/elki/index/tree/query/package-info.java index 5b8f56f6..29976738 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/query/package-info.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/query/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/spatial/SpatialDirectoryEntry.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/SpatialDirectoryEntry.java index 9833e5b5..4a131cbf 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/SpatialDirectoryEntry.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/SpatialDirectoryEntry.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial; 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/spatial/SpatialEntry.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/SpatialEntry.java index c50a5ebf..4fe55adf 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/SpatialEntry.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/SpatialEntry.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial; 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/spatial/SpatialIndexTree.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/SpatialIndexTree.java index 3b9eaa6b..b4bd5208 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/SpatialIndexTree.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/SpatialIndexTree.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial; 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/spatial/SpatialNode.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/SpatialNode.java index 8bf25766..449992a2 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/SpatialNode.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/SpatialNode.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial; 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/spatial/SpatialPair.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/SpatialPair.java index f29680e7..f69b1dd1 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/SpatialPair.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/SpatialPair.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial; 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/spatial/SpatialPointLeafEntry.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/SpatialPointLeafEntry.java index 60981677..d79893b0 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/SpatialPointLeafEntry.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/SpatialPointLeafEntry.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial; 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 @@ -30,6 +30,7 @@ import java.io.ObjectOutput; import de.lmu.ifi.dbs.elki.data.NumberVector; import de.lmu.ifi.dbs.elki.database.ids.DBID; import de.lmu.ifi.dbs.elki.index.tree.AbstractLeafEntry; +import de.lmu.ifi.dbs.elki.math.linearalgebra.Vector; /** * Represents an entry in a leaf node of a spatial index. A SpatialLeafEntry @@ -38,7 +39,7 @@ import de.lmu.ifi.dbs.elki.index.tree.AbstractLeafEntry; * * @author Elke Achtert */ -public class SpatialPointLeafEntry extends AbstractLeafEntry implements SpatialEntry { +public class SpatialPointLeafEntry extends AbstractLeafEntry implements SpatialEntry, NumberVector<Double> { /** * Serial version. */ @@ -69,7 +70,7 @@ public class SpatialPointLeafEntry extends AbstractLeafEntry implements SpatialE /** * Constructor from number vector. - * + * * @param id Object id * @param vector Number vector */ @@ -77,7 +78,7 @@ public class SpatialPointLeafEntry extends AbstractLeafEntry implements SpatialE super(id); int dim = vector.getDimensionality(); this.values = new double[dim]; - for(int i = 0; i < dim; i++) { + for (int i = 0; i < dim; i++) { values[i] = vector.doubleValue(i); } } @@ -117,7 +118,7 @@ public class SpatialPointLeafEntry extends AbstractLeafEntry implements SpatialE public void writeExternal(ObjectOutput out) throws IOException { super.writeExternal(out); out.writeInt(values.length); - for(double v : values) { + for (double v : values) { out.writeDouble(v); } } @@ -135,8 +136,49 @@ public class SpatialPointLeafEntry extends AbstractLeafEntry implements SpatialE public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { super.readExternal(in); values = new double[in.readInt()]; - for(int d = 0; d < values.length; d++) { + for (int d = 0; d < values.length; d++) { values[d] = in.readDouble(); } } -}
\ No newline at end of file + + @Override + @Deprecated + public Double getValue(int dimension) { + return values[dimension]; + } + + @Override + public double doubleValue(int dimension) { + return values[dimension]; + } + + @Override + public float floatValue(int dimension) { + return (float) values[dimension]; + } + + @Override + public int intValue(int dimension) { + return (int) values[dimension]; + } + + @Override + public long longValue(int dimension) { + return (long) values[dimension]; + } + + @Override + public short shortValue(int dimension) { + return (short) values[dimension]; + } + + @Override + public byte byteValue(int dimension) { + return (byte) values[dimension]; + } + + @Override + public Vector getColumnVector() { + return new Vector(values.clone()); + } +} diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/kd/MinimalisticMemoryKDTree.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/kd/MinimalisticMemoryKDTree.java new file mode 100644 index 00000000..28f19a25 --- /dev/null +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/kd/MinimalisticMemoryKDTree.java @@ -0,0 +1,443 @@ +package de.lmu.ifi.dbs.elki.index.tree.spatial.kd; + +/* + 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.data.NumberVector; +import de.lmu.ifi.dbs.elki.data.VectorUtil; +import de.lmu.ifi.dbs.elki.data.VectorUtil.SortDBIDsBySingleDimension; +import de.lmu.ifi.dbs.elki.data.type.TypeInformation; +import de.lmu.ifi.dbs.elki.data.type.TypeUtil; +import de.lmu.ifi.dbs.elki.database.ids.ArrayModifiableDBIDs; +import de.lmu.ifi.dbs.elki.database.ids.DBIDArrayIter; +import de.lmu.ifi.dbs.elki.database.ids.DBIDUtil; +import de.lmu.ifi.dbs.elki.database.ids.distance.DoubleDistanceDBIDPairList; +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.ids.distance.ModifiableDoubleDistanceDBIDList; +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.database.query.knn.KNNQuery; +import de.lmu.ifi.dbs.elki.database.query.range.AbstractDistanceRangeQuery; +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.distancefunction.DoubleNorm; +import de.lmu.ifi.dbs.elki.distance.distancefunction.minkowski.LPNormDistanceFunction; +import de.lmu.ifi.dbs.elki.distance.distancefunction.minkowski.SparseLPNormDistanceFunction; +import de.lmu.ifi.dbs.elki.distance.distancefunction.minkowski.SquaredEuclideanDistanceFunction; +import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance; +import de.lmu.ifi.dbs.elki.distance.distancevalue.DoubleDistance; +import de.lmu.ifi.dbs.elki.index.AbstractIndex; +import de.lmu.ifi.dbs.elki.index.IndexFactory; +import de.lmu.ifi.dbs.elki.index.KNNIndex; +import de.lmu.ifi.dbs.elki.index.RangeIndex; +import de.lmu.ifi.dbs.elki.logging.Logging; +import de.lmu.ifi.dbs.elki.logging.statistics.Counter; +import de.lmu.ifi.dbs.elki.utilities.Alias; +import de.lmu.ifi.dbs.elki.utilities.datastructures.QuickSelect; +import de.lmu.ifi.dbs.elki.utilities.documentation.Reference; + +/** + * Simple implementation of a static in-memory K-D-tree. Does not support + * dynamic updates or anything, but also is very simple and memory efficient: + * all it uses is one {@link ArrayModifiableDBIDs} to sort the data in a + * serialized tree. + * + * @author Erich Schubert + * + * @apiviz.has KDTreeKNNQuery + * @apiviz.has KDTreeRangeQuery + * + * @param <O> Vector type + */ +@Reference(authors = "J. L. Bentley", title = "Multidimensional binary search trees used for associative searching", booktitle = "Communications of the ACM, Vol. 18 Issue 9, Sept. 1975", url = "http://dx.doi.org/10.1145/361002.361007") +public class MinimalisticMemoryKDTree<O extends NumberVector<?>> extends AbstractIndex<O> implements KNNIndex<O>, RangeIndex<O> { + /** + * Class logger + */ + private static final Logging LOG = Logging.getLogger(MinimalisticMemoryKDTree.class); + + /** + * The actual "tree" as a sorted array. + */ + ArrayModifiableDBIDs sorted = null; + + /** + * The number of dimensions. + */ + int dims = -1; + + /** + * Counter for comparisons. + */ + final Counter objaccess; + + /** + * Counter for distance computations. + */ + final Counter distcalc; + + /** + * Constructor. + * + * @param relation Relation to index + */ + public MinimalisticMemoryKDTree(Relation<O> relation) { + super(relation); + if(LOG.isStatistics()) { + String prefix = this.getClass().getName(); + this.objaccess = LOG.newCounter(prefix + ".objaccess"); + this.distcalc = LOG.newCounter(prefix + ".distancecalcs"); + } + else { + this.objaccess = null; + this.distcalc = null; + } + } + + @Override + public void initialize() { + sorted = DBIDUtil.newArray(relation.getDBIDs()); + dims = RelationUtil.dimensionality(relation); + SortDBIDsBySingleDimension comp = new VectorUtil.SortDBIDsBySingleDimension(relation); + buildTree(0, sorted.size(), 0, comp); + } + + /** + * Recursively build the tree by partial sorting. O(n log n) complexity. + * Apparently there exists a variant in only O(n log log n)? Please + * contribute! + * + * @param left Interval minimum + * @param right Interval maximum + * @param axis Current splitting axis + * @param comp Comparator + */ + private void buildTree(int left, int right, int axis, SortDBIDsBySingleDimension comp) { + final int middle = (left + right) >>> 1; + comp.setDimension(axis); + + QuickSelect.quickSelect(sorted, comp, left, right, middle); + final int next = (axis + 1) % dims; + if(left < middle) { + buildTree(left, middle, next, comp); + } + if(middle + 1 < right) { + buildTree(middle + 1, right, next, comp); + } + } + + @Override + public String getLongName() { + return "kd-tree"; + } + + @Override + public String getShortName() { + return "kd-tree"; + } + + @Override + public void logStatistics() { + if(objaccess != null) { + LOG.statistics(objaccess); + } + if(distcalc != null) { + LOG.statistics(distcalc); + } + } + + /** + * Count a single object access. + */ + protected void countObjectAccess() { + if(objaccess != null) { + objaccess.increment(); + } + } + + /** + * Count a distance computation. + */ + protected void countDistanceComputation() { + if(distcalc != null) { + distcalc.increment(); + } + } + + @SuppressWarnings("unchecked") + @Override + public <D extends Distance<D>> KNNQuery<O, D> getKNNQuery(DistanceQuery<O, D> distanceQuery, Object... hints) { + DistanceFunction<? super O, D> df = distanceQuery.getDistanceFunction(); + // TODO: if we know this works for other distance functions, add them, too! + if(df instanceof LPNormDistanceFunction) { + return (KNNQuery<O, D>) new KDTreeKNNQuery((DistanceQuery<O, DoubleDistance>) distanceQuery, (DoubleNorm<? super O>) df); + } + if(df instanceof SquaredEuclideanDistanceFunction) { + return (KNNQuery<O, D>) new KDTreeKNNQuery((DistanceQuery<O, DoubleDistance>) distanceQuery, (DoubleNorm<? super O>) df); + } + if(df instanceof SparseLPNormDistanceFunction) { + return (KNNQuery<O, D>) new KDTreeKNNQuery((DistanceQuery<O, DoubleDistance>) distanceQuery, (DoubleNorm<? super O>) df); + } + return null; + } + + @SuppressWarnings("unchecked") + @Override + public <D extends Distance<D>> RangeQuery<O, D> getRangeQuery(DistanceQuery<O, D> distanceQuery, Object... hints) { + DistanceFunction<? super O, D> df = distanceQuery.getDistanceFunction(); + // TODO: if we know this works for other distance functions, add them, too! + if(df instanceof LPNormDistanceFunction) { + return (RangeQuery<O, D>) new KDTreeRangeQuery((DistanceQuery<O, DoubleDistance>) distanceQuery, (DoubleNorm<? super O>) df); + } + if(df instanceof SquaredEuclideanDistanceFunction) { + return (RangeQuery<O, D>) new KDTreeRangeQuery((DistanceQuery<O, DoubleDistance>) distanceQuery, (DoubleNorm<? super O>) df); + } + if(df instanceof SparseLPNormDistanceFunction) { + return (RangeQuery<O, D>) new KDTreeRangeQuery((DistanceQuery<O, DoubleDistance>) distanceQuery, (DoubleNorm<? super O>) df); + } + return null; + } + + /** + * kNN query for the k-d-tree. + * + * @author Erich Schubert + */ + public class KDTreeKNNQuery extends AbstractDistanceKNNQuery<O, DoubleDistance> { + /** + * Norm to use. + */ + private DoubleNorm<? super O> norm; + + /** + * Constructor. + * + * @param distanceQuery Distance query + * @param norm Norm to use + */ + public KDTreeKNNQuery(DistanceQuery<O, DoubleDistance> distanceQuery, DoubleNorm<? super O> norm) { + super(distanceQuery); + this.norm = norm; + } + + @Override + public KNNList<DoubleDistance> getKNNForObject(O obj, int k) { + final DoubleDistanceKNNHeap knns = (DoubleDistanceKNNHeap) DBIDUtil.newHeap(DoubleDistance.FACTORY, k); + kdKNNSearch(0, sorted.size(), 0, obj, knns, sorted.iter(), Double.POSITIVE_INFINITY); + return knns.toKNNList(); + } + + /** + * Perform a kNN search on the kd-tree. + * + * @param left Subtree begin + * @param right Subtree end (exclusive) + * @param axis Current splitting axis + * @param query Query object + * @param knns kNN heap + * @param iter Iterator variable (reduces memory footprint!) + * @param maxdist Current upper bound of kNN distance. + * @return New upper bound of kNN distance. + */ + private double kdKNNSearch(int left, int right, int axis, O query, DoubleDistanceKNNHeap knns, DBIDArrayIter iter, double maxdist) { + // Look at current node: + final int middle = (left + right) >>> 1; + iter.seek(middle); + O split = relation.get(iter); + countObjectAccess(); + + // Distance to axis: + final double delta = split.doubleValue(axis) - query.doubleValue(axis); + final boolean onleft = (delta >= 0); + final boolean onright = (delta <= 0); + + // Next axis: + final int next = (axis + 1) % dims; + + // Exact match chance (delta == 0)! + // process first, then descend both sides. + if(onleft && onright) { + double dist = norm.doubleDistance(query, split); + countDistanceComputation(); + if(dist <= maxdist) { + iter.seek(middle); + knns.add(dist, iter); + maxdist = knns.doubleKNNDistance(); + } + if(left < middle) { + maxdist = kdKNNSearch(left, middle, next, query, knns, iter, maxdist); + } + if(middle + 1 < right) { + maxdist = kdKNNSearch(middle + 1, right, next, query, knns, iter, maxdist); + } + } + else { + if(onleft) { + if(left < middle) { + maxdist = kdKNNSearch(left, middle, next, query, knns, iter, maxdist); + } + // Look at splitting element (unless already above): + if(Math.abs(delta) <= maxdist) { + double dist = norm.doubleDistance(query, split); + countDistanceComputation(); + if(dist <= maxdist) { + iter.seek(middle); + knns.add(dist, iter); + maxdist = knns.doubleKNNDistance(); + } + } + if((middle + 1 < right) && (Math.abs(delta) <= maxdist)) { + maxdist = kdKNNSearch(middle + 1, right, next, query, knns, iter, maxdist); + } + } + else { // onright + if(middle + 1 < right) { + maxdist = kdKNNSearch(middle + 1, right, next, query, knns, iter, maxdist); + } + // Look at splitting element (unless already above): + if(Math.abs(delta) <= maxdist) { + double dist = norm.doubleDistance(query, split); + countDistanceComputation(); + if(dist <= maxdist) { + iter.seek(middle); + knns.add(dist, iter); + maxdist = knns.doubleKNNDistance(); + } + } + if((left < middle) && (Math.abs(delta) <= maxdist)) { + maxdist = kdKNNSearch(left, middle, next, query, knns, iter, maxdist); + } + } + } + return maxdist; + } + } + + /** + * kNN query for the k-d-tree. + * + * @author Erich Schubert + */ + public class KDTreeRangeQuery extends AbstractDistanceRangeQuery<O, DoubleDistance> { + /** + * Norm to use. + */ + private DoubleNorm<? super O> norm; + + /** + * Constructor. + * + * @param distanceQuery Distance query + * @param norm Norm to use + */ + public KDTreeRangeQuery(DistanceQuery<O, DoubleDistance> distanceQuery, DoubleNorm<? super O> norm) { + super(distanceQuery); + this.norm = norm; + } + + @Override + public DoubleDistanceDBIDPairList getRangeForObject(O obj, DoubleDistance range) { + final DoubleDistanceDBIDPairList res = new DoubleDistanceDBIDPairList(); + kdRangeSearch(0, sorted.size(), 0, obj, res, sorted.iter(), range.doubleValue()); + res.sort(); + return res; + } + + /** + * Perform a kNN search on the kd-tree. + * + * @param left Subtree begin + * @param right Subtree end (exclusive) + * @param axis Current splitting axis + * @param query Query object + * @param res kNN heap + * @param iter Iterator variable (reduces memory footprint!) + * @param radius Query radius + */ + private void kdRangeSearch(int left, int right, int axis, O query, ModifiableDoubleDistanceDBIDList res, DBIDArrayIter iter, double radius) { + // Look at current node: + final int middle = (left + right) >>> 1; + iter.seek(middle); + O split = relation.get(iter); + countObjectAccess(); + + // Distance to axis: + final double delta = split.doubleValue(axis) - query.doubleValue(axis); + final boolean onleft = (delta >= 0); + final boolean onright = (delta <= 0); + final boolean close = (Math.abs(delta) <= radius); + + // Next axis: + final int next = (axis + 1) % dims; + + // Current object: + if(close) { + double dist = norm.doubleDistance(query, split); + countDistanceComputation(); + if(dist <= radius) { + iter.seek(middle); + res.add(dist, iter); + } + } + if(left < middle && (onleft || close)) { + kdRangeSearch(left, middle, next, query, res, iter, radius); + } + if(middle + 1 < right && (onright || close)) { + kdRangeSearch(middle + 1, right, next, query, res, iter, radius); + } + } + } + + /** + * Factory class + * + * @author Erich Schubert + * + * @apiviz.stereotype factory + * @apiviz.has MinimalisticMemoryKDTree + * + * @param <O> Vector type + */ + @Alias({"minikd", "kd"}) + public static class Factory<O extends NumberVector<?>> implements IndexFactory<O, MinimalisticMemoryKDTree<O>> { + /** + * Constructor. Trivial parameterizable. + */ + public Factory() { + super(); + } + + @Override + public MinimalisticMemoryKDTree<O> instantiate(Relation<O> relation) { + return new MinimalisticMemoryKDTree<>(relation); + } + + @Override + public TypeInformation getInputTypeRestriction() { + return TypeUtil.NUMBER_VECTOR_FIELD; + } + } +} 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/spatial/kd/package-info.java index ed13ae73..88a42c2d 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/split/package-info.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/kd/package-info.java @@ -1,11 +1,11 @@ /** - * <p>Splitting strategies of nodes in an M-Tree (and variants).</p> + * <p>K-d-tree and variants.</p> */ /* 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,4 +23,4 @@ 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 +package de.lmu.ifi.dbs.elki.index.tree.spatial.kd;
\ No newline at end of file diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/package-info.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/package-info.java index fb5c67ee..7fbdd2ac 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/package-info.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/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/spatial/rstarvariants/AbstractRStarTree.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/AbstractRStarTree.java index 8ede52d7..63c8e8fa 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/AbstractRStarTree.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/AbstractRStarTree.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants; 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 @@ -46,16 +46,11 @@ import de.lmu.ifi.dbs.elki.index.tree.spatial.SpatialDirectoryEntry; import de.lmu.ifi.dbs.elki.index.tree.spatial.SpatialEntry; import de.lmu.ifi.dbs.elki.index.tree.spatial.SpatialIndexTree; import de.lmu.ifi.dbs.elki.index.tree.spatial.SpatialPointLeafEntry; -import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.bulk.BulkSplit; -import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.insert.InsertionStrategy; -import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.insert.LeastOverlapInsertionStrategy; -import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.overflow.LimitedReinsertOverflowTreatment; -import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.overflow.OverflowTreatment; -import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.split.SplitStrategy; -import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.split.TopologicalSplitter; import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.util.NodeArrayAdapter; +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.exceptions.AbortException; /** @@ -68,15 +63,13 @@ import de.lmu.ifi.dbs.elki.utilities.exceptions.AbortException; * * @apiviz.landmark * @apiviz.has AbstractRStarTreeNode oneway - - contains - * @apiviz.composedOf BulkSplit - * @apiviz.composedOf SplitStrategy - * @apiviz.composedOf InsertionStrategy - * @apiviz.composedOf OverflowTreatment + * @apiviz.composedOf AbstractRTreeSettings + * @apiviz.composedOf Statistics * * @param <N> Node type * @param <E> Entry type */ -public abstract class AbstractRStarTree<N extends AbstractRStarTreeNode<N, E>, E extends SpatialEntry> extends SpatialIndexTree<N, E> { +public abstract class AbstractRStarTree<N extends AbstractRStarTreeNode<N, E>, E extends SpatialEntry, S extends AbstractRTreeSettings> extends SpatialIndexTree<N, E> { /** * Development flag: This will enable some extra integrity checks on the tree. */ @@ -90,7 +83,7 @@ public abstract class AbstractRStarTree<N extends AbstractRStarTreeNode<N, E>, E /** * For counting the number of distance computations. */ - public int distanceCalcs = 0; + public Statistics statistics = new Statistics(); /** * The last inserted entry. @@ -98,92 +91,19 @@ public abstract class AbstractRStarTree<N extends AbstractRStarTreeNode<N, E>, E E lastInsertedEntry = null; /** - * The strategy for bulk load. + * Settings class. */ - protected BulkSplit bulkSplitter; - - /** - * The split strategy. - */ - protected SplitStrategy nodeSplitter = TopologicalSplitter.STATIC; - - /** - * The insertion strategy to use. - */ - protected InsertionStrategy insertionStrategy = LeastOverlapInsertionStrategy.STATIC; - - /** - * Overflow treatment. - */ - protected OverflowTreatment overflowTreatment = LimitedReinsertOverflowTreatment.RSTAR_OVERFLOW; - - /** - * Relative minimum fill. - */ - protected double relativeMinFill = 0.4; + protected S settings; /** * Constructor. * * @param pagefile Page file + * @param settings Settings */ - public AbstractRStarTree(PageFile<N> pagefile) { + public AbstractRStarTree(PageFile<N> pagefile, S settings) { super(pagefile); - } - - /** - * Set the bulk loading strategy. - * - * @param bulkSplitter Bulk loading strategy - */ - public void setBulkStrategy(BulkSplit bulkSplitter) { - this.bulkSplitter = bulkSplitter; - } - - /** - * Set the node splitting strategy. - * - * @param nodeSplitter the split strategy to set - */ - public void setNodeSplitStrategy(SplitStrategy nodeSplitter) { - if(nodeSplitter != null) { - this.nodeSplitter = nodeSplitter; - } - else { - getLogger().warning("Ignoring setNodeSplitStrategy(null)"); - } - } - - /** - * Set insertion strategy. - * - * @param insertionStrategy the insertion strategy to set - */ - public void setInsertionStrategy(InsertionStrategy insertionStrategy) { - if(insertionStrategy != null) { - this.insertionStrategy = insertionStrategy; - } - else { - getLogger().warning("Ignoring setInsertionStrategy(null)"); - } - } - - /** - * Set the overflow treatment strategy. - * - * @param overflowTreatment overflow treatment strategy - */ - public void setOverflowTreatment(OverflowTreatment overflowTreatment) { - this.overflowTreatment = overflowTreatment; - } - - /** - * Set the relative minimum fill. (Only supported before the tree was used!) - * - * @param relative Relative minimum fill - */ - public void setMinimumFill(double relative) { - this.relativeMinFill = relative; + this.settings = settings; } /** @@ -198,20 +118,20 @@ public abstract class AbstractRStarTree<N extends AbstractRStarTreeNode<N, E>, E */ protected IndexTreePath<E> findPathToObject(IndexTreePath<E> subtree, SpatialComparable mbr, DBIDRef id) { N node = getNode(subtree.getLastPathComponent().getEntry()); - if(node.isLeaf()) { - for(int i = 0; i < node.getNumEntries(); i++) { - if(DBIDUtil.equal(((LeafEntry) node.getEntry(i)).getDBID(), id)) { - return subtree.pathByAddingChild(new TreeIndexPathComponent<E>(node.getEntry(i), i)); + if (node.isLeaf()) { + for (int i = 0; i < node.getNumEntries(); i++) { + if (DBIDUtil.equal(((LeafEntry) node.getEntry(i)).getDBID(), id)) { + return subtree.pathByAddingChild(new TreeIndexPathComponent<>(node.getEntry(i), i)); } } } // directory node else { - for(int i = 0; i < node.getNumEntries(); i++) { - if(SpatialUtil.intersects(node.getEntry(i), mbr)) { - IndexTreePath<E> childSubtree = subtree.pathByAddingChild(new TreeIndexPathComponent<E>(node.getEntry(i), i)); + for (int i = 0; i < node.getNumEntries(); i++) { + if (SpatialUtil.intersects(node.getEntry(i), mbr)) { + IndexTreePath<E> childSubtree = subtree.pathByAddingChild(new TreeIndexPathComponent<>(node.getEntry(i), i)); IndexTreePath<E> path = findPathToObject(childSubtree, mbr, id); - if(path != null) { + if (path != null) { return path; } } @@ -222,10 +142,10 @@ public abstract class AbstractRStarTree<N extends AbstractRStarTreeNode<N, E>, E @Override public void insertLeaf(E leaf) { - if(!initialized) { + if (!initialized) { initialize(leaf); } - overflowTreatment.reinitialize(); + settings.getOverflowTreatment().reinitialize(); preInsert(leaf); insertLeafEntry(leaf); @@ -243,7 +163,7 @@ public abstract class AbstractRStarTree<N extends AbstractRStarTreeNode<N, E>, E // choose subtree for insertion IndexTreePath<E> subtree = choosePath(getRootPath(), entry, 1); - if(getLogger().isDebugging()) { + if (getLogger().isDebugging()) { getLogger().debugFine("insertion-subtree " + subtree); } @@ -266,7 +186,7 @@ public abstract class AbstractRStarTree<N extends AbstractRStarTreeNode<N, E>, E lastInsertedEntry = entry; // choose node for insertion of o IndexTreePath<E> subtree = choosePath(getRootPath(), entry, level); - if(getLogger().isDebugging()) { + if (getLogger().isDebugging()) { getLogger().debugFine("subtree " + subtree); } @@ -293,20 +213,19 @@ public abstract class AbstractRStarTree<N extends AbstractRStarTreeNode<N, E>, E writeNode(leaf); // condense the tree - Stack<N> stack = new Stack<N>(); + Stack<N> stack = new Stack<>(); condenseTree(deletionPath.getParentPath(), stack); // reinsert underflow nodes - while(!stack.empty()) { + while (!stack.empty()) { N node = stack.pop(); - if(node.isLeaf()) { - for(int i = 0; i < node.getNumEntries(); i++) { - overflowTreatment.reinitialize(); // Intended? + if (node.isLeaf()) { + for (int i = 0; i < node.getNumEntries(); i++) { + settings.getOverflowTreatment().reinitialize(); // Intended? this.insertLeafEntry(node.getEntry(i)); } - } - else { - for(int i = 0; i < node.getNumEntries(); i++) { + } else { + for (int i = 0; i < node.getNumEntries(); i++) { stack.push(getNode(node.getEntry(i))); } } @@ -328,7 +247,7 @@ public abstract class AbstractRStarTree<N extends AbstractRStarTreeNode<N, E>, E // compute height this.height = computeHeight(); - if(getLogger().isDebugging()) { + if (getLogger().isDebugging()) { StringBuilder msg = new StringBuilder(); msg.append(getClass()); msg.append("\n height = ").append(height); @@ -344,15 +263,14 @@ public abstract class AbstractRStarTree<N extends AbstractRStarTreeNode<N, E>, E ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); SpatialPointLeafEntry sl = new SpatialPointLeafEntry(DBIDUtil.importInteger(0), new double[exampleLeaf.getDimensionality()]); - while(baos.size() <= getPageSize()) { + while (baos.size() <= getPageSize()) { sl.writeExternal(oos); oos.flush(); cap++; } // the last one caused the page to overflow. leafCapacity = cap - 1; - } - catch(IOException e) { + } catch (IOException e) { throw new AbortException("Error determining page sizes.", e); } @@ -363,47 +281,43 @@ public abstract class AbstractRStarTree<N extends AbstractRStarTreeNode<N, E>, E ObjectOutputStream oos = new ObjectOutputStream(baos); ModifiableHyperBoundingBox hb = new ModifiableHyperBoundingBox(new double[exampleLeaf.getDimensionality()], new double[exampleLeaf.getDimensionality()]); SpatialDirectoryEntry sl = new SpatialDirectoryEntry(0, hb); - while(baos.size() <= getPageSize()) { + while (baos.size() <= getPageSize()) { sl.writeExternal(oos); oos.flush(); cap++; } dirCapacity = cap - 1; - } - catch(IOException e) { + } catch (IOException e) { throw new AbortException("Error determining page sizes.", e); } - if(dirCapacity <= 1) { - throw new IllegalArgumentException("Node size of " + getPageSize() + " Bytes is chosen too small!"); + if (dirCapacity <= 2) { + throw new IllegalArgumentException("Node size of " + getPageSize() + " bytes is chosen too small!"); } - if(dirCapacity < 10) { - getLogger().warning("Page size is choosen very small! Maximum number of entries " + "in a directory node = " + (dirCapacity - 1)); + final Logging log = getLogger(); + if (dirCapacity < 10) { + log.warning("Page size is choosen very small! Maximum number of entries in a directory node = " + dirCapacity); } // minimum entries per directory node - dirMinimum = (int) Math.round((dirCapacity - 1) * relativeMinFill); - if(dirMinimum < 2) { - dirMinimum = 2; + dirMinimum = (int) Math.floor(dirCapacity * settings.relativeMinFill); + if (dirMinimum < 1) { + dirMinimum = 1; } - if(leafCapacity <= 1) { - throw new IllegalArgumentException("Node size of " + getPageSize() + " Bytes is chosen too small!"); + if (leafCapacity <= 2) { + throw new IllegalArgumentException("Node size of " + getPageSize() + " bytes is chosen too small!"); } - if(leafCapacity < 10) { - getLogger().warning("Page size is choosen very small! Maximum number of entries " + "in a leaf node = " + (leafCapacity - 1)); + if (leafCapacity < 10) { + log.warning("Page size is choosen very small! Maximum number of entries in a leaf node = " + leafCapacity); } // minimum entries per leaf node - leafMinimum = (int) Math.round((leafCapacity - 1) * relativeMinFill); - if(leafMinimum < 2) { - leafMinimum = 2; - } - - if(getLogger().isVerbose()) { - getLogger().verbose("Directory Capacity: " + (dirCapacity - 1) + "\nDirectory minimum: " + dirMinimum + "\nLeaf Capacity: " + (leafCapacity - 1) + "\nLeaf Minimum: " + leafMinimum); + leafMinimum = (int) Math.floor(leafCapacity * settings.relativeMinFill); + if (leafMinimum < 1) { + leafMinimum = 1; } } @@ -413,7 +327,7 @@ public abstract class AbstractRStarTree<N extends AbstractRStarTreeNode<N, E>, E * @return Success code */ public boolean canBulkLoad() { - return (bulkSplitter != null && !initialized); + return (settings.bulkSplitter != null && !initialized); } /** @@ -424,17 +338,17 @@ public abstract class AbstractRStarTree<N extends AbstractRStarTreeNode<N, E>, E */ protected List<E> createBulkLeafNodes(List<E> objects) { int minEntries = leafMinimum; - int maxEntries = leafCapacity - 1; + int maxEntries = leafCapacity; - ArrayList<E> result = new ArrayList<E>(); - List<List<E>> partitions = bulkSplitter.partition(objects, minEntries, maxEntries); + ArrayList<E> result = new ArrayList<>(); + List<List<E>> partitions = settings.bulkSplitter.partition(objects, minEntries, maxEntries); - for(List<E> partition : partitions) { + for (List<E> partition : partitions) { // create leaf node N leafNode = createNewLeafNode(); // insert data - for(E o : partition) { + for (E o : partition) { leafNode.addLeafEntry(o); } // write to file @@ -442,12 +356,12 @@ public abstract class AbstractRStarTree<N extends AbstractRStarTreeNode<N, E>, E result.add(createNewDirectoryEntry(leafNode)); - if(getLogger().isDebugging()) { - getLogger().debugFine("Created leaf page "+leafNode.getPageID()); + if (getLogger().isDebugging()) { + getLogger().debugFine("Created leaf page " + leafNode.getPageID()); } } - if(getLogger().isDebugging()) { + if (getLogger().isDebugging()) { getLogger().debugFine("numDataPages = " + result.size()); } return result; @@ -528,8 +442,8 @@ public abstract class AbstractRStarTree<N extends AbstractRStarTreeNode<N, E>, E // switch the ids oldRoot.setPageID(root.getPageID()); - if(!oldRoot.isLeaf()) { - for(int i = 0; i < oldRoot.getNumEntries(); i++) { + if (!oldRoot.isLeaf()) { + for (int i = 0; i < oldRoot.getNumEntries(); i++) { N node = getNode(oldRoot.getEntry(i)); writeNode(node); } @@ -544,7 +458,7 @@ public abstract class AbstractRStarTree<N extends AbstractRStarTreeNode<N, E>, E writeNode(root); writeNode(oldRoot); writeNode(newNode); - if(getLogger().isDebugging()) { + if (getLogger().isDebugging()) { String msg = "Create new Root: ID=" + root.getPageID(); msg += "\nchild1 " + oldRoot + " " + new HyperBoundingBox(oldRootEntry); msg += "\nchild2 " + newNode + " " + new HyperBoundingBox(newNodeEntry); @@ -552,7 +466,7 @@ public abstract class AbstractRStarTree<N extends AbstractRStarTreeNode<N, E>, E getLogger().debugFine(msg); } - return new IndexTreePath<E>(new TreeIndexPathComponent<E>(getRootEntry(), null)); + return new IndexTreePath<>(new TreeIndexPathComponent<>(getRootEntry(), null)); } /** @@ -570,21 +484,20 @@ public abstract class AbstractRStarTree<N extends AbstractRStarTreeNode<N, E>, E int index = -1; double cEVol = Double.NaN; E ei; - for(int i = 0; i < node.getNumEntries(); i++) { + for (int i = 0; i < node.getNumEntries(); i++) { ei = node.getEntry(i); // skip test on pairwise overlaps - if(SpatialUtil.contains(ei, mbr)) { - if(containingEntry == null) { + if (SpatialUtil.contains(ei, mbr)) { + if (containingEntry == null) { containingEntry = ei; index = i; - } - else { + } else { double tempVol = SpatialUtil.volume(ei); - if(Double.isNaN(cEVol)) { // calculate volume of currently best + if (Double.isNaN(cEVol)) { // calculate volume of currently best cEVol = SpatialUtil.volume(containingEntry); } // take containing node with lowest volume - if(tempVol < cEVol) { + if (tempVol < cEVol) { cEVol = tempVol; containingEntry = ei; index = i; @@ -592,7 +505,7 @@ public abstract class AbstractRStarTree<N extends AbstractRStarTreeNode<N, E>, E } } } - return (containingEntry == null ? null : new TreeIndexPathComponent<E>(containingEntry, index)); + return (containingEntry == null ? null : new TreeIndexPathComponent<>(containingEntry, index)); } /** @@ -606,38 +519,36 @@ public abstract class AbstractRStarTree<N extends AbstractRStarTreeNode<N, E>, E * @return the path of the appropriate subtree to insert the given mbr */ protected IndexTreePath<E> choosePath(IndexTreePath<E> subtree, SpatialComparable mbr, int level) { - if(getLogger().isDebuggingFiner()) { + if (getLogger().isDebuggingFiner()) { getLogger().debugFiner("node " + subtree + ", level " + level); } N node = getNode(subtree.getLastPathComponent().getEntry()); - if(node == null) { + if (node == null) { throw new RuntimeException("Page file did not return node for node id: " + getPageID(subtree.getLastPathComponent().getEntry())); } - if(node.isLeaf()) { + if (node.isLeaf()) { return subtree; } // first test on containment TreeIndexPathComponent<E> containingEntry = containedTest(node, mbr); - if(containingEntry != null) { + if (containingEntry != null) { IndexTreePath<E> newSubtree = subtree.pathByAddingChild(containingEntry); - if(height - subtree.getPathCount() == level) { + if (height - subtree.getPathCount() == level) { return newSubtree; - } - else { + } else { return choosePath(newSubtree, mbr, level); } } N childNode = getNode(node.getEntry(0)); - int num = insertionStrategy.choose(node, NodeArrayAdapter.STATIC, mbr, height, subtree.getPathCount()); - TreeIndexPathComponent<E> comp = new TreeIndexPathComponent<E>(node.getEntry(num), num); + int num = settings.insertionStrategy.choose(node, NodeArrayAdapter.STATIC, mbr, height, subtree.getPathCount()); + TreeIndexPathComponent<E> comp = new TreeIndexPathComponent<>(node.getEntry(num), num); // children are leafs - if(childNode.isLeaf()) { - if(height - subtree.getPathCount() == level) { + if (childNode.isLeaf()) { + if (height - subtree.getPathCount() == level) { return subtree.pathByAddingChild(comp); - } - else { + } else { throw new IllegalArgumentException("childNode is leaf, but currentLevel != level: " + (height - subtree.getPathCount()) + " != " + level); } } @@ -645,10 +556,9 @@ public abstract class AbstractRStarTree<N extends AbstractRStarTreeNode<N, E>, E else { IndexTreePath<E> newSubtree = subtree.pathByAddingChild(comp); // desired level is reached - if(height - subtree.getPathCount() == level) { + if (height - subtree.getPathCount() == level) { return newSubtree; - } - else { + } else { return choosePath(newSubtree, mbr, level); } } @@ -666,7 +576,7 @@ public abstract class AbstractRStarTree<N extends AbstractRStarTreeNode<N, E>, E * reinsertion */ private N overflowTreatment(N node, IndexTreePath<E> path) { - if(overflowTreatment.handleOverflow(this, node, path)) { + if (settings.getOverflowTreatment().handleOverflow(this, node, path)) { return null; } return split(node); @@ -681,14 +591,13 @@ public abstract class AbstractRStarTree<N extends AbstractRStarTreeNode<N, E>, E private N split(N node) { // choose the split dimension and the split point int minimum = node.isLeaf() ? leafMinimum : dirMinimum; - BitSet split = nodeSplitter.split(node, NodeArrayAdapter.STATIC, minimum); + BitSet split = settings.nodeSplitter.split(node, NodeArrayAdapter.STATIC, minimum); // New node final N newNode; - if(node.isLeaf()) { + if (node.isLeaf()) { newNode = createNewLeafNode(); - } - else { + } else { newNode = createNewDirectoryNode(); } // do the split @@ -712,8 +621,8 @@ public abstract class AbstractRStarTree<N extends AbstractRStarTreeNode<N, E>, E final int level = height - (path.getPathCount() - 1); BitSet remove = new BitSet(); - List<E> reInsertEntries = new ArrayList<E>(offs.length); - for(int i = 0; i < offs.length; i++) { + List<E> reInsertEntries = new ArrayList<>(offs.length); + for (int i = 0; i < offs.length; i++) { reInsertEntries.add(node.getEntry(offs[i])); remove.set(offs[i]); } @@ -724,30 +633,28 @@ public abstract class AbstractRStarTree<N extends AbstractRStarTreeNode<N, E>, E // and adapt the mbrs IndexTreePath<E> childPath = path; N child = node; - while(childPath.getParentPath() != null) { + while (childPath.getParentPath() != null) { N parent = getNode(childPath.getParentPath().getLastPathComponent().getEntry()); int indexOfChild = childPath.getLastPathComponent().getIndex(); - if(child.adjustEntry(parent.getEntry(indexOfChild))) { + if (child.adjustEntry(parent.getEntry(indexOfChild))) { writeNode(parent); childPath = childPath.getParentPath(); child = parent; - } - else { + } else { break; // TODO: stop writing when MBR didn't change! } } // reinsert the first entries - for(E entry : reInsertEntries) { - if(node.isLeaf()) { - if(getLogger().isDebugging()) { + for (E entry : reInsertEntries) { + if (node.isLeaf()) { + if (getLogger().isDebugging()) { getLogger().debug("reinsert " + entry); } insertLeafEntry(entry); - } - else { - if(getLogger().isDebugging()) { + } else { + if (getLogger().isDebugging()) { getLogger().debug("reinsert " + entry + " at " + level); } insertDirectoryEntry(entry, level); @@ -761,7 +668,7 @@ public abstract class AbstractRStarTree<N extends AbstractRStarTreeNode<N, E>, E * @param subtree the subtree to be adjusted */ protected void adjustTree(IndexTreePath<E> subtree) { - if(getLogger().isDebugging()) { + if (getLogger().isDebugging()) { getLogger().debugFine("Adjust tree " + subtree); } @@ -769,15 +676,15 @@ public abstract class AbstractRStarTree<N extends AbstractRStarTreeNode<N, E>, E N node = getNode(subtree.getLastPathComponent().getEntry()); // overflow in node - if(hasOverflow(node)) { + if (hasOverflow(node)) { // treatment of overflow: reinsertion or split N split = overflowTreatment(node, subtree); // node was split - if(split != null) { + if (split != null) { // if root was split: create a new root that points the two // split nodes - if(isRoot(node)) { + if (isRoot(node)) { IndexTreePath<E> newRootPath = createNewRoot(node, split); height++; adjustTree(newRootPath); @@ -786,7 +693,7 @@ public abstract class AbstractRStarTree<N extends AbstractRStarTreeNode<N, E>, E else { // get the parent and add the new split node N parent = getNode(subtree.getParentPath().getLastPathComponent().getEntry()); - if(getLogger().isDebugging()) { + if (getLogger().isDebugging()) { getLogger().debugFine("parent " + parent); } parent.addDirectoryEntry(createNewDirectoryEntry(split)); @@ -807,11 +714,11 @@ public abstract class AbstractRStarTree<N extends AbstractRStarTreeNode<N, E>, E // no overflow, only adjust parameters of the entry representing the // node else { - if(!isRoot(node)) { + if (!isRoot(node)) { N parent = getNode(subtree.getParentPath().getLastPathComponent().getEntry()); E entry = parent.getEntry(subtree.getLastPathComponent().getIndex()); boolean changed = node.adjustEntryIncremental(entry, lastInsertedEntry); - if(changed) { + if (changed) { // node.adjustEntry(parent.getEntry(index)); // write changes in parent to file writeNode(parent); @@ -835,18 +742,16 @@ public abstract class AbstractRStarTree<N extends AbstractRStarTreeNode<N, E>, E private void condenseTree(IndexTreePath<E> subtree, Stack<N> stack) { N node = getNode(subtree.getLastPathComponent().getEntry()); // node is not root - if(!isRoot(node)) { + if (!isRoot(node)) { N parent = getNode(subtree.getParentPath().getLastPathComponent().getEntry()); int index = subtree.getLastPathComponent().getIndex(); - if(hasUnderflow(node)) { - if(parent.deleteEntry(index)) { + if (hasUnderflow(node)) { + if (parent.deleteEntry(index)) { stack.push(node); - } - else { + } else { node.adjustEntry(parent.getEntry(index)); } - } - else { + } else { node.adjustEntry(parent.getEntry(index)); } writeNode(parent); @@ -856,20 +761,19 @@ public abstract class AbstractRStarTree<N extends AbstractRStarTreeNode<N, E>, E // node is root else { - if(hasUnderflow(node) && node.getNumEntries() == 1 && !node.isLeaf()) { + if (hasUnderflow(node) && node.getNumEntries() == 1 && !node.isLeaf()) { N child = getNode(node.getEntry(0)); N newRoot; - if(child.isLeaf()) { + if (child.isLeaf()) { newRoot = createNewLeafNode(); newRoot.setPageID(getRootID()); - for(int i = 0; i < child.getNumEntries(); i++) { + for (int i = 0; i < child.getNumEntries(); i++) { newRoot.addLeafEntry(child.getEntry(i)); } - } - else { + } else { newRoot = createNewDirectoryNode(); newRoot.setPageID(getRootID()); - for(int i = 0; i < child.getNumEntries(); i++) { + for (int i = 0; i < child.getNumEntries(); i++) { newRoot.addDirectoryEntry(child.getEntry(i)); } } @@ -881,9 +785,9 @@ public abstract class AbstractRStarTree<N extends AbstractRStarTreeNode<N, E>, E @Override public final List<E> getLeaves() { - List<E> result = new ArrayList<E>(); + List<E> result = new ArrayList<>(); - if(height == 1) { + if (height == 1) { result.add(getRootEntry()); return result; } @@ -901,13 +805,12 @@ public abstract class AbstractRStarTree<N extends AbstractRStarTreeNode<N, E>, E */ private void getLeafNodes(N node, List<E> result, int currentLevel) { // Level 1 are the leaf nodes, Level 2 is the one atop! - if(currentLevel == 2) { - for(int i = 0; i < node.getNumEntries(); i++) { + if (currentLevel == 2) { + for (int i = 0; i < node.getNumEntries(); i++) { result.add(node.getEntry(i)); } - } - else { - for(int i = 0; i < node.getNumEntries(); i++) { + } else { + for (int i = 0; i < node.getNumEntries(); i++) { N child = getNode(node.getEntry(i)); getLeafNodes(child, result, (currentLevel - 1)); } @@ -918,11 +821,100 @@ public abstract class AbstractRStarTree<N extends AbstractRStarTreeNode<N, E>, E * Perform additional integrity checks. */ public void doExtraIntegrityChecks() { - if(EXTRA_INTEGRITY_CHECKS) { + if (EXTRA_INTEGRITY_CHECKS) { getRoot().integrityCheck(this); } } + @Override + public void logStatistics() { + super.logStatistics(); + Logging log = getLogger(); + if (log.isStatistics()) { + log.statistics(new LongStatistic(this.getClass().getName() + ".height", height)); + 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(); + final String prefix = AbstractRStarTree.this.getClass().getName(); + distanceCalcs = log.isStatistics() ? log.newCounter(prefix + ".distancecalcs") : null; + knnQueries = log.isStatistics() ? log.newCounter(prefix + ".knnqueries") : null; + rangeQueries = log.isStatistics() ? log.newCounter(prefix + ".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); + } + } + } + /** * Returns a string representation of this R*-Tree. * @@ -936,45 +928,42 @@ public abstract class AbstractRStarTree<N extends AbstractRStarTreeNode<N, E>, E int objects = 0; int levels = 0; - if(initialized) { + if (initialized) { N node = getRoot(); int dim = getRootEntry().getDimensionality(); - while(!node.isLeaf()) { - if(node.getNumEntries() > 0) { + while (!node.isLeaf()) { + if (node.getNumEntries() > 0) { E entry = node.getEntry(0); node = getNode(entry); levels++; } } - BreadthFirstEnumeration<N, E> enumeration = new BreadthFirstEnumeration<N, E>(this, getRootPath()); - while(enumeration.hasMoreElements()) { + BreadthFirstEnumeration<N, E> enumeration = new BreadthFirstEnumeration<>(this, getRootPath()); + while (enumeration.hasMoreElements()) { IndexTreePath<E> indexPath = enumeration.nextElement(); E entry = indexPath.getLastPathComponent().getEntry(); - if(entry.isLeafEntry()) { + if (entry.isLeafEntry()) { objects++; - } - else { + } else { node = getNode(entry); - if(node.isLeaf()) { + if (node.isLeaf()) { leafNodes++; - } - else { + } else { dirNodes++; } } } result.append(getClass().getName()).append(" has ").append((levels + 1)).append(" levels.\n"); - result.append(dirNodes).append(" Directory Knoten (max = ").append(dirCapacity - 1).append(", min = ").append(dirMinimum).append(")\n"); - result.append(leafNodes).append(" Daten Knoten (max = ").append(leafCapacity - 1).append(", min = ").append(leafMinimum).append(")\n"); + result.append(dirNodes).append(" Directory Knoten (max = ").append(dirCapacity).append(", min = ").append(dirMinimum).append(")\n"); + result.append(leafNodes).append(" Daten Knoten (max = ").append(leafCapacity).append(", min = ").append(leafMinimum).append(")\n"); result.append(objects).append(' ').append(dim).append("-dim. Punkte im Baum \n"); - PageFileUtil.appendPageFileStatistics(result, getPageFileStatistics()); - } - else { + // PageFileUtil.appendPageFileStatistics(result, getPageFileStatistics()); + } else { result.append(getClass().getName()).append(" is empty!\n"); } return result.toString(); } -}
\ No newline at end of file +} diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/AbstractRStarTreeFactory.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/AbstractRStarTreeFactory.java index ace5ad41..48b84302 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/AbstractRStarTreeFactory.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/AbstractRStarTreeFactory.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants; 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,7 +27,7 @@ import de.lmu.ifi.dbs.elki.data.NumberVector; import de.lmu.ifi.dbs.elki.data.type.TypeInformation; import de.lmu.ifi.dbs.elki.data.type.TypeUtil; 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.spatial.SpatialEntry; import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.bulk.BulkSplit; import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.insert.CombinedInsertionStrategy; @@ -36,6 +36,7 @@ import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.overflow. import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.overflow.OverflowTreatment; import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.split.SplitStrategy; import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.split.TopologicalSplitter; +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.constraints.LessConstraint; @@ -56,76 +57,21 @@ import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.ObjectParameter; * @param <E> Entry type * @param <I> Index type */ -public abstract class AbstractRStarTreeFactory<O extends NumberVector<?>, N extends AbstractRStarTreeNode<N, E>, E extends SpatialEntry, I extends AbstractRStarTree<N, E> & Index> extends TreeIndexFactory<O, I> { +public abstract class AbstractRStarTreeFactory<O extends NumberVector<?>, N extends AbstractRStarTreeNode<N, E>, E extends SpatialEntry, I extends AbstractRStarTree<N, E, S> & Index, S extends AbstractRTreeSettings> extends PagedIndexFactory<O, I> { /** - * Fast-insertion parameter. Optional. + * Tree settings */ - public static OptionID INSERTION_STRATEGY_ID = new OptionID("rtree.insertionstrategy", "The strategy to use for object insertion."); - - /** - * Split strategy parameter. Optional. - */ - public static OptionID SPLIT_STRATEGY_ID = new OptionID("rtree.splitstrategy", "The strategy to use for node splitting."); - - /** - * Parameter for bulk strategy - */ - public static final OptionID BULK_SPLIT_ID = new OptionID("spatial.bulkstrategy", "The class to perform the bulk split with."); - - /** - * Parameter for the relative minimum fill. - */ - public static final OptionID MINIMUM_FILL_ID = new OptionID("rtree.minimum-fill", "Minimum relative fill required for data pages."); - - /** - * Overflow treatment. - */ - public static OptionID OVERFLOW_STRATEGY_ID = new OptionID("rtree.overflowtreatment", "The strategy to use for handling overflows."); - - /** - * Strategy to find the insertion node with. - */ - protected InsertionStrategy insertionStrategy; - - /** - * The strategy for bulk load. - */ - protected BulkSplit bulkSplitter; - - /** - * The strategy for splitting nodes - */ - protected SplitStrategy nodeSplitter; - - /** - * Overflow treatment strategy - */ - protected OverflowTreatment overflowTreatment; - - /** - * Relative minimum fill - */ - protected double minimumFill; + protected S settings; /** * Constructor. * - * @param fileName - * @param pageSize - * @param cacheSize - * @param bulkSplitter the strategy to use for bulk splitting - * @param insertionStrategy the strategy to find the insertion child - * @param nodeSplitter the strategy to use for splitting nodes - * @param overflowTreatment the strategy to use for overflow treatment - * @param minimumFill the relative minimum fill + * @param pageFileFactory Page file factory + * @param settings Tree settings */ - public AbstractRStarTreeFactory(String fileName, int pageSize, long cacheSize, BulkSplit bulkSplitter, InsertionStrategy insertionStrategy, SplitStrategy nodeSplitter, OverflowTreatment overflowTreatment, double minimumFill) { - super(fileName, pageSize, cacheSize); - this.insertionStrategy = insertionStrategy; - this.bulkSplitter = bulkSplitter; - this.nodeSplitter = nodeSplitter; - this.overflowTreatment = overflowTreatment; - this.minimumFill = minimumFill; + public AbstractRStarTreeFactory(PageFileFactory<?> pageFileFactory, S settings) { + super(pageFileFactory); + this.settings = settings; } @Override @@ -139,53 +85,69 @@ public abstract class AbstractRStarTreeFactory<O extends NumberVector<?>, N exte * @author Erich Schubert * * @apiviz.exclude + * + * @param <O> Object type + * @param <S> Settings class */ - public abstract static class Parameterizer<O extends NumberVector<?>> extends TreeIndexFactory.Parameterizer<O> { + public abstract static class Parameterizer<O extends NumberVector<?>, S extends AbstractRTreeSettings> extends PagedIndexFactory.Parameterizer<O> { + /** + * Fast-insertion parameter. Optional. + */ + public static OptionID INSERTION_STRATEGY_ID = new OptionID("rtree.insertionstrategy", "The strategy to use for object insertion."); + /** - * Insertion strategy + * Split strategy parameter. Optional. */ - protected InsertionStrategy insertionStrategy = null; + public static OptionID SPLIT_STRATEGY_ID = new OptionID("rtree.splitstrategy", "The strategy to use for node splitting."); /** - * The strategy for splitting nodes + * Parameter for bulk strategy */ - protected SplitStrategy nodeSplitter = null; + public static final OptionID BULK_SPLIT_ID = new OptionID("spatial.bulkstrategy", "The class to perform the bulk split with."); /** - * Bulk loading strategy + * Parameter for the relative minimum fill. */ - protected BulkSplit bulkSplitter = null; + public static final OptionID MINIMUM_FILL_ID = new OptionID("rtree.minimum-fill", "Minimum relative fill required for data pages."); /** - * Overflow treatment strategy + * Overflow treatment. */ - protected OverflowTreatment overflowTreatment = null; + public static OptionID OVERFLOW_STRATEGY_ID = new OptionID("rtree.overflowtreatment", "The strategy to use for handling overflows."); /** - * Relative minimum fill + * Tree settings + */ + protected S settings; + + /** + * Create the settings object + * + * @return Settings instance. */ - protected double minimumFill; + abstract protected S createSettings(); @Override protected void makeOptions(Parameterization config) { super.makeOptions(config); - ObjectParameter<InsertionStrategy> insertionStrategyP = new ObjectParameter<InsertionStrategy>(INSERTION_STRATEGY_ID, InsertionStrategy.class, CombinedInsertionStrategy.class); + settings = createSettings(); + ObjectParameter<InsertionStrategy> insertionStrategyP = new ObjectParameter<>(INSERTION_STRATEGY_ID, InsertionStrategy.class, CombinedInsertionStrategy.class); if (config.grab(insertionStrategyP)) { - insertionStrategy = insertionStrategyP.instantiateClass(config); + settings.insertionStrategy = insertionStrategyP.instantiateClass(config); } - ObjectParameter<SplitStrategy> splitStrategyP = new ObjectParameter<SplitStrategy>(SPLIT_STRATEGY_ID, SplitStrategy.class, TopologicalSplitter.class); + ObjectParameter<SplitStrategy> splitStrategyP = new ObjectParameter<>(SPLIT_STRATEGY_ID, SplitStrategy.class, TopologicalSplitter.class); if (config.grab(splitStrategyP)) { - nodeSplitter = splitStrategyP.instantiateClass(config); + settings.nodeSplitter = splitStrategyP.instantiateClass(config); } DoubleParameter minimumFillP = new DoubleParameter(MINIMUM_FILL_ID, 0.4); minimumFillP.addConstraint(new GreaterConstraint(0.0)); minimumFillP.addConstraint(new LessConstraint(0.5)); if (config.grab(minimumFillP)) { - minimumFill = minimumFillP.getValue(); + settings.relativeMinFill = minimumFillP.getValue(); } - ObjectParameter<OverflowTreatment> overflowP = new ObjectParameter<OverflowTreatment>(OVERFLOW_STRATEGY_ID, OverflowTreatment.class, LimitedReinsertOverflowTreatment.class); + ObjectParameter<OverflowTreatment> overflowP = new ObjectParameter<>(OVERFLOW_STRATEGY_ID, OverflowTreatment.class, LimitedReinsertOverflowTreatment.class); if (config.grab(overflowP)) { - overflowTreatment = overflowP.instantiateClass(config); + settings.setOverflowTreatment(overflowP.instantiateClass(config)); } configBulkLoad(config); } @@ -196,13 +158,13 @@ public abstract class AbstractRStarTreeFactory<O extends NumberVector<?>, N exte * @param config Parameterization */ protected void configBulkLoad(Parameterization config) { - ObjectParameter<BulkSplit> bulkSplitP = new ObjectParameter<BulkSplit>(BULK_SPLIT_ID, BulkSplit.class, true); + ObjectParameter<BulkSplit> bulkSplitP = new ObjectParameter<>(BULK_SPLIT_ID, BulkSplit.class, true); if (config.grab(bulkSplitP)) { - bulkSplitter = bulkSplitP.instantiateClass(config); + settings.bulkSplitter = bulkSplitP.instantiateClass(config); } } @Override - protected abstract AbstractRStarTreeFactory<O, ?, ?, ?> makeInstance(); + protected abstract AbstractRStarTreeFactory<O, ?, ?, ?, ?> makeInstance(); } } diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/AbstractRStarTreeNode.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/AbstractRStarTreeNode.java index 80666ebb..6b5fc2f0 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/AbstractRStarTreeNode.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/AbstractRStarTreeNode.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants; 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 @@ -133,7 +133,7 @@ public abstract class AbstractRStarTreeNode<N extends AbstractRStarTreeNode<N, E * Tests this node (for debugging purposes). */ @SuppressWarnings("unchecked") - public final void integrityCheck(AbstractRStarTree<N, E> tree) { + public final void integrityCheck(AbstractRStarTree<N, E, ?> tree) { // leaf node if(isLeaf()) { for(int i = 0; i < getCapacity(); i++) { diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/AbstractRTreeSettings.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/AbstractRTreeSettings.java new file mode 100644 index 00000000..f876be13 --- /dev/null +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/AbstractRTreeSettings.java @@ -0,0 +1,121 @@ +package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants; + +import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.bulk.BulkSplit; +import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.insert.InsertionStrategy; +import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.insert.LeastOverlapInsertionStrategy; +import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.overflow.LimitedReinsertOverflowTreatment; +import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.overflow.OverflowTreatment; +import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.split.SplitStrategy; +import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.split.TopologicalSplitter; + +/* + 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/>. + */ + +/** + * Class to wrap common Rtree settings. + * + * @author Erich Schubert + * + * @apiviz.composedOf BulkSplit + * @apiviz.composedOf SplitStrategy + * @apiviz.composedOf InsertionStrategy + * @apiviz.composedOf OverflowTreatment + */ +public class AbstractRTreeSettings { + /** + * The strategy for bulk load. + */ + protected BulkSplit bulkSplitter = null; + + /** + * The split strategy. + */ + protected SplitStrategy nodeSplitter = TopologicalSplitter.STATIC; + + /** + * The insertion strategy to use. + */ + protected InsertionStrategy insertionStrategy = LeastOverlapInsertionStrategy.STATIC; + + /** + * Overflow treatment. + */ + private OverflowTreatment overflowTreatment = LimitedReinsertOverflowTreatment.RSTAR_OVERFLOW; + + /** + * Relative minimum fill. + */ + protected double relativeMinFill = 0.4; + + /** + * Set the bulk loading strategy. + * + * @param bulkSplitter Bulk loading strategy + */ + public void setBulkStrategy(BulkSplit bulkSplitter) { + this.bulkSplitter = bulkSplitter; + } + + /** + * Set the node splitting strategy. + * + * @param nodeSplitter the split strategy to set + */ + public void setNodeSplitStrategy(SplitStrategy nodeSplitter) { + this.nodeSplitter = nodeSplitter; + } + + /** + * Set insertion strategy. + * + * @param insertionStrategy the insertion strategy to set + */ + public void setInsertionStrategy(InsertionStrategy insertionStrategy) { + this.insertionStrategy = insertionStrategy; + } + + /** + * Set the overflow treatment strategy. + * + * @param overflowTreatment overflow treatment strategy + */ + public void setOverflowTreatment(OverflowTreatment overflowTreatment) { + this.overflowTreatment = overflowTreatment; + } + + /** + * Set the relative minimum fill. (Only supported before the tree was used!) + * + * @param relative Relative minimum fill + */ + public void setMinimumFill(double relative) { + this.relativeMinFill = relative; + } + + /** + * @return the overflowTreatment + */ + public OverflowTreatment getOverflowTreatment() { + return overflowTreatment; + } +} diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/NonFlatRStarTree.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/NonFlatRStarTree.java index fd7d3d8b..8a4f530f 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/NonFlatRStarTree.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/NonFlatRStarTree.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants; 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,14 +38,15 @@ import de.lmu.ifi.dbs.elki.persistent.PageFile; * @param <N> Node type * @param <E> Entry type */ -public abstract class NonFlatRStarTree<N extends AbstractRStarTreeNode<N, E>, E extends SpatialEntry> extends AbstractRStarTree<N, E> { +public abstract class NonFlatRStarTree<N extends AbstractRStarTreeNode<N, E>, E extends SpatialEntry, S extends AbstractRTreeSettings> extends AbstractRStarTree<N, E, S> { /** * Constructor. * * @param pagefile Page file + * @param settings Settings */ - public NonFlatRStarTree(PageFile<N> pagefile) { - super(pagefile); + public NonFlatRStarTree(PageFile<N> pagefile, S settings) { + super(pagefile, settings); } /** @@ -180,8 +181,8 @@ public abstract class NonFlatRStarTree<N extends AbstractRStarTreeNode<N, E>, E int minEntries = dirMinimum; int maxEntries = dirCapacity - 1; - ArrayList<E> result = new ArrayList<E>(); - List<List<E>> partitions = bulkSplitter.partition(nodes, minEntries, maxEntries); + ArrayList<E> result = new ArrayList<>(); + List<List<E>> partitions = settings.bulkSplitter.partition(nodes, minEntries, maxEntries); for(List<E> partition : partitions) { // create node diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/deliclu/DeLiCluDirectoryEntry.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/deliclu/DeLiCluDirectoryEntry.java index 10f25ec0..510120c9 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/deliclu/DeLiCluDirectoryEntry.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/deliclu/DeLiCluDirectoryEntry.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.deliclu; 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/spatial/rstarvariants/deliclu/DeLiCluEntry.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/deliclu/DeLiCluEntry.java index 8b279268..f72b7d8d 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/deliclu/DeLiCluEntry.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/deliclu/DeLiCluEntry.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.deliclu; 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/spatial/rstarvariants/deliclu/DeLiCluLeafEntry.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/deliclu/DeLiCluLeafEntry.java index bc701185..741ab840 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/deliclu/DeLiCluLeafEntry.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/deliclu/DeLiCluLeafEntry.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.deliclu; 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/spatial/rstarvariants/deliclu/DeLiCluNode.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/deliclu/DeLiCluNode.java index bf993c01..7b3221c3 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/deliclu/DeLiCluNode.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/deliclu/DeLiCluNode.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.deliclu; 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/spatial/rstarvariants/deliclu/DeLiCluTree.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/deliclu/DeLiCluTree.java index 0cd74a14..33366763 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/deliclu/DeLiCluTree.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/deliclu/DeLiCluTree.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.deliclu; 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,19 +23,19 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.deliclu; along with this program. If not, see <http://www.gnu.org/licenses/>. */ -import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; - +import gnu.trove.map.hash.TIntObjectHashMap; +import gnu.trove.set.TIntSet; +import gnu.trove.set.hash.TIntHashSet; import de.lmu.ifi.dbs.elki.index.tree.BreadthFirstEnumeration; import de.lmu.ifi.dbs.elki.index.tree.Entry; import de.lmu.ifi.dbs.elki.index.tree.spatial.SpatialEntry; +import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.AbstractRTreeSettings; import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.NonFlatRStarTree; import de.lmu.ifi.dbs.elki.logging.Logging; import de.lmu.ifi.dbs.elki.persistent.PageFile; /** - * DeLiCluTree is a spatial index structure based on an R-TRee. DeLiCluTree is + * DeLiCluTree is a spatial index structure based on an R-Tree. DeLiCluTree is * designed for the DeLiClu algorithm, having in each node a boolean array which * indicates whether the child nodes are already handled by the DeLiClu * algorithm. @@ -44,7 +44,7 @@ import de.lmu.ifi.dbs.elki.persistent.PageFile; * * @apiviz.has DeLiCluNode oneway - - contains */ -public class DeLiCluTree extends NonFlatRStarTree<DeLiCluNode, DeLiCluEntry> { +public class DeLiCluTree extends NonFlatRStarTree<DeLiCluNode, DeLiCluEntry, AbstractRTreeSettings> { /** * The logger for this class. */ @@ -53,15 +53,16 @@ public class DeLiCluTree extends NonFlatRStarTree<DeLiCluNode, DeLiCluEntry> { /** * Holds the ids of the expanded nodes. */ - private HashMap<Integer, HashSet<Integer>> expanded = new HashMap<Integer, HashSet<Integer>>(); + private TIntObjectHashMap<TIntHashSet> expanded = new TIntObjectHashMap<>(); /** * Constructor. * * @param pagefile Page file + * @param settings Settings */ - public DeLiCluTree(PageFile<DeLiCluNode> pagefile) { - super(pagefile); + public DeLiCluTree(PageFile<DeLiCluNode> pagefile, AbstractRTreeSettings settings) { + super(pagefile, settings); } /** @@ -71,9 +72,9 @@ public class DeLiCluTree extends NonFlatRStarTree<DeLiCluNode, DeLiCluEntry> { * @param entry2 the second node */ public void setExpanded(SpatialEntry entry1, SpatialEntry entry2) { - HashSet<Integer> exp1 = expanded.get(getPageID(entry1)); + TIntHashSet exp1 = expanded.get(getPageID(entry1)); if(exp1 == null) { - exp1 = new HashSet<Integer>(); + exp1 = new TIntHashSet(); expanded.put(getPageID(entry1), exp1); } exp1.add(getPageID(entry2)); @@ -85,12 +86,12 @@ public class DeLiCluTree extends NonFlatRStarTree<DeLiCluNode, DeLiCluEntry> { * @param entry the id of the node for which the expansions should be returned * @return the nodes which are already expanded with the specified node */ - public Set<Integer> getExpanded(SpatialEntry entry) { - HashSet<Integer> exp = expanded.get(getPageID(entry)); + public TIntSet getExpanded(SpatialEntry entry) { + TIntHashSet exp = expanded.get(getPageID(entry)); if(exp != null) { return exp; } - return new HashSet<Integer>(); + return new TIntHashSet(); } /** @@ -99,12 +100,12 @@ public class DeLiCluTree extends NonFlatRStarTree<DeLiCluNode, DeLiCluEntry> { * @param entry the id of the node for which the expansions should be returned * @return the nodes which are already expanded with the specified node */ - public Set<Integer> getExpanded(DeLiCluNode entry) { - HashSet<Integer> exp = expanded.get(entry.getPageID()); + public TIntSet getExpanded(DeLiCluNode entry) { + TIntHashSet exp = expanded.get(entry.getPageID()); if(exp != null) { return exp; } - return new HashSet<Integer>(); + return new TIntHashSet(); } /** @@ -115,7 +116,7 @@ public class DeLiCluTree extends NonFlatRStarTree<DeLiCluNode, DeLiCluEntry> { public int numNodes() { int numNodes = 0; - BreadthFirstEnumeration<DeLiCluNode, DeLiCluEntry> bfs = new BreadthFirstEnumeration<DeLiCluNode, DeLiCluEntry>(this, getRootPath()); + BreadthFirstEnumeration<DeLiCluNode, DeLiCluEntry> bfs = new BreadthFirstEnumeration<>(this, getRootPath()); while(bfs.hasMoreElements()) { Entry entry = bfs.nextElement().getLastPathComponent().getEntry(); if(!entry.isLeafEntry()) { @@ -170,4 +171,4 @@ public class DeLiCluTree extends NonFlatRStarTree<DeLiCluNode, DeLiCluEntry> { protected Logging getLogger() { return LOG; } -}
\ No newline at end of file +} diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/deliclu/DeLiCluTreeFactory.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/deliclu/DeLiCluTreeFactory.java index b64192c1..a63b8004 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/deliclu/DeLiCluTreeFactory.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/deliclu/DeLiCluTreeFactory.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.deliclu; 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,9 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.deliclu; import de.lmu.ifi.dbs.elki.data.NumberVector; import de.lmu.ifi.dbs.elki.database.relation.Relation; import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.AbstractRStarTreeFactory; -import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.bulk.BulkSplit; -import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.insert.InsertionStrategy; -import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.overflow.OverflowTreatment; -import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.split.SplitStrategy; +import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.AbstractRTreeSettings; import de.lmu.ifi.dbs.elki.persistent.PageFile; +import de.lmu.ifi.dbs.elki.persistent.PageFileFactory; /** * Factory for DeLiClu R*-Trees. @@ -42,32 +40,21 @@ import de.lmu.ifi.dbs.elki.persistent.PageFile; * * @param <O> Object type */ -public class DeLiCluTreeFactory<O extends NumberVector<?>> extends AbstractRStarTreeFactory<O, DeLiCluNode, DeLiCluEntry, DeLiCluTreeIndex<O>> { +public class DeLiCluTreeFactory<O extends NumberVector<?>> extends AbstractRStarTreeFactory<O, DeLiCluNode, DeLiCluEntry, DeLiCluTreeIndex<O>, AbstractRTreeSettings> { /** * Constructor. * - * @param fileName - * @param pageSize - * @param cacheSize - * @param bulkSplitter Bulk loading strategy - * @param insertionStrategy the strategy to find the insertion child - * @param nodeSplitter the strategy for splitting nodes. - * @param overflowTreatment the strategy to use for overflow treatment - * @param minimumFill the relative minimum fill + * @param pageFileFactory Page file factory + * @param settings Settings */ - public DeLiCluTreeFactory(String fileName, int pageSize, long cacheSize, BulkSplit bulkSplitter, InsertionStrategy insertionStrategy, SplitStrategy nodeSplitter, OverflowTreatment overflowTreatment, double minimumFill) { - super(fileName, pageSize, cacheSize, bulkSplitter, insertionStrategy, nodeSplitter, overflowTreatment, minimumFill); + public DeLiCluTreeFactory(PageFileFactory<?> pageFileFactory, AbstractRTreeSettings settings) { + super(pageFileFactory, settings); } @Override public DeLiCluTreeIndex<O> instantiate(Relation<O> relation) { PageFile<DeLiCluNode> pagefile = makePageFile(getNodeClass()); - DeLiCluTreeIndex<O> index = new DeLiCluTreeIndex<O>(relation, pagefile); - index.setBulkStrategy(bulkSplitter); - index.setInsertionStrategy(insertionStrategy); - index.setNodeSplitStrategy(nodeSplitter); - index.setOverflowTreatment(overflowTreatment); - index.setMinimumFill(minimumFill); + DeLiCluTreeIndex<O> index = new DeLiCluTreeIndex<>(relation, pagefile, settings); return index; } @@ -82,10 +69,15 @@ public class DeLiCluTreeFactory<O extends NumberVector<?>> extends AbstractRStar * * @apiviz.exclude */ - public static class Parameterizer<O extends NumberVector<?>> extends AbstractRStarTreeFactory.Parameterizer<O> { + public static class Parameterizer<O extends NumberVector<?>> extends AbstractRStarTreeFactory.Parameterizer<O, AbstractRTreeSettings> { @Override protected DeLiCluTreeFactory<O> makeInstance() { - return new DeLiCluTreeFactory<O>(fileName, pageSize, cacheSize, bulkSplitter, insertionStrategy, nodeSplitter, overflowTreatment, minimumFill); + return new DeLiCluTreeFactory<>(pageFileFactory, settings); + } + + @Override + protected AbstractRTreeSettings createSettings() { + return new AbstractRTreeSettings(); } } -}
\ No newline at end of file +} diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/deliclu/DeLiCluTreeIndex.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/deliclu/DeLiCluTreeIndex.java index b1216a51..67c9c9e0 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/deliclu/DeLiCluTreeIndex.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/deliclu/DeLiCluTreeIndex.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.deliclu; 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,10 +38,12 @@ 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.distance.distancevalue.Distance; +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.IndexTreePath; import de.lmu.ifi.dbs.elki.index.tree.TreeIndexPathComponent; +import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.AbstractRTreeSettings; import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.query.RStarTreeUtil; import de.lmu.ifi.dbs.elki.logging.Logging; import de.lmu.ifi.dbs.elki.persistent.PageFile; @@ -54,7 +56,7 @@ import de.lmu.ifi.dbs.elki.utilities.exceptions.AbortException; * * @param <O> Object type */ -public class DeLiCluTreeIndex<O extends NumberVector<?>> extends DeLiCluTree implements KNNIndex<O>, RangeIndex<O> { +public class DeLiCluTreeIndex<O extends NumberVector<?>> extends DeLiCluTree implements KNNIndex<O>, RangeIndex<O>, DynamicIndex { /** * The relation we index. */ @@ -65,11 +67,11 @@ public class DeLiCluTreeIndex<O extends NumberVector<?>> extends DeLiCluTree imp * * @param relation Relation to index * @param pagefile Page file + * @param settings Tree settings */ - public DeLiCluTreeIndex(Relation<O> relation, PageFile<DeLiCluNode> pagefile) { - super(pagefile); + public DeLiCluTreeIndex(Relation<O> relation, PageFile<DeLiCluNode> pagefile, AbstractRTreeSettings settings) { + super(pagefile, settings); this.relation = relation; - this.initialize(); } /** @@ -128,6 +130,12 @@ public class DeLiCluTreeIndex<O extends NumberVector<?>> extends DeLiCluTree imp return pathToObject.getPath(); } + @Override + public void initialize() { + super.initialize(); + insertAll(relation.getDBIDs()); + } + /** * Inserts the specified real vector object into this index. * @@ -152,7 +160,7 @@ public class DeLiCluTreeIndex<O extends NumberVector<?>> extends DeLiCluTree imp // Make an example leaf if (canBulkLoad()) { - List<DeLiCluEntry> leafs = new ArrayList<DeLiCluEntry>(ids.size()); + List<DeLiCluEntry> leafs = new ArrayList<>(ids.size()); for (DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) { leafs.add(createNewLeafEntry(DBIDUtil.deref(iter))); } diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/deliclu/package-info.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/deliclu/package-info.java index b6c0af9b..f8bec8cb 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/deliclu/package-info.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/deliclu/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/spatial/rstarvariants/package-info.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/package-info.java index 2774fbe1..e50cc513 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/package-info.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/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/spatial/rstarvariants/query/DoubleDistanceRStarTreeKNNQuery.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/query/DoubleDistanceRStarTreeKNNQuery.java index 6d539f25..b7769d45 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/query/DoubleDistanceRStarTreeKNNQuery.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/query/DoubleDistanceRStarTreeKNNQuery.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.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 @@ -34,15 +34,14 @@ import de.lmu.ifi.dbs.elki.data.spatial.SpatialComparable; 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.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.ModifiableDBIDs; +import de.lmu.ifi.dbs.elki.database.ids.distance.DoubleDistanceKNNHeap; +import de.lmu.ifi.dbs.elki.database.ids.distance.DoubleDistanceKNNList; 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.SpatialPrimitiveDoubleDistanceFunction; -import de.lmu.ifi.dbs.elki.distance.distanceresultlist.DoubleDistanceKNNHeap; -import de.lmu.ifi.dbs.elki.distance.distanceresultlist.DoubleDistanceKNNList; 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.LeafEntry; @@ -50,7 +49,7 @@ import de.lmu.ifi.dbs.elki.index.tree.query.DoubleDistanceSearchCandidate; import de.lmu.ifi.dbs.elki.index.tree.spatial.SpatialEntry; import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.AbstractRStarTree; import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.AbstractRStarTreeNode; -import de.lmu.ifi.dbs.elki.utilities.datastructures.heap.Heap; +import de.lmu.ifi.dbs.elki.utilities.datastructures.heap.ComparableMinHeap; import de.lmu.ifi.dbs.elki.utilities.documentation.Reference; /** @@ -73,7 +72,7 @@ public class DoubleDistanceRStarTreeKNNQuery<O extends SpatialComparable> extend /** * The index to use */ - protected final AbstractRStarTree<?, ?> tree; + protected final AbstractRStarTree<?, ?, ?> tree; /** * Spatial primitive distance function @@ -87,7 +86,7 @@ public class DoubleDistanceRStarTreeKNNQuery<O extends SpatialComparable> extend * @param distanceQuery Distance query to use * @param distanceFunction Distance function */ - public DoubleDistanceRStarTreeKNNQuery(AbstractRStarTree<?, ?> tree, DistanceQuery<O, DoubleDistance> distanceQuery, SpatialPrimitiveDoubleDistanceFunction<? super O> distanceFunction) { + public DoubleDistanceRStarTreeKNNQuery(AbstractRStarTree<?, ?, ?> tree, DistanceQuery<O, DoubleDistance> distanceQuery, SpatialPrimitiveDoubleDistanceFunction<? super O> distanceFunction) { super(distanceQuery); this.tree = tree; this.distanceFunction = distanceFunction; @@ -102,7 +101,8 @@ public class DoubleDistanceRStarTreeKNNQuery<O extends SpatialComparable> extend * @param knnList the knn list containing the result */ protected void doKNNQuery(O object, DoubleDistanceKNNHeap knnList) { - final Heap<DoubleDistanceSearchCandidate> pq = new Heap<DoubleDistanceSearchCandidate>(Math.min(knnList.getK() << 1, 20)); + final ComparableMinHeap<DoubleDistanceSearchCandidate> pq = new ComparableMinHeap<>(Math.min(knnList.getK() << 1, 21)); + tree.statistics.countKNNQuery(); // push root pq.add(new DoubleDistanceSearchCandidate(0.0, tree.getRootID())); @@ -119,14 +119,14 @@ public class DoubleDistanceRStarTreeKNNQuery<O extends SpatialComparable> extend } } - private double expandNode(O object, DoubleDistanceKNNHeap knnList, final Heap<DoubleDistanceSearchCandidate> pq, double maxDist, final int nodeID) { + private double expandNode(O object, DoubleDistanceKNNHeap knnList, final ComparableMinHeap<DoubleDistanceSearchCandidate> pq, double maxDist, final int nodeID) { AbstractRStarTreeNode<?, ?> node = tree.getNode(nodeID); // data node if(node.isLeaf()) { for(int i = 0; i < node.getNumEntries(); i++) { SpatialEntry entry = node.getEntry(i); double distance = distanceFunction.doubleMinDist(entry, object); - tree.distanceCalcs++; + tree.statistics.countDistanceCalculation(); if(distance <= maxDist) { knnList.add(distance, ((LeafEntry) entry).getDBID()); maxDist = knnList.doubleKNNDistance(); @@ -138,7 +138,7 @@ public class DoubleDistanceRStarTreeKNNQuery<O extends SpatialComparable> extend for(int i = 0; i < node.getNumEntries(); i++) { SpatialEntry entry = node.getEntry(i); double distance = distanceFunction.doubleMinDist(entry, object); - tree.distanceCalcs++; + tree.statistics.countDistanceCalculation(); // Greedy expand, bypassing the queue if(distance <= 0) { expandNode(object, knnList, pq, maxDist, ((DirectoryEntry) entry).getPageID()); @@ -169,9 +169,10 @@ public class DoubleDistanceRStarTreeKNNQuery<O extends SpatialComparable> extend double knn_q_maxDist = knns_q.doubleKNNDistance(); DBID pid = ((LeafEntry) p).getDBID(); - // FIXME: objects are NOT accessible by DBID in a plain rtree context! + // FIXME: objects are NOT accessible by DBID in a plain R-tree + // context! double dist_pq = distanceFunction.doubleDistance(relation.get(pid), relation.get(q)); - tree.distanceCalcs++; + tree.statistics.countDistanceCalculation(); if(dist_pq <= knn_q_maxDist) { knns_q.add(dist_pq, pid); } @@ -210,14 +211,14 @@ public class DoubleDistanceRStarTreeKNNQuery<O extends SpatialComparable> extend * @return a list of the sorted entries */ protected List<DoubleDistanceEntry> getSortedEntries(AbstractRStarTreeNode<?, ?> node, DBIDs ids) { - List<DoubleDistanceEntry> result = new ArrayList<DoubleDistanceEntry>(); + List<DoubleDistanceEntry> result = new ArrayList<>(); for(int i = 0; i < node.getNumEntries(); i++) { SpatialEntry entry = node.getEntry(i); double minMinDist = Double.MAX_VALUE; - for (DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) { + for(DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) { double minDist = distanceFunction.doubleMinDist(entry, relation.get(iter)); - tree.distanceCalcs++; + tree.statistics.countDistanceCalculation(); minMinDist = Math.min(minDist, minMinDist); } result.add(new DoubleDistanceEntry(entry, minMinDist)); @@ -268,34 +269,30 @@ public class DoubleDistanceRStarTreeKNNQuery<O extends SpatialComparable> extend throw new IllegalArgumentException("At least one enumeration has to be requested!"); } - final DoubleDistanceKNNHeap knnList = new DoubleDistanceKNNHeap(k); + final DoubleDistanceKNNHeap knnList = (DoubleDistanceKNNHeap) DBIDUtil.newHeap(DoubleDistance.FACTORY, k); doKNNQuery(obj, knnList); return knnList.toKNNList(); } @Override - public DoubleDistanceKNNList getKNNForDBID(DBIDRef id, int k) { - return getKNNForObject(relation.get(id), k); - } - - @Override public List<DoubleDistanceKNNList> getKNNForBulkDBIDs(ArrayDBIDs ids, int k) { if(k < 1) { throw new IllegalArgumentException("At least one enumeration has to be requested!"); } // While this works, it seems to be slow at least for large sets! - final Map<DBID, DoubleDistanceKNNHeap> knnLists = new HashMap<DBID, DoubleDistanceKNNHeap>(ids.size()); - for (DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) { + final Map<DBID, DoubleDistanceKNNHeap> knnLists = new HashMap<>(ids.size()); + for(DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) { DBID id = DBIDUtil.deref(iter); - knnLists.put(id, new DoubleDistanceKNNHeap(k)); + knnLists.put(id, (DoubleDistanceKNNHeap) DBIDUtil.newHeap(DoubleDistance.FACTORY, k)); } batchNN(tree.getRoot(), knnLists); - List<DoubleDistanceKNNList> result = new ArrayList<DoubleDistanceKNNList>(); - for (DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) { + List<DoubleDistanceKNNList> result = new ArrayList<>(); + for(DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) { DBID id = DBIDUtil.deref(iter); + tree.statistics.countKNNQuery(); result.add(knnLists.get(id).toKNNList()); } return result; diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/query/DoubleDistanceRStarTreeRangeQuery.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/query/DoubleDistanceRStarTreeRangeQuery.java index 715b9552..eb85574f 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/query/DoubleDistanceRStarTreeRangeQuery.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/query/DoubleDistanceRStarTreeRangeQuery.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.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,19 +24,19 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.query; */ import de.lmu.ifi.dbs.elki.data.spatial.SpatialComparable; -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.DoubleDistanceDBIDList; +import de.lmu.ifi.dbs.elki.database.ids.distance.DoubleDistanceDBIDPairList; 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.SpatialPrimitiveDoubleDistanceFunction; -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.LeafEntry; import de.lmu.ifi.dbs.elki.index.tree.query.DoubleDistanceSearchCandidate; import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.AbstractRStarTree; import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.AbstractRStarTreeNode; -import de.lmu.ifi.dbs.elki.utilities.datastructures.heap.Heap; +import de.lmu.ifi.dbs.elki.utilities.datastructures.heap.ComparableMinHeap; import de.lmu.ifi.dbs.elki.utilities.documentation.Reference; /** @@ -60,7 +60,7 @@ public class DoubleDistanceRStarTreeRangeQuery<O extends SpatialComparable> exte /** * The index to use */ - protected final AbstractRStarTree<?, ?> tree; + protected final AbstractRStarTree<?, ?, ?> tree; /** * Spatial primitive distance function @@ -74,7 +74,7 @@ public class DoubleDistanceRStarTreeRangeQuery<O extends SpatialComparable> exte * @param distanceQuery Distance query to use * @param distanceFunction Distance function */ - public DoubleDistanceRStarTreeRangeQuery(AbstractRStarTree<?, ?> tree, DistanceQuery<O, DoubleDistance> distanceQuery, SpatialPrimitiveDoubleDistanceFunction<? super O> distanceFunction) { + public DoubleDistanceRStarTreeRangeQuery(AbstractRStarTree<?, ?, ?> tree, DistanceQuery<O, DoubleDistance> distanceQuery, SpatialPrimitiveDoubleDistanceFunction<? super O> distanceFunction) { super(distanceQuery); this.tree = tree; this.distanceFunction = distanceFunction; @@ -88,8 +88,9 @@ public class DoubleDistanceRStarTreeRangeQuery<O extends SpatialComparable> exte * @return Objects contained in query range. */ protected DoubleDistanceDBIDList doRangeQuery(O object, double epsilon) { - final DoubleDistanceDBIDList result = new DoubleDistanceDBIDList(); - final Heap<DoubleDistanceSearchCandidate> pq = new Heap<DoubleDistanceSearchCandidate>(); + tree.statistics.countRangeQuery(); + final DoubleDistanceDBIDPairList result = new DoubleDistanceDBIDPairList(); + final ComparableMinHeap<DoubleDistanceSearchCandidate> pq = new ComparableMinHeap<>(); // push root pq.add(new DoubleDistanceSearchCandidate(0.0, tree.getRootID())); @@ -101,12 +102,12 @@ public class DoubleDistanceRStarTreeRangeQuery<O extends SpatialComparable> exte break; } - AbstractRStarTreeNode<?, ?> node = tree.getNode(pqNode.nodeID.intValue()); + AbstractRStarTreeNode<?, ?> node = tree.getNode(pqNode.nodeID); final int numEntries = node.getNumEntries(); for(int i = 0; i < numEntries; i++) { double distance = distanceFunction.doubleMinDist(object, node.getEntry(i)); - tree.distanceCalcs++; + tree.statistics.countDistanceCalculation(); if(distance <= epsilon) { if(node.isLeaf()) { LeafEntry entry = (LeafEntry) node.getEntry(i); @@ -126,12 +127,7 @@ public class DoubleDistanceRStarTreeRangeQuery<O extends SpatialComparable> exte } @Override - public DistanceDBIDResult<DoubleDistance> getRangeForObject(O obj, DoubleDistance range) { + public DistanceDBIDList<DoubleDistance> getRangeForObject(O obj, DoubleDistance range) { return doRangeQuery(obj, range.doubleValue()); } - - @Override - public DistanceDBIDResult<DoubleDistance> getRangeForDBID(DBIDRef id, DoubleDistance range) { - return getRangeForObject(relation.get(id), range); - } }
\ No newline at end of file diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/query/GenericRStarTreeKNNQuery.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/query/GenericRStarTreeKNNQuery.java index ed7f5949..f520d52f 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/query/GenericRStarTreeKNNQuery.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/query/GenericRStarTreeKNNQuery.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.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 @@ -34,27 +34,25 @@ import de.lmu.ifi.dbs.elki.data.spatial.SpatialComparable; 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.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.ModifiableDBIDs; +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.SpatialDistanceQuery; 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.distancefunction.SpatialPrimitiveDistanceFunction; -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.index.tree.DirectoryEntry; -import de.lmu.ifi.dbs.elki.index.tree.DistanceEntry; import de.lmu.ifi.dbs.elki.index.tree.LeafEntry; import de.lmu.ifi.dbs.elki.index.tree.query.GenericDistanceSearchCandidate; import de.lmu.ifi.dbs.elki.index.tree.spatial.SpatialEntry; import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.AbstractRStarTree; import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.AbstractRStarTreeNode; -import de.lmu.ifi.dbs.elki.utilities.datastructures.heap.Heap; +import de.lmu.ifi.dbs.elki.utilities.datastructures.heap.ComparableMinHeap; import de.lmu.ifi.dbs.elki.utilities.documentation.Reference; +import de.lmu.ifi.dbs.elki.utilities.pairs.FCPair; /** * Instance of a KNN query for a particular spatial index. @@ -76,7 +74,7 @@ public class GenericRStarTreeKNNQuery<O extends SpatialComparable, D extends Dis /** * The index to use */ - protected final AbstractRStarTree<?, ?> tree; + protected final AbstractRStarTree<?, ?, ?> tree; /** * Spatial primitive distance function @@ -89,7 +87,7 @@ public class GenericRStarTreeKNNQuery<O extends SpatialComparable, D extends Dis * @param tree Index to use * @param distanceQuery Distance query to use */ - public GenericRStarTreeKNNQuery(AbstractRStarTree<?, ?> tree, SpatialDistanceQuery<O, D> distanceQuery) { + public GenericRStarTreeKNNQuery(AbstractRStarTree<?, ?, ?> tree, SpatialDistanceQuery<O, D> distanceQuery) { super(distanceQuery); this.tree = tree; this.distanceFunction = distanceQuery.getDistanceFunction(); @@ -104,32 +102,33 @@ public class GenericRStarTreeKNNQuery<O extends SpatialComparable, D extends Dis * @param knnList the knn list containing the result */ protected void doKNNQuery(O object, KNNHeap<D> knnList) { - final Heap<GenericDistanceSearchCandidate<D>> pq = new Heap<GenericDistanceSearchCandidate<D>>(Math.min(knnList.getK() << 1, 20)); + final ComparableMinHeap<GenericDistanceSearchCandidate<D>> pq = new ComparableMinHeap<>(Math.min(knnList.getK() << 1, 20)); + tree.statistics.countKNNQuery(); // push root - pq.add(new GenericDistanceSearchCandidate<D>(distanceFunction.getDistanceFactory().nullDistance(), tree.getRootID())); + pq.add(new GenericDistanceSearchCandidate<>(distanceFunction.getDistanceFactory().nullDistance(), tree.getRootID())); D maxDist = distanceFunction.getDistanceFactory().infiniteDistance(); // search in tree - while(!pq.isEmpty()) { + while (!pq.isEmpty()) { GenericDistanceSearchCandidate<D> pqNode = pq.poll(); - if(pqNode.mindist.compareTo(maxDist) > 0) { + if (pqNode.mindist.compareTo(maxDist) > 0) { return; } maxDist = expandNode(object, knnList, pq, maxDist, pqNode.nodeID); } } - private D expandNode(O object, KNNHeap<D> knnList, final Heap<GenericDistanceSearchCandidate<D>> pq, D maxDist, final int nodeID) { + private D expandNode(O object, KNNHeap<D> knnList, final ComparableMinHeap<GenericDistanceSearchCandidate<D>> pq, D maxDist, final int nodeID) { AbstractRStarTreeNode<?, ?> node = tree.getNode(nodeID); // data node - if(node.isLeaf()) { - for(int i = 0; i < node.getNumEntries(); i++) { + if (node.isLeaf()) { + for (int i = 0; i < node.getNumEntries(); i++) { SpatialEntry entry = node.getEntry(i); D distance = distanceFunction.minDist(entry, object); - tree.distanceCalcs++; - if(distance.compareTo(maxDist) <= 0) { + tree.statistics.countDistanceCalculation(); + if (distance.compareTo(maxDist) <= 0) { knnList.add(distance, ((LeafEntry) entry).getDBID()); maxDist = knnList.getKNNDistance(); } @@ -137,17 +136,16 @@ public class GenericRStarTreeKNNQuery<O extends SpatialComparable, D extends Dis } // directory node else { - for(int i = 0; i < node.getNumEntries(); i++) { + for (int i = 0; i < node.getNumEntries(); i++) { SpatialEntry entry = node.getEntry(i); D distance = distanceFunction.minDist(entry, object); - tree.distanceCalcs++; + tree.statistics.countDistanceCalculation(); // Greedy expand, bypassing the queue - if(distance.isNullDistance()) { + if (distance.isNullDistance()) { expandNode(object, knnList, pq, maxDist, ((DirectoryEntry) entry).getPageID()); - } - else { - if(distance.compareTo(maxDist) <= 0) { - pq.add(new GenericDistanceSearchCandidate<D>(distance, ((DirectoryEntry) entry).getPageID())); + } else { + if (distance.compareTo(maxDist) <= 0) { + pq.add(new GenericDistanceSearchCandidate<>(distance, ((DirectoryEntry) entry).getPageID())); } } } @@ -162,10 +160,10 @@ public class GenericRStarTreeKNNQuery<O extends SpatialComparable, D extends Dis * @param knnLists a map containing the knn lists for each query objects */ protected void batchNN(AbstractRStarTreeNode<?, ?> node, Map<DBID, KNNHeap<D>> knnLists) { - if(node.isLeaf()) { - for(int i = 0; i < node.getNumEntries(); i++) { + if (node.isLeaf()) { + for (int i = 0; i < node.getNumEntries(); i++) { SpatialEntry p = node.getEntry(i); - for(Entry<DBID, KNNHeap<D>> ent : knnLists.entrySet()) { + for (Entry<DBID, KNNHeap<D>> ent : knnLists.entrySet()) { final DBID q = ent.getKey(); final KNNHeap<D> knns_q = ent.getValue(); D knn_q_maxDist = knns_q.getKNNDistance(); @@ -173,26 +171,26 @@ public class GenericRStarTreeKNNQuery<O extends SpatialComparable, D extends Dis DBID pid = ((LeafEntry) p).getDBID(); // FIXME: objects are NOT accessible by DBID in a plain rtree context! D dist_pq = distanceQuery.distance(pid, q); - if(dist_pq.compareTo(knn_q_maxDist) <= 0) { + tree.statistics.countDistanceCalculation(); + if (dist_pq.compareTo(knn_q_maxDist) <= 0) { knns_q.add(dist_pq, pid); } } } - } - else { + } else { ModifiableDBIDs ids = DBIDUtil.newArray(knnLists.size()); - for(DBID id : knnLists.keySet()) { + for (DBID id : knnLists.keySet()) { ids.add(id); } - List<DistanceEntry<D, SpatialEntry>> entries = getSortedEntries(node, ids); - for(DistanceEntry<D, SpatialEntry> distEntry : entries) { - D minDist = distEntry.getDistance(); - for(Entry<DBID, KNNHeap<D>> ent : knnLists.entrySet()) { + List<FCPair<D, SpatialEntry>> entries = getSortedEntries(node, ids); + for (FCPair<D, SpatialEntry> distEntry : entries) { + D minDist = distEntry.first; + for (Entry<DBID, KNNHeap<D>> ent : knnLists.entrySet()) { final KNNHeap<D> knns_q = ent.getValue(); D knn_q_maxDist = knns_q.getKNNDistance(); - if(minDist.compareTo(knn_q_maxDist) <= 0) { - SpatialEntry entry = distEntry.getEntry(); + if (minDist.compareTo(knn_q_maxDist) <= 0) { + SpatialEntry entry = distEntry.second; AbstractRStarTreeNode<?, ?> child = tree.getNode(((DirectoryEntry) entry).getPageID().intValue()); batchNN(child, knnLists); break; @@ -210,17 +208,18 @@ public class GenericRStarTreeKNNQuery<O extends SpatialComparable, D extends Dis * @param ids the id of the objects * @return a list of the sorted entries */ - protected List<DistanceEntry<D, SpatialEntry>> getSortedEntries(AbstractRStarTreeNode<?, ?> node, DBIDs ids) { - List<DistanceEntry<D, SpatialEntry>> result = new ArrayList<DistanceEntry<D, SpatialEntry>>(); + protected List<FCPair<D, SpatialEntry>> getSortedEntries(AbstractRStarTreeNode<?, ?> node, DBIDs ids) { + List<FCPair<D, SpatialEntry>> result = new ArrayList<>(); - for(int i = 0; i < node.getNumEntries(); i++) { + for (int i = 0; i < node.getNumEntries(); i++) { SpatialEntry entry = node.getEntry(i); D minMinDist = distanceQuery.getDistanceFactory().infiniteDistance(); for (DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) { D minDist = distanceFunction.minDist(entry, relation.get(iter)); + tree.statistics.countDistanceCalculation(); minMinDist = DistanceUtil.min(minDist, minMinDist); } - result.add(new DistanceEntry<D, SpatialEntry>(entry, minMinDist, i)); + result.add(new FCPair<>(minMinDist, entry)); } Collections.sort(result); @@ -228,38 +227,27 @@ public class GenericRStarTreeKNNQuery<O extends SpatialComparable, D extends Dis } @Override - public KNNResult<D> getKNNForObject(O obj, int k) { - if(k < 1) { - throw new IllegalArgumentException("At least one enumeration has to be requested!"); - } - - final KNNHeap<D> knnList = KNNUtil.newHeap(distanceFunction, k); + public KNNList<D> getKNNForObject(O obj, int k) { + final KNNHeap<D> knnList = DBIDUtil.newHeap(distanceFunction.getDistanceFactory(), k); doKNNQuery(obj, knnList); 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) { - if(k < 1) { - throw new IllegalArgumentException("At least one enumeration has to be requested!"); - } + public List<KNNList<D>> getKNNForBulkDBIDs(ArrayDBIDs ids, int k) { // While this works, it seems to be slow at least for large sets! - final Map<DBID, KNNHeap<D>> knnLists = new HashMap<DBID, KNNHeap<D>>(ids.size()); + final Map<DBID, KNNHeap<D>> knnLists = new HashMap<>(ids.size()); for (DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) { - knnLists.put(DBIDUtil.deref(iter), KNNUtil.newHeap(distanceFunction, k)); + knnLists.put(DBIDUtil.deref(iter), DBIDUtil.newHeap(distanceFunction.getDistanceFactory(), k)); } batchNN(tree.getRoot(), knnLists); - List<KNNResult<D>> result = new ArrayList<KNNResult<D>>(); + List<KNNList<D>> result = new ArrayList<>(); for (DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) { + tree.statistics.countKNNQuery(); result.add(knnLists.get(DBIDUtil.deref(iter)).toKNNList()); } return result; } -}
\ No newline at end of file +} diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/query/GenericRStarTreeRangeQuery.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/query/GenericRStarTreeRangeQuery.java index a5232b30..16a3393a 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/query/GenericRStarTreeRangeQuery.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/query/GenericRStarTreeRangeQuery.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.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,19 +24,18 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.query; */ import de.lmu.ifi.dbs.elki.data.spatial.SpatialComparable; -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.SpatialDistanceQuery; import de.lmu.ifi.dbs.elki.database.query.range.AbstractDistanceRangeQuery; import de.lmu.ifi.dbs.elki.distance.distancefunction.SpatialPrimitiveDistanceFunction; -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.index.tree.DirectoryEntry; import de.lmu.ifi.dbs.elki.index.tree.LeafEntry; import de.lmu.ifi.dbs.elki.index.tree.query.GenericDistanceSearchCandidate; import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.AbstractRStarTree; import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.AbstractRStarTreeNode; -import de.lmu.ifi.dbs.elki.utilities.datastructures.heap.Heap; +import de.lmu.ifi.dbs.elki.utilities.datastructures.heap.ComparableMinHeap; import de.lmu.ifi.dbs.elki.utilities.documentation.Reference; /** @@ -60,7 +59,7 @@ public class GenericRStarTreeRangeQuery<O extends SpatialComparable, D extends D /** * The index to use */ - protected final AbstractRStarTree<?, ?> tree; + protected final AbstractRStarTree<?, ?, ?> tree; /** * Spatial primitive distance function @@ -73,7 +72,7 @@ public class GenericRStarTreeRangeQuery<O extends SpatialComparable, D extends D * @param tree Index to use * @param distanceQuery Distance query to use */ - public GenericRStarTreeRangeQuery(AbstractRStarTree<?, ?> tree, SpatialDistanceQuery<O, D> distanceQuery) { + public GenericRStarTreeRangeQuery(AbstractRStarTree<?, ?, ?> tree, SpatialDistanceQuery<O, D> distanceQuery) { super(distanceQuery); this.tree = tree; this.distanceFunction = distanceQuery.getDistanceFunction(); @@ -86,12 +85,13 @@ public class GenericRStarTreeRangeQuery<O extends SpatialComparable, D extends D * @param epsilon Query range * @return Objects contained in query range. */ - protected DistanceDBIDResult<D> doRangeQuery(O object, D epsilon) { - final GenericDistanceDBIDList<D> result = new GenericDistanceDBIDList<D>(); - final Heap<GenericDistanceSearchCandidate<D>> pq = new Heap<GenericDistanceSearchCandidate<D>>(); + protected DistanceDBIDList<D> doRangeQuery(O object, D epsilon) { + final GenericDistanceDBIDList<D> result = new GenericDistanceDBIDList<>(); + final ComparableMinHeap<GenericDistanceSearchCandidate<D>> pq = new ComparableMinHeap<>(); + tree.statistics.countRangeQuery(); // push root - pq.add(new GenericDistanceSearchCandidate<D>(distanceFunction.getDistanceFactory().nullDistance(), tree.getRootID())); + pq.add(new GenericDistanceSearchCandidate<>(distanceFunction.getDistanceFactory().nullDistance(), tree.getRootID())); // search in tree while(!pq.isEmpty()) { @@ -100,11 +100,12 @@ public class GenericRStarTreeRangeQuery<O extends SpatialComparable, D extends D break; } - AbstractRStarTreeNode<?, ?> node = tree.getNode(pqNode.nodeID.intValue()); + AbstractRStarTreeNode<?, ?> node = tree.getNode(pqNode.nodeID); final int numEntries = node.getNumEntries(); for(int i = 0; i < numEntries; i++) { D distance = distanceFunction.minDist(node.getEntry(i), object); + tree.statistics.countDistanceCalculation(); if(distance.compareTo(epsilon) <= 0) { if(node.isLeaf()) { LeafEntry entry = (LeafEntry) node.getEntry(i); @@ -112,7 +113,7 @@ public class GenericRStarTreeRangeQuery<O extends SpatialComparable, D extends D } else { DirectoryEntry entry = (DirectoryEntry) node.getEntry(i); - pq.add(new GenericDistanceSearchCandidate<D>(distance, entry.getEntryID())); + pq.add(new GenericDistanceSearchCandidate<>(distance, entry.getEntryID())); } } } @@ -124,12 +125,7 @@ public class GenericRStarTreeRangeQuery<O extends SpatialComparable, D extends D } @Override - public DistanceDBIDResult<D> getRangeForObject(O obj, D range) { + public DistanceDBIDList<D> getRangeForObject(O obj, D range) { return doRangeQuery(obj, range); } - - @Override - public DistanceDBIDResult<D> getRangeForDBID(DBIDRef id, D range) { - return getRangeForObject(relation.get(id), range); - } }
\ No newline at end of file diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/query/RStarTreeUtil.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/query/RStarTreeUtil.java index 477e3a36..46c814ee 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/query/RStarTreeUtil.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/query/RStarTreeUtil.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.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 @@ -62,17 +62,17 @@ public final class RStarTreeUtil { * @return Query object */ @SuppressWarnings({ "cast", "unchecked" }) - public static <O extends SpatialComparable, D extends Distance<D>> RangeQuery<O, D> getRangeQuery(AbstractRStarTree<?, ?> tree, SpatialDistanceQuery<O, D> distanceQuery, Object... hints) { + public static <O extends SpatialComparable, D extends Distance<D>> RangeQuery<O, D> getRangeQuery(AbstractRStarTree<?, ?, ?> tree, SpatialDistanceQuery<O, D> distanceQuery, Object... hints) { // Can we support this distance function - spatial distances only! SpatialPrimitiveDistanceFunction<? super O, D> df = distanceQuery.getDistanceFunction(); // Can we use an optimized query? if(df instanceof SpatialPrimitiveDoubleDistanceFunction) { DistanceQuery<O, DoubleDistance> dqc = (DistanceQuery<O, DoubleDistance>) DistanceQuery.class.cast(distanceQuery); SpatialPrimitiveDoubleDistanceFunction<? super O> dfc = (SpatialPrimitiveDoubleDistanceFunction<? super O>) SpatialPrimitiveDoubleDistanceFunction.class.cast(df); - RangeQuery<O, ?> q = new DoubleDistanceRStarTreeRangeQuery<O>(tree, dqc, dfc); + RangeQuery<O, ?> q = new DoubleDistanceRStarTreeRangeQuery<>(tree, dqc, dfc); return (RangeQuery<O, D>) q; } - return new GenericRStarTreeRangeQuery<O, D>(tree, distanceQuery); + return new GenericRStarTreeRangeQuery<>(tree, distanceQuery); } /** @@ -87,16 +87,16 @@ public final class RStarTreeUtil { * @return Query object */ @SuppressWarnings({ "cast", "unchecked" }) - public static <O extends SpatialComparable, D extends Distance<D>> KNNQuery<O, D> getKNNQuery(AbstractRStarTree<?, ?> tree, SpatialDistanceQuery<O, D> distanceQuery, Object... hints) { + public static <O extends SpatialComparable, D extends Distance<D>> KNNQuery<O, D> getKNNQuery(AbstractRStarTree<?, ?, ?> tree, SpatialDistanceQuery<O, D> distanceQuery, Object... hints) { // Can we support this distance function - spatial distances only! SpatialPrimitiveDistanceFunction<? super O, D> df = distanceQuery.getDistanceFunction(); // Can we use an optimized query? if(df instanceof SpatialPrimitiveDoubleDistanceFunction) { DistanceQuery<O, DoubleDistance> dqc = (DistanceQuery<O, DoubleDistance>) DistanceQuery.class.cast(distanceQuery); SpatialPrimitiveDoubleDistanceFunction<? super O> dfc = (SpatialPrimitiveDoubleDistanceFunction<? super O>) SpatialPrimitiveDoubleDistanceFunction.class.cast(df); - KNNQuery<O, ?> q = new DoubleDistanceRStarTreeKNNQuery<O>(tree, dqc, dfc); + KNNQuery<O, ?> q = new DoubleDistanceRStarTreeKNNQuery<>(tree, dqc, dfc); return (KNNQuery<O, D>) q; } - return new GenericRStarTreeKNNQuery<O, D>(tree, distanceQuery); + return new GenericRStarTreeKNNQuery<>(tree, distanceQuery); } }
\ No newline at end of file diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/query/package-info.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/query/package-info.java index 0b47cab0..69bcd3d0 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/query/package-info.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/query/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/spatial/rstarvariants/rstar/RStarTree.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/rstar/RStarTree.java index d63d77cb..1c2a7fe8 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/rstar/RStarTree.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/rstar/RStarTree.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.rstar; 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,6 +25,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.rstar; import de.lmu.ifi.dbs.elki.index.tree.spatial.SpatialDirectoryEntry; import de.lmu.ifi.dbs.elki.index.tree.spatial.SpatialEntry; +import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.AbstractRTreeSettings; import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.NonFlatRStarTree; import de.lmu.ifi.dbs.elki.logging.Logging; import de.lmu.ifi.dbs.elki.persistent.PageFile; @@ -44,7 +45,7 @@ import de.lmu.ifi.dbs.elki.utilities.documentation.Title; @Title("R*-Tree") @Description("Balanced index structure based on bounding rectangles.") @Reference(authors = "N. Beckmann, H.-P. Kriegel, R. Schneider, B. Seeger", title = "The R*-tree: an efficient and robust access method for points and rectangles", booktitle = "Proceedings of the 1990 ACM SIGMOD International Conference on Management of Data, Atlantic City, NJ, May 23-25, 1990", url = "http://dx.doi.org/10.1145/93597.98741") -public class RStarTree extends NonFlatRStarTree<RStarTreeNode, SpatialEntry> { +public class RStarTree extends NonFlatRStarTree<RStarTreeNode, SpatialEntry, AbstractRTreeSettings> { /** * The logger for this class. */ @@ -54,9 +55,10 @@ public class RStarTree extends NonFlatRStarTree<RStarTreeNode, SpatialEntry> { * Constructor. * * @param pagefile Page file + * @param settings Settings class */ - public RStarTree(PageFile<RStarTreeNode> pagefile) { - super(pagefile); + public RStarTree(PageFile<RStarTreeNode> pagefile, AbstractRTreeSettings settings) { + super(pagefile, settings); } @Override diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/rstar/RStarTreeFactory.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/rstar/RStarTreeFactory.java index da7c03fd..72f7f7dd 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/rstar/RStarTreeFactory.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/rstar/RStarTreeFactory.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.rstar; 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,11 +27,10 @@ import de.lmu.ifi.dbs.elki.data.NumberVector; import de.lmu.ifi.dbs.elki.database.relation.Relation; import de.lmu.ifi.dbs.elki.index.tree.spatial.SpatialEntry; import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.AbstractRStarTreeFactory; -import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.bulk.BulkSplit; -import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.insert.InsertionStrategy; -import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.overflow.OverflowTreatment; -import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.split.SplitStrategy; +import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.AbstractRTreeSettings; import de.lmu.ifi.dbs.elki.persistent.PageFile; +import de.lmu.ifi.dbs.elki.persistent.PageFileFactory; +import de.lmu.ifi.dbs.elki.utilities.Alias; /** * Factory for regular R*-Trees. @@ -43,33 +42,22 @@ import de.lmu.ifi.dbs.elki.persistent.PageFile; * * @param <O> Object type */ -public class RStarTreeFactory<O extends NumberVector<?>> extends AbstractRStarTreeFactory<O, RStarTreeNode, SpatialEntry, RStarTreeIndex<O>> { +@Alias({"rstar", "r*"}) +public class RStarTreeFactory<O extends NumberVector<?>> extends AbstractRStarTreeFactory<O, RStarTreeNode, SpatialEntry, RStarTreeIndex<O>, AbstractRTreeSettings> { /** * Constructor. * - * @param fileName - * @param pageSize - * @param cacheSize - * @param bulkSplitter Bulk loading strategy - * @param insertionStrategy the strategy to find the insertion child - * @param nodeSplitter the strategy for splitting nodes. - * @param overflowTreatment the strategy to use for overflow treatment - * @param minimumFill the relative minimum fill + * @param pageFileFactory Data storage + * @param settings Tree settings */ - public RStarTreeFactory(String fileName, int pageSize, long cacheSize, BulkSplit bulkSplitter, InsertionStrategy insertionStrategy, SplitStrategy nodeSplitter, OverflowTreatment overflowTreatment, double minimumFill) { - super(fileName, pageSize, cacheSize, bulkSplitter, insertionStrategy, nodeSplitter, overflowTreatment, minimumFill); + public RStarTreeFactory(PageFileFactory<?> pageFileFactory, AbstractRTreeSettings settings) { + super(pageFileFactory, settings); } @Override public RStarTreeIndex<O> instantiate(Relation<O> relation) { PageFile<RStarTreeNode> pagefile = makePageFile(getNodeClass()); - RStarTreeIndex<O> index = new RStarTreeIndex<O>(relation, pagefile); - index.setBulkStrategy(bulkSplitter); - index.setInsertionStrategy(insertionStrategy); - index.setNodeSplitStrategy(nodeSplitter); - index.setOverflowTreatment(overflowTreatment); - index.setMinimumFill(minimumFill); - return index; + return new RStarTreeIndex<>(relation, pagefile, settings); } protected Class<RStarTreeNode> getNodeClass() { @@ -82,11 +70,18 @@ public class RStarTreeFactory<O extends NumberVector<?>> extends AbstractRStarTr * @author Erich Schubert * * @apiviz.exclude + * + * @param <O> Object type */ - public static class Parameterizer<O extends NumberVector<?>> extends AbstractRStarTreeFactory.Parameterizer<O> { + public static class Parameterizer<O extends NumberVector<?>> extends AbstractRStarTreeFactory.Parameterizer<O, AbstractRTreeSettings> { @Override protected RStarTreeFactory<O> makeInstance() { - return new RStarTreeFactory<O>(fileName, pageSize, cacheSize, bulkSplitter, insertionStrategy, nodeSplitter, overflowTreatment, minimumFill); + return new RStarTreeFactory<>(pageFileFactory, settings); + } + + @Override + protected AbstractRTreeSettings createSettings() { + return new AbstractRTreeSettings(); } } }
\ No newline at end of file diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/rstar/RStarTreeIndex.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/rstar/RStarTreeIndex.java index 1946293f..15b43e64 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/rstar/RStarTreeIndex.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/rstar/RStarTreeIndex.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.rstar; 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 @@ -37,11 +37,13 @@ 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.distance.distancevalue.Distance; +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.IndexTreePath; import de.lmu.ifi.dbs.elki.index.tree.spatial.SpatialEntry; import de.lmu.ifi.dbs.elki.index.tree.spatial.SpatialPointLeafEntry; +import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.AbstractRTreeSettings; import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.query.RStarTreeUtil; import de.lmu.ifi.dbs.elki.logging.Logging; import de.lmu.ifi.dbs.elki.persistent.PageFile; @@ -53,7 +55,7 @@ import de.lmu.ifi.dbs.elki.persistent.PageFile; * * @param <O> Object type */ -public class RStarTreeIndex<O extends NumberVector<?>> extends RStarTree implements RangeIndex<O>, KNNIndex<O> { +public class RStarTreeIndex<O extends NumberVector<?>> extends RStarTree implements RangeIndex<O>, KNNIndex<O>, DynamicIndex { /** * The appropriate logger for this index. */ @@ -69,11 +71,11 @@ public class RStarTreeIndex<O extends NumberVector<?>> extends RStarTree impleme * * @param relation Relation to index * @param pagefile Page file + * @param settings Tree settings */ - public RStarTreeIndex(Relation<O> relation, PageFile<RStarTreeNode> pagefile) { - super(pagefile); + public RStarTreeIndex(Relation<O> relation, PageFile<RStarTreeNode> pagefile, AbstractRTreeSettings settings) { + super(pagefile, settings); this.relation = relation; - this.initialize(); } /** @@ -86,6 +88,12 @@ public class RStarTreeIndex<O extends NumberVector<?>> extends RStarTree impleme return new SpatialPointLeafEntry(DBIDUtil.deref(id), relation.get(id)); } + @Override + public void initialize() { + super.initialize(); + insertAll(relation.getDBIDs()); // Will check for actual bulk load! + } + /** * Inserts the specified reel vector object into this index. * @@ -110,7 +118,7 @@ public class RStarTreeIndex<O extends NumberVector<?>> extends RStarTree impleme // Make an example leaf if(canBulkLoad()) { - List<SpatialEntry> leafs = new ArrayList<SpatialEntry>(ids.size()); + List<SpatialEntry> leafs = new ArrayList<>(ids.size()); for (DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) { leafs.add(createNewLeafEntry(iter)); } diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/rstar/RStarTreeNode.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/rstar/RStarTreeNode.java index b51d191a..7226fa1c 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/rstar/RStarTreeNode.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/rstar/RStarTreeNode.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.rstar; 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/spatial/rstarvariants/rstar/package-info.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/rstar/package-info.java index e15569c5..7897fae1 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/rstar/package-info.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/rstar/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/spatial/rstarvariants/strategies/bulk/AbstractBulkSplit.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/AbstractBulkSplit.java index 4a0304f1..7d463a03 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/AbstractBulkSplit.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/AbstractBulkSplit.java @@ -7,7 +7,7 @@ import java.util.List; 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 @@ -75,7 +75,7 @@ public abstract class AbstractBulkSplit implements BulkSplit { // build partitions final int size = objects.size(); final int numberPartitions = (int) Math.ceil(((double) size) / maxEntries); - List<List<T>> partitions = new ArrayList<List<T>>(numberPartitions); + List<List<T>> partitions = new ArrayList<>(numberPartitions); int start = 0; for(int pnum = 0; pnum < numberPartitions; pnum++) { int end = (int) ((pnum + 1.) * size / numberPartitions); diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/AdaptiveSortTileRecursiveBulkSplit.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/AdaptiveSortTileRecursiveBulkSplit.java new file mode 100644 index 00000000..fbbf7d8f --- /dev/null +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/AdaptiveSortTileRecursiveBulkSplit.java @@ -0,0 +1,151 @@ +package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.bulk; + +/* + 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.Arrays; +import java.util.List; + +import de.lmu.ifi.dbs.elki.data.spatial.SpatialComparable; +import de.lmu.ifi.dbs.elki.data.spatial.SpatialSingleMeanComparator; +import de.lmu.ifi.dbs.elki.utilities.datastructures.QuickSelect; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.AbstractParameterizer; + +/** + * This is variation of the original STR bulk load for non-rectangular data + * spaces. Instead of iterating through the dimensions and splitting each by + * (approximately) the same factor, this variation tries to adjust the factor to + * the extends of the data space. I.e. if the data set is twice as wide as high, + * this should produce twice as many partitions on the X than on the Y axis. + * + * Whether or not this offers benefits greatly depends on the distance queries + * used. But for symmetric distances, the resulting pages should be more + * rectangular, which often is beneficial. + * + * See {@link SortTileRecursiveBulkSplit} for the original STR bulk load. + * + * @author Erich Schubert + */ +public class AdaptiveSortTileRecursiveBulkSplit extends AbstractBulkSplit { + /** + * Static instance. + */ + public static final AdaptiveSortTileRecursiveBulkSplit STATIC = new AdaptiveSortTileRecursiveBulkSplit(); + + @Override + public <T extends SpatialComparable> List<List<T>> partition(List<T> spatialObjects, int minEntries, int maxEntries) { + final int dims = spatialObjects.get(0).getDimensionality(); + final int p = (int) Math.ceil(spatialObjects.size() / (double) maxEntries); + List<List<T>> ret = new ArrayList<>(p); + strPartition(spatialObjects, 0, spatialObjects.size(), 0, dims, maxEntries, new SpatialSingleMeanComparator(0), ret); + return ret; + } + + /** + * Recursively partition. + * + * @param objs Object list + * @param start Subinterval start + * @param end Subinterval end + * @param depth Iteration depth (must be less than dimensionality!) + * @param dims Total number of dimensions + * @param maxEntries Maximum page size + * @param c Comparison helper + * @param ret Output list + * @param <T> data type + */ + protected <T extends SpatialComparable> void strPartition(List<T> objs, int start, int end, int depth, int dims, int maxEntries, SpatialSingleMeanComparator c, List<List<T>> ret) { + final int p = (int) Math.ceil((end - start) / (double) maxEntries); + + // Compute min and max: + double[] mm = new double[dims * 2]; + for (int d = 0; d < mm.length; d += 2) { + mm[d] = Double.POSITIVE_INFINITY; // min <- +inf + mm[d + 1] = Double.NEGATIVE_INFINITY; // max <- -inf + } + for (int i = start; i < end; i++) { + T o = objs.get(i); + for (int d1 = 0, d2 = 0; d2 < mm.length; d1++, d2 += 2) { + mm[d2] = Math.min(mm[d2], o.getMin(d1)); + mm[d2 + 1] = Math.max(mm[d2 + 1], o.getMax(d1)); + } + } + // Find maximum and compute extends + double maxex = 0.0; + int sdim = depth; + double[] exts = new double[dims]; + for (int d = 0; d < mm.length; d += 2) { + final double extend = mm[d + 1] - mm[d]; + if (extend > maxex) { + maxex = extend; + sdim = d >>> 1; + } + exts[d >>> 1] = extend; + } + // Compute sum of the k largest extends: + Arrays.sort(exts); + double extsum = 0.; + for (int d = depth; d < exts.length; d++) { + extsum += exts[d]; + } + // Chose the number of partitions: + final int s; + if (maxex > 0. && depth + 1 < dims) { + s = (int) Math.ceil(Math.pow(p, 1.0 / (dims - depth)) * (dims - depth) * maxex / extsum); + } else { + s = (int) Math.ceil(Math.pow(p, 1.0 / (dims - depth))); + } + + final double len = end - start; // double intentional! + for (int i = 0; i < s; i++) { + // We don't completely sort, but only ensure the quantile is invariant. + int s2 = start + (int) ((i * len) / s); + int e2 = start + (int) (((i + 1) * len) / s); + // LoggingUtil.warning("STR " + dim + " s2:" + s2 + " e2:" + e2); + if (e2 < end) { + c.setDimension(sdim); + QuickSelect.quickSelect(objs, c, s2, end, e2); + } + if (depth + 1 == dims) { + ret.add(objs.subList(s2, e2)); + } else { + // Descend + strPartition(objs, s2, e2, depth + 1, dims, maxEntries, c, ret); + } + } + } + + /** + * Parameterization class. + * + * @author Erich Schubert + * + * @apiviz.exclude + */ + public static class Parameterizer extends AbstractParameterizer { + @Override + protected AdaptiveSortTileRecursiveBulkSplit makeInstance() { + return STATIC; + } + } +} diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/BulkSplit.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/BulkSplit.java index 1eb88f7c..c32a512c 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/BulkSplit.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/BulkSplit.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.bulk; 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/spatial/rstarvariants/strategies/bulk/FileOrderBulkSplit.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/FileOrderBulkSplit.java index 308c70cb..8b0dfd77 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/FileOrderBulkSplit.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/FileOrderBulkSplit.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.bulk; 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/spatial/rstarvariants/strategies/bulk/MaxExtensionBulkSplit.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/MaxExtensionBulkSplit.java index 2fd69531..5251e18b 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/MaxExtensionBulkSplit.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/MaxExtensionBulkSplit.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.bulk; 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,7 @@ import java.util.Collections; import java.util.List; import de.lmu.ifi.dbs.elki.data.spatial.SpatialComparable; -import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.util.SpatialComparator; +import de.lmu.ifi.dbs.elki.data.spatial.SpatialSingleMinComparator; import de.lmu.ifi.dbs.elki.logging.Logging; import de.lmu.ifi.dbs.elki.utilities.optionhandling.AbstractParameterizer; @@ -39,14 +39,14 @@ import de.lmu.ifi.dbs.elki.utilities.optionhandling.AbstractParameterizer; * * @author Elke Achtert * - * @apiviz.uses SpatialComparator + * @apiviz.composedOf SpatialSingleMinComparator */ public class MaxExtensionBulkSplit extends AbstractBulkSplit { /** * Logger. */ private static final Logging LOG = Logging.getLogger(MaxExtensionBulkSplit.class); - + /** * Static instance */ @@ -70,40 +70,40 @@ public class MaxExtensionBulkSplit extends AbstractBulkSplit { */ @Override public <N extends SpatialComparable> List<List<N>> partition(List<N> spatialObjects, int minEntries, int maxEntries) { - List<List<N>> partitions = new ArrayList<List<N>>(); - List<N> objects = new ArrayList<N>(spatialObjects); + List<List<N>> partitions = new ArrayList<>(); + List<N> objects = new ArrayList<>(spatialObjects); - while(objects.size() > 0) { + while (objects.size() > 0) { StringBuilder msg = new StringBuilder(); // get the split axis and split point int splitAxis = chooseMaximalExtendedSplitAxis(objects); int splitPoint = chooseBulkSplitPoint(objects.size(), minEntries, maxEntries); - if(LOG.isDebugging()) { + if (LOG.isDebugging()) { msg.append("\nsplitAxis ").append(splitAxis); msg.append("\nsplitPoint ").append(splitPoint); } // sort in the right dimension - Collections.sort(objects, new SpatialComparator(splitAxis, SpatialComparator.MIN)); + Collections.sort(objects, new SpatialSingleMinComparator(splitAxis)); // insert into partition - List<N> partition1 = new ArrayList<N>(); - for(int i = 0; i < splitPoint; i++) { + List<N> partition1 = new ArrayList<>(); + for (int i = 0; i < splitPoint; i++) { N o = objects.remove(0); partition1.add(o); } partitions.add(partition1); // copy array - if(LOG.isDebugging()) { + if (LOG.isDebugging()) { msg.append("\ncurrent partition ").append(partition1); msg.append("\nremaining objects # ").append(objects.size()); LOG.debugFine(msg.toString()); } } - if(LOG.isDebugging()) { + if (LOG.isDebugging()) { LOG.debugFine("partitions " + partitions); } return partitions; @@ -124,17 +124,17 @@ public class MaxExtensionBulkSplit extends AbstractBulkSplit { Arrays.fill(minExtension, Double.MAX_VALUE); // compute min and max value in each dimension - for(SpatialComparable object : objects) { - for(int d = 0; d < dimension; d++) { + for (SpatialComparable object : objects) { + for (int d = 0; d < dimension; d++) { double min, max; min = object.getMin(d); max = object.getMax(d); - if(maxExtension[d] < max) { + if (maxExtension[d] < max) { maxExtension[d] = max; } - if(minExtension[d] > min) { + if (minExtension[d] > min) { minExtension[d] = min; } } @@ -143,9 +143,9 @@ public class MaxExtensionBulkSplit extends AbstractBulkSplit { // set split axis to dim with maximal extension int splitAxis = -1; double max = 0; - for(int d = 0; d < dimension; d++) { + for (int d = 0; d < dimension; d++) { double currentExtension = maxExtension[d] - minExtension[d]; - if(max < currentExtension) { + if (max < currentExtension) { max = currentExtension; splitAxis = d; } @@ -166,4 +166,4 @@ public class MaxExtensionBulkSplit extends AbstractBulkSplit { return MaxExtensionBulkSplit.STATIC; } } -}
\ No newline at end of file +} diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/MaxExtensionSortTileRecursiveBulkSplit.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/MaxExtensionSortTileRecursiveBulkSplit.java new file mode 100644 index 00000000..6bf37642 --- /dev/null +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/MaxExtensionSortTileRecursiveBulkSplit.java @@ -0,0 +1,134 @@ +package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.bulk; + +/* + 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.List; + +import de.lmu.ifi.dbs.elki.data.spatial.SpatialComparable; +import de.lmu.ifi.dbs.elki.data.spatial.SpatialSingleMeanComparator; +import de.lmu.ifi.dbs.elki.utilities.datastructures.QuickSelect; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.AbstractParameterizer; + +/** + * This is variation of the {@link SortTileRecursiveBulkSplit}, incorporating + * some ideas from {@link MaxExtensionBulkSplit}. Instead of iterating through + * the axes in order, it always chooses the axis with the largest extend. This + * may rarely lead to the data being split on the same axis twice, but most + * importantly it varies the splitting order compared to STR. + * + * {@link AdaptiveSortTileRecursiveBulkSplit} takes these ideas one step + * further, by also varying the fan-out degree. + * + * @author Erich Schubert + */ +public class MaxExtensionSortTileRecursiveBulkSplit extends AbstractBulkSplit { + /** + * Static instance. + */ + public static final MaxExtensionSortTileRecursiveBulkSplit STATIC = new MaxExtensionSortTileRecursiveBulkSplit(); + + @Override + public <T extends SpatialComparable> List<List<T>> partition(List<T> spatialObjects, int minEntries, int maxEntries) { + final int dims = spatialObjects.get(0).getDimensionality(); + final int p = (int) Math.ceil(spatialObjects.size() / (double) maxEntries); + List<List<T>> ret = new ArrayList<>(p); + strPartition(spatialObjects, 0, spatialObjects.size(), 0, dims, maxEntries, new SpatialSingleMeanComparator(0), ret); + return ret; + } + + /** + * Recursively partition. + * + * @param objs Object list + * @param start Subinterval start + * @param end Subinterval end + * @param depth Iteration depth (must be less than dimensionality!) + * @param dims Total number of dimensions + * @param maxEntries Maximum page size + * @param c Comparison helper + * @param ret Output list + * @param <T> data type + */ + protected <T extends SpatialComparable> void strPartition(List<T> objs, int start, int end, int depth, int dims, int maxEntries, SpatialSingleMeanComparator c, List<List<T>> ret) { + final int p = (int) Math.ceil((end - start) / (double) maxEntries); + + // Compute min and max: + double[] mm = new double[dims * 2]; + for (int d = 0; d < mm.length; d += 2) { + mm[d] = Double.POSITIVE_INFINITY; // min <- +inf + mm[d + 1] = Double.NEGATIVE_INFINITY; // max <- -inf + } + for (int i = start; i < end; i++) { + T o = objs.get(i); + for (int d1 = 0, d2 = 0; d2 < mm.length; d1++, d2 += 2) { + mm[d2] = Math.min(mm[d2], o.getMin(d1)); + mm[d2 + 1] = Math.max(mm[d2 + 1], o.getMax(d1)); + } + } + // Find maximum and compute extends + double maxex = 0.0; + int sdim = -1; + for (int d = 0; d < mm.length; d += 2) { + final double extend = mm[d + 1] - mm[d]; + if (extend > maxex) { + maxex = extend; + sdim = d >> 1; + } + } + // Chose the number of partitions: + final int s = (int) Math.ceil(Math.pow(p, 1.0 / (dims - depth))); + + final double len = end - start; // double intentional! + for (int i = 0; i < s; i++) { + // We don't completely sort, but only ensure the quantile is invariant. + int s2 = start + (int) ((i * len) / s); + int e2 = start + (int) (((i + 1) * len) / s); + // LoggingUtil.warning("STR " + dim + " s2:" + s2 + " e2:" + e2); + if (e2 < end) { + c.setDimension(sdim); + QuickSelect.quickSelect(objs, c, s2, end, e2); + } + if (depth + 1 == dims) { + ret.add(objs.subList(s2, e2)); + } else { + // Descend + strPartition(objs, s2, e2, depth + 1, dims, maxEntries, c, ret); + } + } + } + + /** + * Parameterization class. + * + * @author Erich Schubert + * + * @apiviz.exclude + */ + public static class Parameterizer extends AbstractParameterizer { + @Override + protected MaxExtensionSortTileRecursiveBulkSplit makeInstance() { + return STATIC; + } + } +} diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/OneDimSortBulkSplit.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/OneDimSortBulkSplit.java index 2209ddef..5d2083b3 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/OneDimSortBulkSplit.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/OneDimSortBulkSplit.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.bulk; 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,10 +23,10 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.bulk; along with this program. If not, see <http://www.gnu.org/licenses/>. */ import java.util.Collections; -import java.util.Comparator; import java.util.List; import de.lmu.ifi.dbs.elki.data.spatial.SpatialComparable; +import de.lmu.ifi.dbs.elki.data.spatial.SpatialSingleMeanComparator; import de.lmu.ifi.dbs.elki.utilities.documentation.Reference; import de.lmu.ifi.dbs.elki.utilities.optionhandling.AbstractParameterizer; @@ -47,7 +47,7 @@ public class OneDimSortBulkSplit extends AbstractBulkSplit { /** * Static instance. */ - public static final AbstractBulkSplit STATIC = new OneDimSortBulkSplit(); + public static final OneDimSortBulkSplit STATIC = new OneDimSortBulkSplit(); /** * Constructor. @@ -59,14 +59,7 @@ public class OneDimSortBulkSplit extends AbstractBulkSplit { @Override public <T extends SpatialComparable> List<List<T>> partition(List<T> spatialObjects, int minEntries, int maxEntries) { // Sort by first dimension - Collections.sort(spatialObjects, new Comparator<SpatialComparable>() { - @Override - public int compare(SpatialComparable o1, SpatialComparable o2) { - double min1 = (o1.getMax(0) + o1.getMin(0)) * .5; - double min2 = (o2.getMax(0) + o2.getMin(0)) * .5; - return Double.compare(min1, min2); - } - }); + Collections.sort(spatialObjects, new SpatialSingleMeanComparator(0)); return trivialPartition(spatialObjects, minEntries, maxEntries); } @@ -79,8 +72,8 @@ public class OneDimSortBulkSplit extends AbstractBulkSplit { */ public static class Parameterizer extends AbstractParameterizer { @Override - protected AbstractBulkSplit makeInstance() { + protected OneDimSortBulkSplit makeInstance() { return OneDimSortBulkSplit.STATIC; } } -}
\ No newline at end of file +} diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/SortTileRecursiveBulkSplit.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/SortTileRecursiveBulkSplit.java index e24ef3ce..6cd7a598 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/SortTileRecursiveBulkSplit.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/SortTileRecursiveBulkSplit.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.bulk; 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,14 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.bulk; along with this program. If not, see <http://www.gnu.org/licenses/>. */ import java.util.ArrayList; -import java.util.Comparator; import java.util.List; import de.lmu.ifi.dbs.elki.data.spatial.SpatialComparable; +import de.lmu.ifi.dbs.elki.data.spatial.SpatialSingleMeanComparator; +import de.lmu.ifi.dbs.elki.utilities.Alias; import de.lmu.ifi.dbs.elki.utilities.datastructures.QuickSelect; import de.lmu.ifi.dbs.elki.utilities.documentation.Reference; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.AbstractParameterizer; /** * Sort-Tile-Recursive aims at tiling the data space with a grid-like structure @@ -44,13 +46,19 @@ import de.lmu.ifi.dbs.elki.utilities.documentation.Reference; * @author Erich Schubert */ @Reference(authors = "Leutenegger, S.T. and Lopez, M.A. and Edgington, J.", title = "STR: A simple and efficient algorithm for R-tree packing", booktitle = "Proc. 13th International Conference on Data Engineering, 1997", url = "http://dx.doi.org/10.1109/ICDE.1997.582015") +@Alias({"str", "STR"}) public class SortTileRecursiveBulkSplit extends AbstractBulkSplit { + /** + * Static instance. + */ + public static final SortTileRecursiveBulkSplit STATIC = new SortTileRecursiveBulkSplit(); + @Override public <T extends SpatialComparable> List<List<T>> partition(List<T> spatialObjects, int minEntries, int maxEntries) { final int dims = spatialObjects.get(0).getDimensionality(); final int p = (int) Math.ceil(spatialObjects.size() / (double) maxEntries); - List<List<T>> ret = new ArrayList<List<T>>(p); - strPartition(spatialObjects, 0, spatialObjects.size(), 0, dims, maxEntries, new Compare<T>(), ret); + List<List<T>> ret = new ArrayList<>(p); + strPartition(spatialObjects, 0, spatialObjects.size(), 0, dims, maxEntries, new SpatialSingleMeanComparator(0), ret); return ret; } @@ -67,24 +75,23 @@ public class SortTileRecursiveBulkSplit extends AbstractBulkSplit { * @param ret Output list * @param <T> data type */ - protected <T extends SpatialComparable> void strPartition(List<T> objs, int start, int end, int depth, int dims, int maxEntries, Compare<T> c, List<List<T>> ret) { + protected <T extends SpatialComparable> void strPartition(List<T> objs, int start, int end, int depth, int dims, int maxEntries, SpatialSingleMeanComparator c, List<List<T>> ret) { final int p = (int) Math.ceil((end - start) / (double) maxEntries); final int s = (int) Math.ceil(Math.pow(p, 1.0 / (dims - depth))); final double len = end - start; // double intentional! - for(int i = 0; i < s; i++) { + for (int i = 0; i < s; i++) { // We don't completely sort, but only ensure the quantile is invariant. int s2 = start + (int) ((i * len) / s); int e2 = start + (int) (((i + 1) * len) / s); // LoggingUtil.warning("STR " + dim + " s2:" + s2 + " e2:" + e2); - if(e2 < end) { - c.dim = depth; + if (e2 < end) { + c.setDimension(depth); QuickSelect.quickSelect(objs, c, s2, end, e2); } - if(depth + 1 == dims) { + if (depth + 1 == dims) { ret.add(objs.subList(s2, e2)); - } - else { + } else { // Descend strPartition(objs, s2, e2, depth + 1, dims, maxEntries, c, ret); } @@ -92,25 +99,16 @@ public class SortTileRecursiveBulkSplit extends AbstractBulkSplit { } /** - * Comparison helper. - * - * @apiviz.exclude + * Parameterization class. * * @author Erich Schubert * - * @param <T> Type + * @apiviz.exclude */ - private static class Compare<T extends SpatialComparable> implements Comparator<T> { - /** - * Current dimension. - */ - int dim; - + public static class Parameterizer extends AbstractParameterizer { @Override - public int compare(T o1, T o2) { - final double v1 = o1.getMin(dim) + o1.getMax(dim); - final double v2 = o2.getMin(dim) + o2.getMax(dim); - return Double.compare(v1, v2); + protected SortTileRecursiveBulkSplit makeInstance() { + return STATIC; } } -}
\ No newline at end of file +} diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/SpatialSortBulkSplit.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/SpatialSortBulkSplit.java index beb6e657..6e2b6369 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/SpatialSortBulkSplit.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/SpatialSortBulkSplit.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.bulk; 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 @@ -40,7 +40,7 @@ import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.ObjectParameter; * <p> * On packing R-trees<br/> * Kamel, I. and Faloutsos, C.<br/> - * Proc. 2of the second international conference on Information and knowledge + * Proc. of the second international conference on Information and knowledge * management * </p> * @@ -48,7 +48,7 @@ import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.ObjectParameter; * * @author Erich Schubert */ -@Reference(title = "On packing R-trees", authors = "Kamel, I. and Faloutsos, C.", booktitle = "Proc. 2of the second international conference on Information and knowledge management", url = "http://dx.doi.org/10.1145/170088.170403") +@Reference(title = "On packing R-trees", authors = "Kamel, I. and Faloutsos, C.", booktitle = "Proc. of the second international conference on Information and knowledge management", url = "http://dx.doi.org/10.1145/170088.170403") public class SpatialSortBulkSplit extends AbstractBulkSplit { /** * Sorting class @@ -93,7 +93,7 @@ public class SpatialSortBulkSplit extends AbstractBulkSplit { protected void makeOptions(Parameterization config) { super.makeOptions(config); - ObjectParameter<SpatialSorter> sorterP = new ObjectParameter<SpatialSorter>(SORTER_ID, SpatialSorter.class); + ObjectParameter<SpatialSorter> sorterP = new ObjectParameter<>(SORTER_ID, SpatialSorter.class); if(config.grab(sorterP)) { sorter = sorterP.instantiateClass(config); } diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/package-info.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/package-info.java index 0d01ba83..5c52de3e 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/package-info.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/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/spatial/rstarvariants/strategies/insert/ApproximativeLeastOverlapInsertionStrategy.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/insert/ApproximativeLeastOverlapInsertionStrategy.java index c39bd914..5b4e7a56 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/insert/ApproximativeLeastOverlapInsertionStrategy.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/insert/ApproximativeLeastOverlapInsertionStrategy.java @@ -3,7 +3,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.insert; 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 @@ -77,7 +77,7 @@ public class ApproximativeLeastOverlapInsertionStrategy extends LeastOverlapInse } // Heap of candidates - TopBoundedHeap<DoubleIntPair> candidates = new TopBoundedHeap<DoubleIntPair>(numCandidates, Collections.reverseOrder()); + TopBoundedHeap<DoubleIntPair> candidates = new TopBoundedHeap<>(numCandidates, Collections.reverseOrder()); for(int i = 0; i < size; i++) { // Existing object and extended rectangle: SpatialComparable entry = getter.get(options, i); diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/insert/CombinedInsertionStrategy.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/insert/CombinedInsertionStrategy.java index 63bbe9dc..837f0312 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/insert/CombinedInsertionStrategy.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/insert/CombinedInsertionStrategy.java @@ -3,7 +3,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.insert; 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 @@ -108,12 +108,12 @@ public class CombinedInsertionStrategy implements InsertionStrategy { @Override protected void makeOptions(Parameterization config) { super.makeOptions(config); - ClassParameter<InsertionStrategy> dirP = new ClassParameter<InsertionStrategy>(DIR_STRATEGY_ID, InsertionStrategy.class, LeastEnlargementWithAreaInsertionStrategy.class); + ClassParameter<InsertionStrategy> dirP = new ClassParameter<>(DIR_STRATEGY_ID, InsertionStrategy.class, LeastEnlargementWithAreaInsertionStrategy.class); if(config.grab(dirP)) { dirStrategy = dirP.instantiateClass(config); } - ClassParameter<InsertionStrategy> leafP = new ClassParameter<InsertionStrategy>(LEAF_STRATEGY_ID, InsertionStrategy.class, LeastOverlapInsertionStrategy.class); + ClassParameter<InsertionStrategy> leafP = new ClassParameter<>(LEAF_STRATEGY_ID, InsertionStrategy.class, LeastOverlapInsertionStrategy.class); if(config.grab(leafP)) { leafStrategy = leafP.instantiateClass(config); } diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/insert/InsertionStrategy.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/insert/InsertionStrategy.java index 96294514..477f0f48 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/insert/InsertionStrategy.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/insert/InsertionStrategy.java @@ -3,7 +3,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.insert; 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/spatial/rstarvariants/strategies/insert/LeastEnlargementInsertionStrategy.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/insert/LeastEnlargementInsertionStrategy.java index eb211cb6..39348bf5 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/insert/LeastEnlargementInsertionStrategy.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/insert/LeastEnlargementInsertionStrategy.java @@ -3,7 +3,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.insert; 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/spatial/rstarvariants/strategies/insert/LeastEnlargementWithAreaInsertionStrategy.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/insert/LeastEnlargementWithAreaInsertionStrategy.java index 977a132b..627428e9 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/insert/LeastEnlargementWithAreaInsertionStrategy.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/insert/LeastEnlargementWithAreaInsertionStrategy.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.insert; 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/spatial/rstarvariants/strategies/insert/LeastOverlapInsertionStrategy.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/insert/LeastOverlapInsertionStrategy.java index 2eba8912..18855d90 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/insert/LeastOverlapInsertionStrategy.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/insert/LeastOverlapInsertionStrategy.java @@ -3,7 +3,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.insert; 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/spatial/rstarvariants/strategies/insert/package-info.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/insert/package-info.java index ad54e1e1..d425c7bd 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/insert/package-info.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/insert/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/spatial/rstarvariants/strategies/overflow/LimitedReinsertOverflowTreatment.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/overflow/LimitedReinsertOverflowTreatment.java index 3c25cbbc..0af90d78 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/overflow/LimitedReinsertOverflowTreatment.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/overflow/LimitedReinsertOverflowTreatment.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.overflow 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,7 +25,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.overflow import java.util.BitSet; -import de.lmu.ifi.dbs.elki.distance.distancefunction.SquaredEuclideanDistanceFunction; +import de.lmu.ifi.dbs.elki.distance.distancefunction.minkowski.SquaredEuclideanDistanceFunction; import de.lmu.ifi.dbs.elki.index.tree.IndexTreePath; import de.lmu.ifi.dbs.elki.index.tree.spatial.SpatialEntry; import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.AbstractRStarTree; @@ -73,7 +73,7 @@ public class LimitedReinsertOverflowTreatment implements OverflowTreatment { } @Override - public <N extends AbstractRStarTreeNode<N, E>, E extends SpatialEntry> boolean handleOverflow(AbstractRStarTree<N, E> tree, N node, IndexTreePath<E> path) { + public <N extends AbstractRStarTreeNode<N, E>, E extends SpatialEntry> boolean handleOverflow(AbstractRStarTree<N, E, ?> tree, N node, IndexTreePath<E> path) { final int level = /* tree.getHeight() - */(path.getPathCount() - 1); // No reinsertions at root level if(path.getPathCount() == 1) { @@ -121,7 +121,7 @@ public class LimitedReinsertOverflowTreatment implements OverflowTreatment { @Override protected void makeOptions(Parameterization config) { super.makeOptions(config); - ObjectParameter<ReinsertStrategy> strategyP = new ObjectParameter<ReinsertStrategy>(REINSERT_STRATEGY_ID, ReinsertStrategy.class, CloseReinsert.class); + ObjectParameter<ReinsertStrategy> strategyP = new ObjectParameter<>(REINSERT_STRATEGY_ID, ReinsertStrategy.class, CloseReinsert.class); if(config.grab(strategyP)) { reinsertStrategy = strategyP.instantiateClass(config); } diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/overflow/OverflowTreatment.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/overflow/OverflowTreatment.java index 87d09038..4b2f94b1 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/overflow/OverflowTreatment.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/overflow/OverflowTreatment.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.overflow 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 @@ -49,5 +49,5 @@ public interface OverflowTreatment { * @param path Path * @return true when already handled (e.g. by reinserting) */ - <N extends AbstractRStarTreeNode<N, E>, E extends SpatialEntry> boolean handleOverflow(AbstractRStarTree<N, E> tree, N node, IndexTreePath<E> path); + <N extends AbstractRStarTreeNode<N, E>, E extends SpatialEntry> boolean handleOverflow(AbstractRStarTree<N, E, ?> tree, N node, IndexTreePath<E> path); }
\ No newline at end of file diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/overflow/SplitOnlyOverflowTreatment.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/overflow/SplitOnlyOverflowTreatment.java index cfbcf6a9..82ceb4ef 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/overflow/SplitOnlyOverflowTreatment.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/overflow/SplitOnlyOverflowTreatment.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.overflow 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 @@ -48,7 +48,7 @@ public class SplitOnlyOverflowTreatment implements OverflowTreatment { } @Override - public <N extends AbstractRStarTreeNode<N, E>, E extends SpatialEntry> boolean handleOverflow(AbstractRStarTree<N, E> tree, N node, IndexTreePath<E> path) { + public <N extends AbstractRStarTreeNode<N, E>, E extends SpatialEntry> boolean handleOverflow(AbstractRStarTree<N, E, ?> tree, N node, IndexTreePath<E> path) { return false; } diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/overflow/package-info.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/overflow/package-info.java index 30899736..fc7f16f0 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/overflow/package-info.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/overflow/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/spatial/rstarvariants/strategies/package-info.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/package-info.java index 41e2eb0b..7d2dfc0a 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/package-info.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/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/spatial/rstarvariants/strategies/reinsert/AbstractPartialReinsert.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/reinsert/AbstractPartialReinsert.java index bb222dfe..cf447985 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/reinsert/AbstractPartialReinsert.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/reinsert/AbstractPartialReinsert.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.reinsert 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,7 +24,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.reinsert */ import de.lmu.ifi.dbs.elki.distance.distancefunction.SpatialPrimitiveDoubleDistanceFunction; -import de.lmu.ifi.dbs.elki.distance.distancefunction.SquaredEuclideanDistanceFunction; +import de.lmu.ifi.dbs.elki.distance.distancefunction.minkowski.SquaredEuclideanDistanceFunction; 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.constraints.GreaterConstraint; @@ -99,7 +99,7 @@ public abstract class AbstractPartialReinsert implements ReinsertStrategy { if (config.grab(reinsertAmountP)) { reinsertAmount = reinsertAmountP.getValue(); } - ObjectParameter<SpatialPrimitiveDoubleDistanceFunction<?>> distanceP = new ObjectParameter<SpatialPrimitiveDoubleDistanceFunction<?>>(REINSERT_DISTANCE_ID, SpatialPrimitiveDoubleDistanceFunction.class, SquaredEuclideanDistanceFunction.class); + ObjectParameter<SpatialPrimitiveDoubleDistanceFunction<?>> distanceP = new ObjectParameter<>(REINSERT_DISTANCE_ID, SpatialPrimitiveDoubleDistanceFunction.class, SquaredEuclideanDistanceFunction.class); if (config.grab(distanceP)) { distanceFunction = distanceP.instantiateClass(config); } diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/reinsert/CloseReinsert.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/reinsert/CloseReinsert.java index 12a4ed0f..3002f18b 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/reinsert/CloseReinsert.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/reinsert/CloseReinsert.java @@ -15,7 +15,7 @@ import de.lmu.ifi.dbs.elki.utilities.pairs.DoubleIntPair; 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/spatial/rstarvariants/strategies/reinsert/FarReinsert.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/reinsert/FarReinsert.java index 771f56fb..02c1d4d7 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/reinsert/FarReinsert.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/reinsert/FarReinsert.java @@ -15,7 +15,7 @@ import de.lmu.ifi.dbs.elki.utilities.pairs.DoubleIntPair; 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/spatial/rstarvariants/strategies/reinsert/ReinsertStrategy.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/reinsert/ReinsertStrategy.java index cba96367..2a4f130f 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/reinsert/ReinsertStrategy.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/reinsert/ReinsertStrategy.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.strategies.reinsert 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/spatial/rstarvariants/strategies/reinsert/package-info.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/reinsert/package-info.java index f6a6f6e9..2d2c6871 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/reinsert/package-info.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/reinsert/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/spatial/rstarvariants/strategies/split/AngTanLinearSplit.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/split/AngTanLinearSplit.java index 3e3d599c..c31abc2d 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/split/AngTanLinearSplit.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/split/AngTanLinearSplit.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.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 diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/split/GreeneSplit.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/split/GreeneSplit.java index 99c15fd6..d00479cf 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/split/GreeneSplit.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/split/GreeneSplit.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.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 diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/split/RTreeLinearSplit.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/split/RTreeLinearSplit.java index b4ff2364..4dc9b15d 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/split/RTreeLinearSplit.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/split/RTreeLinearSplit.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.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 diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/split/RTreeQuadraticSplit.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/split/RTreeQuadraticSplit.java index 8f61771d..91ef8f16 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/split/RTreeQuadraticSplit.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/split/RTreeQuadraticSplit.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.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 diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/split/SplitStrategy.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/split/SplitStrategy.java index 658a63da..0bc1ffcf 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/split/SplitStrategy.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/split/SplitStrategy.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.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 diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/split/TopologicalSplitter.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/split/TopologicalSplitter.java index ab32ba19..dc9092ad 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/split/TopologicalSplitter.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/split/TopologicalSplitter.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.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 @@ -50,7 +50,7 @@ public class TopologicalSplitter implements SplitStrategy { public static final TopologicalSplitter STATIC = new TopologicalSplitter(); /** - * constructor. + * Constructor. */ public TopologicalSplitter() { // Nothing to do. @@ -58,7 +58,7 @@ public class TopologicalSplitter implements SplitStrategy { @Override public <E extends SpatialComparable, A> BitSet split(A entries, ArrayAdapter<E, A> getter, int minEntries) { - Split<A, E> split = new Split<A, E>(entries, getter); + Split<A, E> split = new Split<>(entries, getter); split.chooseSplitAxis(minEntries); split.chooseSplitPoint(minEntries); diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/split/package-info.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/split/package-info.java index 9e8291be..bb8cb1e2 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/split/package-info.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/split/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/spatial/rstarvariants/util/NodeArrayAdapter.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/util/NodeArrayAdapter.java index 3bf35d9d..def824ba 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/util/NodeArrayAdapter.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/util/NodeArrayAdapter.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.util; 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,7 +43,6 @@ public class NodeArrayAdapter implements ArrayAdapter<SpatialEntry, AbstractNode */ protected NodeArrayAdapter() { super(); - // TODO Auto-generated constructor stub } @Override diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/util/SpatialComparator.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/util/SpatialComparator.java deleted file mode 100644 index 2f1ea9b1..00000000 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/util/SpatialComparator.java +++ /dev/null @@ -1,103 +0,0 @@ -package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.util; - -/* - 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.Comparator; - -import de.lmu.ifi.dbs.elki.data.spatial.SpatialComparable; - -/** - * Compares objects of type SpatialComparable. - * - * @author Elke Achtert - * - * @apiviz.uses SpatialComparable - */ -public final class SpatialComparator implements Comparator<SpatialComparable> { - /** - * Indicates the comparison of the min values of the entries' MBRs. - */ - public static final int MIN = 1; - - /** - * Indicates the comparison of the max values of the entries' MBRs. - */ - public static final int MAX = 2; - - /** - * The dimension for comparison. - */ - private final int compareDimension; - - /** - * Indicates the comparison value (min or max). - */ - private final int comparisonValue; - - /** - * Creates a new spatial comparator with the specified parameters. - * - * @param compareDimension the dimension to be set for comparison - * @param comparisonValue the comparison value to be set - */ - public SpatialComparator(int compareDimension, int comparisonValue) { - this.compareDimension = compareDimension; - this.comparisonValue = comparisonValue; - } - - /** - * Compares the two specified spatial comparables according to the sorting - * dimension and the comparison value of this Comparator. - * - * @param o1 the first spatial comparable - * @param o2 the second spatial comparable - * @return a negative integer, zero, or a positive integer as the first - * argument is less than, equal to, or greater than the second. - */ - @Override - public int compare(SpatialComparable o1, SpatialComparable o2) { - if(comparisonValue == MIN) { - if(o1.getMin(compareDimension) < o2.getMin(compareDimension)) { - return -1; - } - - if(o1.getMin(compareDimension) > o2.getMin(compareDimension)) { - return +1; - } - } - else if(comparisonValue == MAX) { - if(o1.getMax(compareDimension) < o2.getMax(compareDimension)) { - return -1; - } - - if(o1.getMax(compareDimension) > o2.getMax(compareDimension)) { - return +1; - } - } - else { - throw new IllegalArgumentException("No comparison value specified!"); - } - return 0; - } -} diff --git a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/util/package-info.java b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/util/package-info.java index 10991028..22088417 100644 --- a/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/util/package-info.java +++ b/src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/util/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 |