summaryrefslogtreecommitdiff
path: root/src/de/lmu/ifi/dbs/elki/index
diff options
context:
space:
mode:
Diffstat (limited to 'src/de/lmu/ifi/dbs/elki/index')
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/AbstractIndex.java34
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/AbstractRefiningIndex.java111
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/DynamicIndex.java66
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/Index.java49
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/IndexFactory.java3
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/KNNIndex.java3
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/PagedIndexFactory.java110
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/RKNNIndex.java3
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/RangeIndex.java3
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/lsh/InMemoryLSHIndex.java418
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/lsh/hashfamilies/AbstractHashFunctionFamily.java164
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/lsh/hashfamilies/EuclideanHashFunctionFamily.java74
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/lsh/hashfamilies/LocalitySensitiveHashFunctionFamily.java65
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/lsh/hashfamilies/ManhattanHashFunctionFamily.java76
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/lsh/hashfamilies/package-info.java27
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/lsh/hashfunctions/LocalitySensitiveHashFunction.java41
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/lsh/hashfunctions/MultipleProjectionsLocalitySensitiveHashFunction.java119
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/lsh/hashfunctions/package-info.java27
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/lsh/package-info.java27
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/preprocessed/AbstractPreprocessorIndex.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/preprocessed/LocalProjectionIndex.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/AbstractMaterializeKNNPreprocessor.java23
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/CachedDoubleDistanceKNNPreprocessor.java205
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/KNNChangeEvent.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/KNNJoinMaterializeKNNPreprocessor.java17
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/KNNListener.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/MaterializeKNNAndRKNNPreprocessor.java63
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/MaterializeKNNPreprocessor.java123
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/MetricalIndexApproximationMaterializeKNNPreprocessor.java28
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/PartitionApproximationMaterializeKNNPreprocessor.java28
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/RandomSampleKNNPreprocessor.java35
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/SpatialApproximationMaterializeKNNPreprocessor.java28
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/preprocessed/localpca/AbstractFilteredPCAIndex.java20
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/preprocessed/localpca/FilteredLocalPCAIndex.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/preprocessed/localpca/KNNQueryFilteredPCAIndex.java32
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/preprocessed/localpca/RangeQueryFilteredPCAIndex.java19
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/preprocessed/localpca/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/preprocessed/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/preprocessed/preference/AbstractPreferenceVectorIndex.java9
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/preprocessed/preference/DiSHPreferenceVectorIndex.java27
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/preprocessed/preference/HiSCPreferenceVectorIndex.java19
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/preprocessed/preference/PreferenceVectorIndex.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/preprocessed/preference/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/preprocessed/snn/SharedNearestNeighborIndex.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/preprocessed/snn/SharedNearestNeighborPreprocessor.java27
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/preprocessed/snn/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/preprocessed/subspaceproj/AbstractSubspaceProjectionIndex.java28
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/preprocessed/subspaceproj/FourCSubspaceIndex.java19
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/preprocessed/subspaceproj/PreDeConSubspaceIndex.java15
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/preprocessed/subspaceproj/SubspaceProjectionIndex.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/preprocessed/subspaceproj/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/projected/LatLngAsECEFIndex.java292
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/projected/LngLatAsECEFIndex.java287
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/projected/PINN.java166
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/projected/ProjectedIndex.java648
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/projected/package-info.java26
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/AbstractDirectoryEntry.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/AbstractLeafEntry.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/AbstractNode.java6
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/BreadthFirstEnumeration.java4
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/DirectoryEntry.java7
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/Entry.java3
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/IndexTree.java56
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/IndexTreePath.java11
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/LeafEntry.java4
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/Node.java3
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/TreeIndexFactory.java184
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/TreeIndexHeader.java4
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/TreeIndexPathComponent.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/MetricalIndexTree.java10
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/AbstractMTree.java373
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/AbstractMTreeFactory.java107
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/AbstractMTreeNode.java82
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/MTreeDirectoryEntry.java44
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/MTreeEntry.java14
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/MTreeLeafEntry.java48
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/MTreeSettings.java56
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/AbstractMkTree.java44
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/AbstractMkTreeUnified.java36
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/AbstractMkTreeUnifiedFactory.java58
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/MkTreeHeader.java6
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/MkTreeSettings.java46
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppDirectoryEntry.java11
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppEntry.java7
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppLeafEntry.java9
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppTree.java215
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppTreeFactory.java77
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppTreeIndex.java111
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppTreeNode.java14
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/MkAppTreeSettings.java47
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/PolynomialApproximation.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkapp/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/ApproximationLine.java24
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/ConvexHull.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCoPDirectoryEntry.java29
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCoPEntry.java13
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCoPLeafEntry.java37
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCoPTree.java335
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCoPTreeIndex.java112
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCoPTreeNode.java18
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/MkCopTreeFactory.java43
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkcop/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxDirectoryEntry.java34
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxEntry.java22
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxLeafEntry.java30
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxTree.java230
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxTreeFactory.java37
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxTreeIndex.java100
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/MkMaxTreeNode.java35
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mkmax/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabDirectoryEntry.java60
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabEntry.java37
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabLeafEntry.java63
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabTree.java146
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabTreeFactory.java33
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabTreeIndex.java136
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/MkTabTreeNode.java44
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/mktab/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mktrees/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mtree/MTree.java90
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mtree/MTreeFactory.java34
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mtree/MTreeIndex.java144
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mtree/MTreeNode.java6
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/mtree/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/DoubleDistanceMetricalIndexKNNQuery.java48
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/DoubleDistanceMetricalIndexRangeQuery.java42
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/MTreeQueryUtil.java24
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/MetricalIndexKNNQuery.java83
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/MetricalIndexRangeQuery.java56
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/MkTreeRKNNQuery.java21
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/query/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/split/MTreeSplit.java138
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/insert/MTreeInsert.java50
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/insert/MinimumEnlargementInsert.java117
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/insert/package-info.java26
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/package-info.java26
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/Assignments.java (renamed from src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/split/Assignments.java)39
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/DistanceEntry.java (renamed from src/de/lmu/ifi/dbs/elki/index/tree/DistanceEntry.java)28
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/MLBDistSplit.java (renamed from src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/split/MLBDistSplit.java)63
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/MMRadSplit.java88
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/MRadSplit.java (renamed from src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/split/MRadSplit.java)54
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/MTreeSplit.java223
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/RandomSplit.java136
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/strategies/split/package-info.java26
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/metrical/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/query/DoubleDistanceSearchCandidate.java6
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/query/DoubleMTreeDistanceSearchCandidate.java4
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/query/GenericDistanceSearchCandidate.java6
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/query/GenericMTreeDistanceSearchCandidate.java54
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/query/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/SpatialDirectoryEntry.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/SpatialEntry.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/SpatialIndexTree.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/SpatialNode.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/SpatialPair.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/SpatialPointLeafEntry.java56
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/kd/MinimalisticMemoryKDTree.java443
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/kd/package-info.java (renamed from src/de/lmu/ifi/dbs/elki/index/tree/metrical/mtreevariants/split/package-info.java)6
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/AbstractRStarTree.java463
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/AbstractRStarTreeFactory.java134
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/AbstractRStarTreeNode.java4
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/AbstractRTreeSettings.java121
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/NonFlatRStarTree.java13
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/deliclu/DeLiCluDirectoryEntry.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/deliclu/DeLiCluEntry.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/deliclu/DeLiCluLeafEntry.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/deliclu/DeLiCluNode.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/deliclu/DeLiCluTree.java41
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/deliclu/DeLiCluTreeFactory.java42
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/deliclu/DeLiCluTreeIndex.java20
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/deliclu/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/query/DoubleDistanceRStarTreeKNNQuery.java51
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/query/DoubleDistanceRStarTreeRangeQuery.java30
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/query/GenericRStarTreeKNNQuery.java110
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/query/GenericRStarTreeRangeQuery.java34
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/query/RStarTreeUtil.java14
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/query/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/rstar/RStarTree.java10
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/rstar/RStarTreeFactory.java45
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/rstar/RStarTreeIndex.java20
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/rstar/RStarTreeNode.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/rstar/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/AbstractBulkSplit.java4
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/AdaptiveSortTileRecursiveBulkSplit.java151
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/BulkSplit.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/FileOrderBulkSplit.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/MaxExtensionBulkSplit.java40
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/MaxExtensionSortTileRecursiveBulkSplit.java134
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/OneDimSortBulkSplit.java19
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/SortTileRecursiveBulkSplit.java50
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/SpatialSortBulkSplit.java8
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/bulk/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/insert/ApproximativeLeastOverlapInsertionStrategy.java4
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/insert/CombinedInsertionStrategy.java6
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/insert/InsertionStrategy.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/insert/LeastEnlargementInsertionStrategy.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/insert/LeastEnlargementWithAreaInsertionStrategy.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/insert/LeastOverlapInsertionStrategy.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/insert/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/overflow/LimitedReinsertOverflowTreatment.java8
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/overflow/OverflowTreatment.java4
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/overflow/SplitOnlyOverflowTreatment.java4
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/overflow/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/reinsert/AbstractPartialReinsert.java6
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/reinsert/CloseReinsert.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/reinsert/FarReinsert.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/reinsert/ReinsertStrategy.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/reinsert/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/split/AngTanLinearSplit.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/split/GreeneSplit.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/split/RTreeLinearSplit.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/split/RTreeQuadraticSplit.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/split/SplitStrategy.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/split/TopologicalSplitter.java6
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/strategies/split/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/util/NodeArrayAdapter.java3
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/util/SpatialComparator.java103
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/tree/spatial/rstarvariants/util/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/vafile/PartialVAFile.java146
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/vafile/VAFile.java115
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/vafile/VALPNormDistance.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/index/vafile/package-info.java2
229 files changed, 7475 insertions, 3682 deletions
diff --git a/src/de/lmu/ifi/dbs/elki/index/AbstractIndex.java b/src/de/lmu/ifi/dbs/elki/index/AbstractIndex.java
index 44418a3e..c9dbf3a0 100644
--- a/src/de/lmu/ifi/dbs/elki/index/AbstractIndex.java
+++ b/src/de/lmu/ifi/dbs/elki/index/AbstractIndex.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index;
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,15 +23,14 @@ package de.lmu.ifi.dbs.elki.index;
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-import de.lmu.ifi.dbs.elki.database.ids.DBIDRef;
-import de.lmu.ifi.dbs.elki.database.ids.DBIDs;
import de.lmu.ifi.dbs.elki.database.relation.Relation;
-import de.lmu.ifi.dbs.elki.persistent.PageFileStatistics;
/**
* Abstract base class for indexes with some implementation defaults.
*
* @author Erich Schubert
+ *
+ * @apiviz.excludeSubtypes
*
* @param <O> Object type stored in the index
*/
@@ -56,31 +55,4 @@ public abstract class AbstractIndex<O> implements Index {
@Override
abstract public String getShortName();
-
- @Override
- public PageFileStatistics getPageFileStatistics() {
- // TODO: move this into a separate interface?
- // By default, we are not file based - no statistics available
- return null;
- }
-
- @Override
- public void insert(DBIDRef id) {
- throw new UnsupportedOperationException("This index does not allow dynamic updates.");
- }
-
- @Override
- public void insertAll(DBIDs ids) {
- throw new UnsupportedOperationException("This index does not allow dynamic updates.");
- }
-
- @Override
- public boolean delete(DBIDRef id) {
- throw new UnsupportedOperationException("This index does not allow dynamic updates.");
- }
-
- @Override
- public void deleteAll(DBIDs id) {
- throw new UnsupportedOperationException("This index does not allow dynamic updates.");
- }
} \ No newline at end of file
diff --git a/src/de/lmu/ifi/dbs/elki/index/AbstractRefiningIndex.java b/src/de/lmu/ifi/dbs/elki/index/AbstractRefiningIndex.java
index 33c9b341..b266824a 100644
--- a/src/de/lmu/ifi/dbs/elki/index/AbstractRefiningIndex.java
+++ b/src/de/lmu/ifi/dbs/elki/index/AbstractRefiningIndex.java
@@ -1,9 +1,10 @@
package de.lmu.ifi.dbs.elki.index;
+
/*
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
@@ -22,20 +23,15 @@ package de.lmu.ifi.dbs.elki.index;
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.DBIDs;
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.range.AbstractDistanceRangeQuery;
import de.lmu.ifi.dbs.elki.database.relation.Relation;
-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.persistent.PageFileStatistics;
+import de.lmu.ifi.dbs.elki.logging.Logging;
+import de.lmu.ifi.dbs.elki.logging.statistics.Counter;
/**
* Abstract base class for Filter-refinement indexes.
@@ -44,16 +40,17 @@ import de.lmu.ifi.dbs.elki.persistent.PageFileStatistics;
*
* @author Erich Schubert
*
+ * @apiviz.excludeSubtypes
* @apiviz.has AbstractRangeQuery
* @apiviz.has AbstractKNNQuery
*
* @param <O> Object type
*/
-public abstract class AbstractRefiningIndex<O> extends AbstractIndex<O> implements PageFileStatistics {
+public abstract class AbstractRefiningIndex<O> extends AbstractIndex<O> {
/**
* Refinement counter.
*/
- private int refinements;
+ private Counter refinements;
/**
* Constructor.
@@ -62,81 +59,61 @@ public abstract class AbstractRefiningIndex<O> extends AbstractIndex<O> implemen
*/
public AbstractRefiningIndex(Relation<O> relation) {
super(relation);
+ Logging log = getLogger();
+ refinements = log.isStatistics() ? log.newCounter(this.getClass().getName() + ".refinements") : null;
}
/**
- * Initialize the index.
+ * Get the class logger.
*
- * @param relation Relation to index
- * @param ids database ids
+ * @return Logger
*/
- protected abstract void initialize(Relation<O> relation, DBIDs ids);
+ abstract public Logging getLogger();
/**
- * Refine a given object (and count the refinement!).
+ * Increment the refinement counter, if in use.
*
- * @param id Object id
- * @return refined object
+ * @param i Increment.
*/
- protected O refine(DBID id) {
- refinements++;
- return relation.get(id);
- }
-
- @Override
- public PageFileStatistics getPageFileStatistics() {
- return this;
- }
-
- @Override
- public long getReadOperations() {
- return refinements;
- }
-
- @Override
- public long getWriteOperations() {
- return 0;
- }
-
- @Override
- public void resetPageAccess() {
- refinements = 0;
+ protected void countRefinements(int i) {
+ if (refinements != null) {
+ refinements.increment(i);
+ }
}
@Override
- public PageFileStatistics getInnerStatistics() {
- return null;
+ public void logStatistics() {
+ if (refinements != null) {
+ getLogger().statistics(refinements);
+ }
}
- @Override
- public void insertAll(DBIDs ids) {
- initialize(relation, ids);
+ /**
+ * Refine a given object (and count the refinement!).
+ *
+ * @param id Object id
+ * @return refined object
+ */
+ protected O refine(DBID id) {
+ countRefinements(1);
+ return relation.get(id);
}
/**
* Range query for this index.
*
* @author Erich Schubert
+ *
+ * @apiviz.excludeSubtypes
*/
public abstract class AbstractRangeQuery<D extends Distance<D>> extends AbstractDistanceRangeQuery<O, D> {
/**
- * Hold the distance function to be used.
- */
- private DistanceQuery<O, D> distanceQuery;
-
- /**
* Constructor.
*
* @param distanceQuery Distance query object
*/
public AbstractRangeQuery(DistanceQuery<O, D> distanceQuery) {
super(distanceQuery);
- this.distanceQuery = distanceQuery;
- }
-
- @Override
- public DistanceDBIDResult<D> getRangeForDBID(DBIDRef id, D range) {
- return getRangeForObject(relation.get(id), range);
}
/**
@@ -147,7 +124,7 @@ public abstract class AbstractRefiningIndex<O> extends AbstractIndex<O> implemen
* @return Distance
*/
protected D refine(DBIDRef id, O q) {
- AbstractRefiningIndex.this.refinements++;
+ AbstractRefiningIndex.this.countRefinements(1);
return distanceQuery.distance(q, id);
}
@@ -157,7 +134,7 @@ public abstract class AbstractRefiningIndex<O> extends AbstractIndex<O> implemen
* @param c Refinements
*/
protected void incRefinements(int c) {
- AbstractRefiningIndex.this.refinements += c;
+ AbstractRefiningIndex.this.countRefinements(c);
}
}
@@ -165,6 +142,8 @@ public abstract class AbstractRefiningIndex<O> extends AbstractIndex<O> implemen
* KNN query for this index.
*
* @author Erich Schubert
+ *
+ * @apiviz.excludeSubtypes
*/
public abstract class AbstractKNNQuery<D extends Distance<D>> extends AbstractDistanceKNNQuery<O, D> {
/**
@@ -176,16 +155,6 @@ public abstract class AbstractRefiningIndex<O> extends AbstractIndex<O> implemen
super(distanceQuery);
}
- @Override
- public List<KNNResult<D>> getKNNForBulkDBIDs(ArrayDBIDs ids, int k) {
- throw new UnsupportedOperationException("Not yet implemented.");
- }
-
- @Override
- public KNNResult<D> getKNNForDBID(DBIDRef id, int k) {
- return getKNNForObject(relation.get(id), k);
- }
-
/**
* Refinement distance computation.
*
@@ -194,7 +163,7 @@ public abstract class AbstractRefiningIndex<O> extends AbstractIndex<O> implemen
* @return Distance
*/
protected D refine(DBID id, O q) {
- AbstractRefiningIndex.this.refinements++;
+ AbstractRefiningIndex.this.countRefinements(1);
return distanceQuery.distance(q, id);
}
@@ -204,7 +173,7 @@ public abstract class AbstractRefiningIndex<O> extends AbstractIndex<O> implemen
* @param c Refinements
*/
protected void incRefinements(int c) {
- AbstractRefiningIndex.this.refinements += c;
+ AbstractRefiningIndex.this.countRefinements(c);
}
}
-} \ No newline at end of file
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/DynamicIndex.java b/src/de/lmu/ifi/dbs/elki/index/DynamicIndex.java
new file mode 100644
index 00000000..53f6d5fe
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/index/DynamicIndex.java
@@ -0,0 +1,66 @@
+package de.lmu.ifi.dbs.elki.index;
+
+/*
+ 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.database.ids.DBIDRef;
+import de.lmu.ifi.dbs.elki.database.ids.DBIDs;
+
+/**
+ * Index that supports dynamic insertions and removals.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.excludeSubtypes
+ */
+public interface DynamicIndex extends Index {
+ /**
+ * Deletes the specified object from this index.
+ *
+ * @param id Object to remove
+ * @return true if this index did contain the object, false otherwise
+ */
+ public boolean delete(DBIDRef id);
+
+ /**
+ * Inserts the specified object into this index.
+ *
+ * @param id the object to be inserted
+ */
+ public void insert(DBIDRef id);
+
+ /**
+ * Deletes the specified objects from this index.
+ *
+ * @param ids Objects to remove
+ */
+ public void deleteAll(DBIDs ids);
+
+ /**
+ * Inserts the specified objects into this index. If a bulk load mode is
+ * implemented, the objects are inserted in one bulk.
+ *
+ * @param ids the objects to be inserted
+ */
+ public void insertAll(DBIDs ids);
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/Index.java b/src/de/lmu/ifi/dbs/elki/index/Index.java
index 1b866f5e..e2156a04 100644
--- a/src/de/lmu/ifi/dbs/elki/index/Index.java
+++ b/src/de/lmu/ifi/dbs/elki/index/Index.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index;
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,53 +23,30 @@ package de.lmu.ifi.dbs.elki.index;
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-import de.lmu.ifi.dbs.elki.database.ids.DBIDRef;
-import de.lmu.ifi.dbs.elki.database.ids.DBIDs;
-import de.lmu.ifi.dbs.elki.persistent.PageFileStatistics;
import de.lmu.ifi.dbs.elki.result.Result;
/**
* Interface defining the minimum requirements for all index classes.
*
+ * See also: {@link IndexFactory}, {@link DynamicIndex}
+ *
* @author Elke Achtert
*
- * @apiviz.landmark
+ * @apiviz.excludeSubtypes
*/
public interface Index extends Result {
/**
- * Get the underlying page file (or a proxy), for access counts.
- *
- * @return page file
- */
- public PageFileStatistics getPageFileStatistics();
-
- /**
- * Inserts the specified object into this index.
- *
- * @param id the object to be inserted
- */
- public void insert(DBIDRef id);
-
- /**
- * Inserts the specified objects into this index. If a bulk load mode is
- * implemented, the objects are inserted in one bulk.
- *
- * @param ids the objects to be inserted
- */
- public void insertAll(DBIDs ids);
-
- /**
- * Deletes the specified object from this index.
- *
- * @param id Object to remove
- * @return true if this index did contain the object, false otherwise
+ * Initialize the index. For static indexes, this is the moment the index is
+ * bulk loaded.
*/
- public boolean delete(DBIDRef id);
+ public void initialize();
/**
- * Deletes the specified objects from this index.
+ * Send statistics to the logger, if enabled.
*
- * @param ids Objects to remove
+ * Note: you must have set the logging level appropriately before initializing
+ * the index! Otherwise, the index might not have collected the desired
+ * statistics.
*/
- public void deleteAll(DBIDs ids);
-} \ No newline at end of file
+ public void logStatistics();
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/IndexFactory.java b/src/de/lmu/ifi/dbs/elki/index/IndexFactory.java
index ac34c53f..80ac2ef5 100644
--- a/src/de/lmu/ifi/dbs/elki/index/IndexFactory.java
+++ b/src/de/lmu/ifi/dbs/elki/index/IndexFactory.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index;
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,6 +34,7 @@ import de.lmu.ifi.dbs.elki.utilities.optionhandling.Parameterizable;
*
* @apiviz.stereotype factory,interface
* @apiviz.has Index oneway - - «create»
+ * @apiviz.excludeSubtypes
*
* @param <V> Input object type
* @param <I> Index type
diff --git a/src/de/lmu/ifi/dbs/elki/index/KNNIndex.java b/src/de/lmu/ifi/dbs/elki/index/KNNIndex.java
index 83a37f88..0384a437 100644
--- a/src/de/lmu/ifi/dbs/elki/index/KNNIndex.java
+++ b/src/de/lmu/ifi/dbs/elki/index/KNNIndex.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index;
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
@@ -33,6 +33,7 @@ import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
* @author Erich Schubert
*
* @apiviz.landmark
+ * @apiviz.excludeSubtypes
* @apiviz.has KNNQuery oneway - - «provides»
*
* @param <O> Object type
diff --git a/src/de/lmu/ifi/dbs/elki/index/PagedIndexFactory.java b/src/de/lmu/ifi/dbs/elki/index/PagedIndexFactory.java
new file mode 100644
index 00000000..211a0fb3
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/index/PagedIndexFactory.java
@@ -0,0 +1,110 @@
+package de.lmu.ifi.dbs.elki.index;
+
+/*
+ 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.persistent.ExternalizablePage;
+import de.lmu.ifi.dbs.elki.persistent.MemoryPageFileFactory;
+import de.lmu.ifi.dbs.elki.persistent.PageFile;
+import de.lmu.ifi.dbs.elki.persistent.PageFileFactory;
+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.ObjectParameter;
+
+/**
+ * Abstract base class for tree-based indexes.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.stereotype factory,interface
+ * @apiviz.excludeSubtypes
+ * @apiviz.composedOf PageFileFactory
+ *
+ * @param <O> Object type
+ * @param <I> Index type
+ */
+public abstract class PagedIndexFactory<O, I extends Index> implements IndexFactory<O, I> {
+ /**
+ * Page file factory.
+ */
+ private PageFileFactory<?> pageFileFactory;
+
+ /**
+ * Constructor.
+ *
+ * @param pageFileFactory Page file factory
+ */
+ public PagedIndexFactory(PageFileFactory<?> pageFileFactory) {
+ super();
+ this.pageFileFactory = pageFileFactory;
+ }
+
+ /**
+ * Make the page file for this index.
+ *
+ * @param <N> page type
+ * @param cls Class information
+ * @return Page file
+ */
+ protected <N extends ExternalizablePage> PageFile<N> makePageFile(Class<N> cls) {
+ @SuppressWarnings("unchecked")
+ final PageFileFactory<N> castFactory = (PageFileFactory<N>) pageFileFactory;
+ return castFactory.newPageFile(cls);
+ }
+
+ /**
+ * Parameterization class.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.exclude
+ */
+ public abstract static class Parameterizer<O> extends AbstractParameterizer {
+ /**
+ * Optional parameter that specifies the factory type of pagefile to use for
+ * the index.
+ * <p>
+ * Key: {@code -index.pagefile}
+ * </p>
+ */
+ public static final OptionID PAGEFILE_ID = new OptionID("index.pagefile", "The pagefile factory for storing the index.");
+
+ /**
+ * Page file factory.
+ */
+ protected PageFileFactory<?> pageFileFactory;
+
+ @Override
+ protected void makeOptions(Parameterization config) {
+ super.makeOptions(config);
+ ObjectParameter<PageFileFactory<?>> pffP = new ObjectParameter<>(PAGEFILE_ID, PageFileFactory.class, MemoryPageFileFactory.class);
+ if (config.grab(pffP)) {
+ pageFileFactory = pffP.instantiateClass(config);
+ }
+ }
+
+ @Override
+ protected abstract PagedIndexFactory<O, ?> makeInstance();
+ }
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/RKNNIndex.java b/src/de/lmu/ifi/dbs/elki/index/RKNNIndex.java
index 6c990cd8..5a1f0f84 100644
--- a/src/de/lmu/ifi/dbs/elki/index/RKNNIndex.java
+++ b/src/de/lmu/ifi/dbs/elki/index/RKNNIndex.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index;
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
@@ -33,6 +33,7 @@ import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
* @author Erich Schubert
*
* @apiviz.landmark
+ * @apiviz.excludeSubtypes
* @apiviz.has RKNNQuery oneway - - «provides»
*
* @param <O> Database Object type
diff --git a/src/de/lmu/ifi/dbs/elki/index/RangeIndex.java b/src/de/lmu/ifi/dbs/elki/index/RangeIndex.java
index 5d64a8fa..cc5b7493 100644
--- a/src/de/lmu/ifi/dbs/elki/index/RangeIndex.java
+++ b/src/de/lmu/ifi/dbs/elki/index/RangeIndex.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index;
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
@@ -33,6 +33,7 @@ import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
* @author Erich Schubert
*
* @apiviz.landmark
+ * @apiviz.excludeSubtypes
* @apiviz.has RangeQuery oneway - - «provides»
*
* @param <O> Database Object type
diff --git a/src/de/lmu/ifi/dbs/elki/index/lsh/InMemoryLSHIndex.java b/src/de/lmu/ifi/dbs/elki/index/lsh/InMemoryLSHIndex.java
new file mode 100644
index 00000000..c1bd43be
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/index/lsh/InMemoryLSHIndex.java
@@ -0,0 +1,418 @@
+package de.lmu.ifi.dbs.elki.index.lsh;
+
+/*
+ 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 gnu.trove.iterator.TIntObjectIterator;
+import gnu.trove.map.TIntObjectMap;
+import gnu.trove.map.hash.TIntObjectHashMap;
+
+import java.util.ArrayList;
+
+import de.lmu.ifi.dbs.elki.data.type.TypeInformation;
+import de.lmu.ifi.dbs.elki.database.ids.DBIDIter;
+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.DistanceDBIDList;
+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.generic.GenericDistanceDBIDList;
+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;
+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.distancefunction.DistanceFunction;
+import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
+import de.lmu.ifi.dbs.elki.index.AbstractRefiningIndex;
+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.index.lsh.hashfamilies.LocalitySensitiveHashFunctionFamily;
+import de.lmu.ifi.dbs.elki.index.lsh.hashfunctions.LocalitySensitiveHashFunction;
+import de.lmu.ifi.dbs.elki.logging.Logging;
+import de.lmu.ifi.dbs.elki.logging.progress.FiniteProgress;
+import de.lmu.ifi.dbs.elki.logging.statistics.LongStatistic;
+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.parameterization.Parameterization;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.IntParameter;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.ObjectParameter;
+
+/**
+ * Locality Sensitive Hashing.
+ *
+ * @author Erich Schubert
+ *
+ * @param <V> Object type to index
+ */
+public class InMemoryLSHIndex<V> implements IndexFactory<V, InMemoryLSHIndex<V>.Instance> {
+ /**
+ * Class logger
+ */
+ private static final Logging LOG = Logging.getLogger(InMemoryLSHIndex.class);
+
+ /**
+ * LSH hash function family to use.
+ */
+ LocalitySensitiveHashFunctionFamily<? super V> family;
+
+ /**
+ * Number of hash functions for each table.
+ */
+ int l;
+
+ /**
+ * Number of buckets to use.
+ */
+ int numberOfBuckets;
+
+ /**
+ * Constructor.
+ *
+ * @param family Projection family
+ * @param l Number of hash tables to use
+ * @param numberOfBuckets Number of buckets to use.
+ */
+ public InMemoryLSHIndex(LocalitySensitiveHashFunctionFamily<? super V> family, int l, int numberOfBuckets) {
+ super();
+ this.family = family;
+ this.l = l;
+ this.numberOfBuckets = numberOfBuckets;
+ }
+
+ @Override
+ public Instance instantiate(Relation<V> relation) {
+ return new Instance(relation, family.generateHashFunctions(relation, l), numberOfBuckets);
+ }
+
+ @Override
+ public TypeInformation getInputTypeRestriction() {
+ return family.getInputTypeRestriction();
+ }
+
+ /**
+ * Instance of a LSH index for a single relation.
+ *
+ * @author Erich Schubert
+ */
+ public class Instance extends AbstractRefiningIndex<V> implements KNNIndex<V>, RangeIndex<V> {
+ /**
+ * Hash functions to use.
+ */
+ ArrayList<? extends LocalitySensitiveHashFunction<? super V>> hashfunctions;
+
+ /**
+ * The actual table
+ */
+ ArrayList<TIntObjectMap<DBIDs>> hashtables;
+
+ /**
+ * Number of buckets to use.
+ */
+ private int numberOfBuckets;
+
+ /**
+ * Constructor.
+ *
+ * @param relation Relation to index.
+ * @param hashfunctions Hash functions.
+ */
+ public Instance(Relation<V> relation, ArrayList<? extends LocalitySensitiveHashFunction<? super V>> hashfunctions, int numberOfBuckets) {
+ super(relation);
+ this.hashfunctions = hashfunctions;
+ this.numberOfBuckets = numberOfBuckets;
+ }
+
+ @Override
+ public String getLongName() {
+ return "LSH index";
+ }
+
+ @Override
+ public String getShortName() {
+ return "lsh-index";
+ }
+
+ @Override
+ public void initialize() {
+ final int numhash = hashfunctions.size();
+ hashtables = new ArrayList<>(numhash);
+ for (int i = 0; i < numhash; i++) {
+ hashtables.add(new TIntObjectHashMap<DBIDs>(numberOfBuckets));
+ }
+
+ FiniteProgress progress = LOG.isVerbose() ? new FiniteProgress("Building LSH index.", relation.size(), LOG) : null;
+ int expect = Math.max(2, (int) Math.ceil(relation.size() / (double) numberOfBuckets));
+ for (DBIDIter iter = relation.getDBIDs().iter(); iter.valid(); iter.advance()) {
+ V obj = relation.get(iter);
+ for (int i = 0; i < numhash; i++) {
+ final TIntObjectMap<DBIDs> table = hashtables.get(i);
+ final LocalitySensitiveHashFunction<? super V> hashfunc = hashfunctions.get(i);
+ // Get the initial (unbounded) hash code:
+ int hash = hashfunc.hashObject(obj);
+ // Reduce to hash table size
+ int bucket = hash % numberOfBuckets;
+ DBIDs cur = table.get(bucket);
+ if (cur == null) {
+ table.put(bucket, DBIDUtil.deref(iter));
+ } else if (cur.size() > 1) {
+ ((ModifiableDBIDs) cur).add(iter);
+ } else {
+ ModifiableDBIDs newbuck = DBIDUtil.newArray(expect);
+ newbuck.addDBIDs(cur);
+ newbuck.add(iter);
+ table.put(bucket, newbuck);
+ }
+ }
+ if (progress != null) {
+ progress.incrementProcessed(LOG);
+ }
+ }
+ if (progress != null) {
+ progress.ensureCompleted(LOG);
+ }
+ if (LOG.isStatistics()) {
+ int min = Integer.MAX_VALUE, max = 0;
+ for (int i = 0; i < numhash; i++) {
+ final TIntObjectMap<DBIDs> table = hashtables.get(i);
+ for (TIntObjectIterator<DBIDs> iter = table.iterator(); iter.hasNext();) {
+ iter.advance();
+ int size = iter.value().size();
+ if (size < min) {
+ min = size;
+ }
+ if (size > max) {
+ max = size;
+ }
+ }
+ }
+ LOG.statistics(new LongStatistic(this.getClass().getName() + ".fill.min", max));
+ LOG.statistics(new LongStatistic(this.getClass().getName() + ".fill.max", min));
+ LOG.statistics(new LongStatistic(this.getClass().getName() + ".hashtables", hashtables.size()));
+ }
+ }
+
+ @Override
+ public Logging getLogger() {
+ return LOG;
+ }
+
+ @Override
+ public <D extends Distance<D>> KNNQuery<V, D> getKNNQuery(DistanceQuery<V, D> distanceQuery, Object... hints) {
+ for (Object hint : hints) {
+ if (DatabaseQuery.HINT_EXACT.equals(hint)) {
+ return null;
+ }
+ }
+ DistanceFunction<? super V, D> df = distanceQuery.getDistanceFunction();
+ if (!family.isCompatible(df)) {
+ return null;
+ }
+ return (KNNQuery<V, D>) new LSHKNNQuery<>(distanceQuery);
+ }
+
+ @Override
+ public <D extends Distance<D>> RangeQuery<V, D> getRangeQuery(DistanceQuery<V, D> distanceQuery, Object... hints) {
+ for (Object hint : hints) {
+ if (DatabaseQuery.HINT_EXACT.equals(hint)) {
+ return null;
+ }
+ }
+ DistanceFunction<? super V, D> df = distanceQuery.getDistanceFunction();
+ if (!family.isCompatible(df)) {
+ return null;
+ }
+ return (RangeQuery<V, D>) new LSHRangeQuery<>(distanceQuery);
+ }
+
+ /**
+ * Class for handling kNN queries against the LSH index.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.exclude
+ *
+ * @param <D> Distance type
+ */
+ protected class LSHKNNQuery<D extends Distance<D>> extends AbstractKNNQuery<D> {
+ /**
+ * Constructor.
+ *
+ * @param distanceQuery
+ */
+ public LSHKNNQuery(DistanceQuery<V, D> distanceQuery) {
+ super(distanceQuery);
+ }
+
+ @Override
+ public KNNList<D> getKNNForObject(V obj, int k) {
+ ModifiableDBIDs candidates = null;
+ final int numhash = hashtables.size();
+ for (int i = 0; i < numhash; i++) {
+ final TIntObjectMap<DBIDs> table = hashtables.get(i);
+ final LocalitySensitiveHashFunction<? super V> hashfunc = hashfunctions.get(i);
+ // Get the initial (unbounded) hash code:
+ int hash = hashfunc.hashObject(obj);
+ // Reduce to hash table size
+ int bucket = hash % numberOfBuckets;
+ DBIDs cur = table.get(bucket);
+ if (cur != null) {
+ if (candidates == null) {
+ candidates = DBIDUtil.newHashSet(cur.size() * numhash + k);
+ }
+ candidates.addDBIDs(cur);
+ }
+ }
+ if (candidates == null) {
+ candidates = DBIDUtil.newArray();
+ }
+
+ // Refine.
+ KNNHeap<D> heap = DBIDUtil.newHeap(distanceQuery.getDistanceFactory(), k);
+ for (DBIDIter iter = candidates.iter(); iter.valid(); iter.advance()) {
+ final D dist = distanceQuery.distance(obj, iter);
+ super.incRefinements(1);
+ heap.add(dist, iter);
+ }
+ return heap.toKNNList();
+ }
+ }
+
+ /**
+ * Class for handling kNN queries against the LSH index.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.exclude
+ *
+ * @param <D> Distance type
+ */
+ protected class LSHRangeQuery<D extends Distance<D>> extends AbstractRangeQuery<D> {
+ /**
+ * Constructor.
+ *
+ * @param distanceQuery
+ */
+ public LSHRangeQuery(DistanceQuery<V, D> distanceQuery) {
+ super(distanceQuery);
+ }
+
+ @Override
+ public DistanceDBIDList<D> getRangeForObject(V obj, D range) {
+ ModifiableDBIDs candidates = DBIDUtil.newHashSet();
+ final int numhash = hashtables.size();
+ for (int i = 0; i < numhash; i++) {
+ final TIntObjectMap<DBIDs> table = hashtables.get(i);
+ final LocalitySensitiveHashFunction<? super V> hashfunc = hashfunctions.get(i);
+ // Get the initial (unbounded) hash code:
+ int hash = hashfunc.hashObject(obj);
+ // Reduce to hash table size
+ int bucket = hash % numberOfBuckets;
+ DBIDs cur = table.get(bucket);
+ if (cur != null) {
+ candidates.addDBIDs(cur);
+ }
+ }
+
+ // Refine.
+ GenericDistanceDBIDList<D> result = new GenericDistanceDBIDList<>();
+ for (DBIDIter iter = candidates.iter(); iter.valid(); iter.advance()) {
+ final D dist = distanceQuery.distance(obj, iter);
+ super.incRefinements(1);
+ if (range.compareTo(dist) >= 0) {
+ result.add(dist, iter);
+ }
+ }
+ return result;
+ }
+ }
+ }
+
+ /**
+ * Parameterization class.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.exclude
+ */
+ public static class Parameterizer<V> extends AbstractParameterizer {
+ /**
+ * Hash function family parameter.
+ */
+ public static final OptionID FAMILY_ID = new OptionID("lsh.family", "Hash function family to use for LSH.");
+
+ /**
+ * Number of hash tables to use for LSH.
+ */
+ public static final OptionID L_ID = new OptionID("lsh.tables", "Number of hash tables to use.");
+
+ /**
+ * Number of hash tables to use for LSH.
+ */
+ public static final OptionID BUCKETS_ID = new OptionID("lsh.buckets", "Number of hash buckets to use.");
+
+ /**
+ * LSH hash function family to use.
+ */
+ LocalitySensitiveHashFunctionFamily<? super V> family;
+
+ /**
+ * Number of hash functions for each table.
+ */
+ int l;
+
+ /**
+ * Number of buckets to use.
+ */
+ int numberOfBuckets;
+
+ @Override
+ protected void makeOptions(Parameterization config) {
+ super.makeOptions(config);
+ ObjectParameter<LocalitySensitiveHashFunctionFamily<? super V>> familyP = new ObjectParameter<>(FAMILY_ID, LocalitySensitiveHashFunctionFamily.class);
+ if (config.grab(familyP)) {
+ family = familyP.instantiateClass(config);
+ }
+
+ IntParameter lP = new IntParameter(L_ID);
+ lP.addConstraint(new GreaterConstraint(0));
+ if (config.grab(lP)) {
+ l = lP.intValue();
+ }
+
+ IntParameter bucketsP = new IntParameter(BUCKETS_ID);
+ bucketsP.setDefaultValue(7919); // Primes work best, apparently.
+ bucketsP.addConstraint(new GreaterConstraint(1));
+ if (config.grab(bucketsP)) {
+ numberOfBuckets = bucketsP.intValue();
+ }
+ }
+
+ @Override
+ protected InMemoryLSHIndex<V> makeInstance() {
+ return new InMemoryLSHIndex<>(family, l, numberOfBuckets);
+ }
+ }
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/lsh/hashfamilies/AbstractHashFunctionFamily.java b/src/de/lmu/ifi/dbs/elki/index/lsh/hashfamilies/AbstractHashFunctionFamily.java
new file mode 100644
index 00000000..1ed350f0
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/index/lsh/hashfamilies/AbstractHashFunctionFamily.java
@@ -0,0 +1,164 @@
+package de.lmu.ifi.dbs.elki.index.lsh.hashfamilies;
+
+/*
+ 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.Random;
+
+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.database.relation.Relation;
+import de.lmu.ifi.dbs.elki.database.relation.RelationUtil;
+import de.lmu.ifi.dbs.elki.index.lsh.hashfunctions.LocalitySensitiveHashFunction;
+import de.lmu.ifi.dbs.elki.index.lsh.hashfunctions.MultipleProjectionsLocalitySensitiveHashFunction;
+import de.lmu.ifi.dbs.elki.math.linearalgebra.randomprojections.RandomProjectionFamily;
+import de.lmu.ifi.dbs.elki.utilities.RandomFactory;
+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.parameterization.Parameterization;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.IntParameter;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.RandomParameter;
+
+/**
+ * Abstract base class for projection based hash functions.
+ *
+ * @author Erich Schubert
+ */
+public abstract class AbstractHashFunctionFamily implements LocalitySensitiveHashFunctionFamily<NumberVector<?>> {
+ /**
+ * Random generator to use.
+ */
+ protected RandomFactory random;
+
+ /**
+ * Projection family to use.
+ */
+ protected RandomProjectionFamily proj;
+
+ /**
+ * Width of each bin.
+ */
+ protected double width;
+
+ /**
+ * The number of projections to use for each hash function.
+ */
+ protected int k;
+
+ /**
+ * Constructor.
+ *
+ * @param random Random generator
+ * @param proj Projection family
+ * @param width Bin width
+ * @param k Number of projections for each hash function.
+ */
+ public AbstractHashFunctionFamily(RandomFactory random, RandomProjectionFamily proj, double width, int k) {
+ super();
+ this.random = random;
+ this.proj = proj;
+ this.width = width;
+ this.k = k;
+ }
+
+ @Override
+ public ArrayList<? extends LocalitySensitiveHashFunction<? super NumberVector<?>>> generateHashFunctions(Relation<? extends NumberVector<?>> relation, int l) {
+ int dim = RelationUtil.dimensionality(relation);
+ ArrayList<LocalitySensitiveHashFunction<? super NumberVector<?>>> ps = new ArrayList<>(l);
+ final Random rnd = random.getRandom();
+ for (int i = 0; i < l; i++) {
+ RandomProjectionFamily.Projection mat = proj.generateProjection(dim, k);
+ ps.add(new MultipleProjectionsLocalitySensitiveHashFunction(mat, width, rnd));
+ }
+ return ps;
+ }
+
+ @Override
+ public TypeInformation getInputTypeRestriction() {
+ return TypeUtil.NUMBER_VECTOR_FIELD;
+ }
+
+ /**
+ * Parameterization class.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.exclude
+ */
+ public abstract static class Parameterizer extends AbstractParameterizer {
+ /**
+ * Parameter for fixing the random seed.
+ */
+ public static final OptionID RANDOM_ID = new OptionID("lsh.projection.random", "Random seed for generating the projections.");
+
+ /**
+ * Parameter for choosing the bin width.
+ */
+ public static final OptionID WIDTH_ID = new OptionID("lsh.projection.width", "Bin width for random projections.");
+
+ /**
+ * Number of projections to use in each hash function.
+ */
+ public static final OptionID NUMPROJ_ID = new OptionID("lsh.projection.projections", "Number of projections to use for each hash function.");
+
+ /**
+ * Random generator to use.
+ */
+ RandomFactory random;
+
+ /**
+ * Width of each bin.
+ */
+ double width;
+
+ /**
+ * The number of projections to use for each hash function.
+ */
+ int k;
+
+ @Override
+ protected void makeOptions(Parameterization config) {
+ super.makeOptions(config);
+ RandomParameter randP = new RandomParameter(RANDOM_ID, RandomFactory.DEFAULT);
+ if (config.grab(randP)) {
+ random = randP.getValue();
+ }
+
+ DoubleParameter widthP = new DoubleParameter(WIDTH_ID);
+ widthP.addConstraint(new GreaterConstraint(0.0));
+ if (config.grab(widthP)) {
+ width = widthP.doubleValue();
+ }
+
+ IntParameter lP = new IntParameter(NUMPROJ_ID);
+ lP.addConstraint(new GreaterConstraint(0));
+ if (config.grab(lP)) {
+ k = lP.intValue();
+ }
+ }
+ }
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/lsh/hashfamilies/EuclideanHashFunctionFamily.java b/src/de/lmu/ifi/dbs/elki/index/lsh/hashfamilies/EuclideanHashFunctionFamily.java
new file mode 100644
index 00000000..0aa983e5
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/index/lsh/hashfamilies/EuclideanHashFunctionFamily.java
@@ -0,0 +1,74 @@
+package de.lmu.ifi.dbs.elki.index.lsh.hashfamilies;
+
+/*
+ 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.distancefunction.minkowski.EuclideanDistanceFunction;
+import de.lmu.ifi.dbs.elki.math.linearalgebra.randomprojections.GaussianRandomProjectionFamily;
+import de.lmu.ifi.dbs.elki.utilities.RandomFactory;
+import de.lmu.ifi.dbs.elki.utilities.documentation.Reference;
+
+/**
+ * 2-stable hash function family for Euclidean distances.
+ *
+ * Reference:
+ * <p>
+ * Locality-sensitive hashing scheme based on p-stable distributions<br />
+ * M. Datar and N. Immorlica and P. Indyk and V. S. Mirrokni<br />
+ * Proc. 20th annual symposium on Computational geometry<br />
+ * </p>
+ *
+ * @author Erich Schubert
+ */
+@Reference(authors = "M. Datar and N. Immorlica and P. Indyk and V. S. Mirrokni", title = "Locality-sensitive hashing scheme based on p-stable distributions", booktitle = "Proc. 20th annual symposium on Computational geometry", url = "http://dx.doi.org/10.1145/997817.997857")
+public class EuclideanHashFunctionFamily extends AbstractHashFunctionFamily {
+ /**
+ * Constructor.
+ *
+ * @param random Random generator
+ * @param width Bin width
+ * @param k Number of projections to combine.
+ */
+ public EuclideanHashFunctionFamily(RandomFactory random, double width, int k) {
+ super(random, new GaussianRandomProjectionFamily(random), width, k);
+ }
+
+ @Override
+ public boolean isCompatible(DistanceFunction<?, ?> df) {
+ return EuclideanDistanceFunction.class.isInstance(df);
+ }
+
+ /**
+ * Parameterization class.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.exclude
+ */
+ public static class Parameterizer extends AbstractHashFunctionFamily.Parameterizer {
+ @Override
+ protected EuclideanHashFunctionFamily makeInstance() {
+ return new EuclideanHashFunctionFamily(random, width, k);
+ }
+ }
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/lsh/hashfamilies/LocalitySensitiveHashFunctionFamily.java b/src/de/lmu/ifi/dbs/elki/index/lsh/hashfamilies/LocalitySensitiveHashFunctionFamily.java
new file mode 100644
index 00000000..4d3468bb
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/index/lsh/hashfamilies/LocalitySensitiveHashFunctionFamily.java
@@ -0,0 +1,65 @@
+package de.lmu.ifi.dbs.elki.index.lsh.hashfamilies;
+
+/*
+ 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 de.lmu.ifi.dbs.elki.data.type.TypeInformation;
+import de.lmu.ifi.dbs.elki.database.relation.Relation;
+import de.lmu.ifi.dbs.elki.distance.distancefunction.DistanceFunction;
+import de.lmu.ifi.dbs.elki.index.lsh.hashfunctions.LocalitySensitiveHashFunction;
+
+/**
+ * LSH family of hash functions.
+ *
+ * @author Erich Schubert
+ *
+ * @param <V> Object type
+ */
+public interface LocalitySensitiveHashFunctionFamily<V> {
+ /**
+ * Get the input type information.
+ *
+ * @return Input type information.
+ */
+ TypeInformation getInputTypeRestriction();
+
+ /**
+ * Generate hash functions for the given relation.
+ *
+ * @param relation Relation to index
+ * @param k number of hash functions per table.
+ * @return Family of hash functions
+ */
+ ArrayList<? extends LocalitySensitiveHashFunction<? super V>> generateHashFunctions(Relation<? extends V> relation, int k);
+
+ /**
+ * Check whether the given distance function can be accelerated using this
+ * hash family.
+ *
+ * @param df Distance function.
+ * @return {@code true} when appropriate.
+ */
+ boolean isCompatible(DistanceFunction<?, ?> df);
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/lsh/hashfamilies/ManhattanHashFunctionFamily.java b/src/de/lmu/ifi/dbs/elki/index/lsh/hashfamilies/ManhattanHashFunctionFamily.java
new file mode 100644
index 00000000..a117c44c
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/index/lsh/hashfamilies/ManhattanHashFunctionFamily.java
@@ -0,0 +1,76 @@
+package de.lmu.ifi.dbs.elki.index.lsh.hashfamilies;
+
+/*
+ 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.distancefunction.minkowski.ManhattanDistanceFunction;
+import de.lmu.ifi.dbs.elki.math.linearalgebra.randomprojections.CauchyRandomProjectionFamily;
+import de.lmu.ifi.dbs.elki.utilities.RandomFactory;
+import de.lmu.ifi.dbs.elki.utilities.documentation.Reference;
+
+/**
+ * 2-stable hash function family for Euclidean distances.
+ *
+ * Reference:
+ * <p>
+ * Locality-sensitive hashing scheme based on p-stable distributions<br />
+ * M. Datar and N. Immorlica and P. Indyk and V. S. Mirrokni<br />
+ * Proc. 20th annual symposium on Computational geometry<br />
+ * </p>
+ *
+ * @author Erich Schubert
+ */
+@Reference(authors = "M. Datar and N. Immorlica and P. Indyk and V. S. Mirrokni", title = "Locality-sensitive hashing scheme based on p-stable distributions", booktitle = "Proc. 20th annual symposium on Computational geometry", url = "http://dx.doi.org/10.1145/997817.997857")
+public class ManhattanHashFunctionFamily extends AbstractHashFunctionFamily {
+ /**
+ * Constructor.
+ *
+ * @param random Random generator
+ * @param width Bin width
+ * @param k Number of projections to combine.
+ */
+ public ManhattanHashFunctionFamily(RandomFactory random, double width, int k) {
+ super(random, new CauchyRandomProjectionFamily(random), width, k);
+ }
+
+ @Override
+ public boolean isCompatible(DistanceFunction<?, ?> df) {
+ // TODO: also allow HistogramIntersectionDistance?
+ return ManhattanDistanceFunction.class.isInstance(df);
+ }
+
+ /**
+ * Parameterization class.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.exclude
+ */
+ public static class Parameterizer extends AbstractHashFunctionFamily.Parameterizer {
+ @Override
+ protected ManhattanHashFunctionFamily makeInstance() {
+ return new ManhattanHashFunctionFamily(random, width, k);
+ }
+ }
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/lsh/hashfamilies/package-info.java b/src/de/lmu/ifi/dbs/elki/index/lsh/hashfamilies/package-info.java
new file mode 100644
index 00000000..5afa0489
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/index/lsh/hashfamilies/package-info.java
@@ -0,0 +1,27 @@
+/**
+ * <p>Hash function families for LSH.</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.lsh.hashfamilies;
+
diff --git a/src/de/lmu/ifi/dbs/elki/index/lsh/hashfunctions/LocalitySensitiveHashFunction.java b/src/de/lmu/ifi/dbs/elki/index/lsh/hashfunctions/LocalitySensitiveHashFunction.java
new file mode 100644
index 00000000..c43f60a5
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/index/lsh/hashfunctions/LocalitySensitiveHashFunction.java
@@ -0,0 +1,41 @@
+package de.lmu.ifi.dbs.elki.index.lsh.hashfunctions;
+
+/*
+ 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/>.
+ */
+
+/**
+ * Hash functions as used by locality sensitive hashing.
+ *
+ * @author Erich Schubert
+ *
+ * @param <V> Data type to hash.
+ */
+public interface LocalitySensitiveHashFunction<V> {
+ /**
+ * Compute the hash value of an object
+ *
+ * @param obj Object to hash
+ * @return Hash value
+ */
+ int hashObject(V obj);
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/lsh/hashfunctions/MultipleProjectionsLocalitySensitiveHashFunction.java b/src/de/lmu/ifi/dbs/elki/index/lsh/hashfunctions/MultipleProjectionsLocalitySensitiveHashFunction.java
new file mode 100644
index 00000000..59f31b0a
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/index/lsh/hashfunctions/MultipleProjectionsLocalitySensitiveHashFunction.java
@@ -0,0 +1,119 @@
+package de.lmu.ifi.dbs.elki.index.lsh.hashfunctions;
+
+/*
+ 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.data.NumberVector;
+import de.lmu.ifi.dbs.elki.math.linearalgebra.randomprojections.RandomProjectionFamily;
+import de.lmu.ifi.dbs.elki.utilities.documentation.Reference;
+
+/**
+ * LSH hash function for vector space data. Depending on the choice of random
+ * vectors, it can be appropriate for Manhattan and Euclidean distances.
+ *
+ * Reference:
+ * <p>
+ * Locality-sensitive hashing scheme based on p-stable distributions<br />
+ * M. Datar and N. Immorlica and P. Indyk and V. S. Mirrokni<br />
+ * Proc. 20th annual symposium on Computational geometry<br />
+ * </p>
+ *
+ * @author Erich Schubert
+ */
+@Reference(authors = "M. Datar and N. Immorlica and P. Indyk and V. S. Mirrokni", title = "Locality-sensitive hashing scheme based on p-stable distributions", booktitle = "Proc. 20th annual symposium on Computational geometry", url = "http://dx.doi.org/10.1145/997817.997857")
+public class MultipleProjectionsLocalitySensitiveHashFunction implements LocalitySensitiveHashFunction<NumberVector<?>> {
+ /**
+ * Projection matrix.
+ */
+ RandomProjectionFamily.Projection projection;
+
+ /**
+ * Shift offset.
+ */
+ double[] shift;
+
+ /**
+ * Scaling factor.
+ */
+ double width;
+
+ /**
+ * Random numbers for mixing the hash codes of the individual functions
+ */
+ int[] randoms1;
+
+ /**
+ * Constructor.
+ *
+ * @param projection Projection vectors
+ * @param width Width of bins
+ * @param rnd Random number generator
+ */
+ public MultipleProjectionsLocalitySensitiveHashFunction(RandomProjectionFamily.Projection projection, double width, Random rnd) {
+ super();
+ this.projection = projection;
+ this.width = width;
+ // Generate random shifts:
+ final int num = projection.getOutputDimensionality();
+ this.shift = new double[num];
+ this.randoms1 = new int[num];
+ for (int i = 0; i < num; i++) {
+ shift[i] = rnd.nextDouble() * width;
+ // Produce a large random number; although 7FFFFFFF would likely be large
+ // enough, we try to stick to the suggested approach (which assumes
+ // unsigned integers).
+ randoms1[i] = (rnd.nextInt(0x7FFFFFFD) << 1) + rnd.nextInt(1) + 1;
+ }
+ }
+
+ @Override
+ public int hashObject(NumberVector<?> vec) {
+ long t1sum = 0L;
+ // Project the vector:
+ final double[] proj = projection.project(vec);
+ for (int i = 0; i < shift.length; i++) {
+ int ai = (int) Math.floor((proj[i] + shift[i]) / width);
+ t1sum += randoms1[i] * (long) ai;
+ }
+ return fastModPrime(t1sum);
+ }
+
+ /**
+ * Fast modulo operation for the largest unsigned integer prime.
+ *
+ * @param data Long input
+ * @return {@code data % (2^32 - 5)}.
+ */
+ public static int fastModPrime(long data) {
+ // Mix high and low 32 bit:
+ int high = (int) (data >>> 32);
+ // Use fast multiplication with 5 for high:
+ int alpha = ((int) data) + (high << 2 + high);
+ // Note that in Java, PRIME will be negative.
+ if (alpha < 0 && alpha > -5) {
+ alpha = alpha + 5;
+ }
+ return alpha;
+ }
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/lsh/hashfunctions/package-info.java b/src/de/lmu/ifi/dbs/elki/index/lsh/hashfunctions/package-info.java
new file mode 100644
index 00000000..e30550f6
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/index/lsh/hashfunctions/package-info.java
@@ -0,0 +1,27 @@
+/**
+ * <p>Hash functions for LSH</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.lsh.hashfunctions;
+
diff --git a/src/de/lmu/ifi/dbs/elki/index/lsh/package-info.java b/src/de/lmu/ifi/dbs/elki/index/lsh/package-info.java
new file mode 100644
index 00000000..78eb59f7
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/index/lsh/package-info.java
@@ -0,0 +1,27 @@
+/**
+ * <p>Locality Sensitive Hashing</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.lsh;
+
diff --git a/src/de/lmu/ifi/dbs/elki/index/package-info.java b/src/de/lmu/ifi/dbs/elki/index/package-info.java
index 003a25bb..f985629d 100644
--- a/src/de/lmu/ifi/dbs/elki/index/package-info.java
+++ b/src/de/lmu/ifi/dbs/elki/index/package-info.java
@@ -8,7 +8,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/preprocessed/AbstractPreprocessorIndex.java b/src/de/lmu/ifi/dbs/elki/index/preprocessed/AbstractPreprocessorIndex.java
index 95d0878d..720efc56 100644
--- a/src/de/lmu/ifi/dbs/elki/index/preprocessed/AbstractPreprocessorIndex.java
+++ b/src/de/lmu/ifi/dbs/elki/index/preprocessed/AbstractPreprocessorIndex.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.preprocessed;
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/preprocessed/LocalProjectionIndex.java b/src/de/lmu/ifi/dbs/elki/index/preprocessed/LocalProjectionIndex.java
index 7373646f..0229c4e5 100644
--- a/src/de/lmu/ifi/dbs/elki/index/preprocessed/LocalProjectionIndex.java
+++ b/src/de/lmu/ifi/dbs/elki/index/preprocessed/LocalProjectionIndex.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.preprocessed;
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/preprocessed/knn/AbstractMaterializeKNNPreprocessor.java b/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/AbstractMaterializeKNNPreprocessor.java
index 7a64f294..570bd660 100644
--- a/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/AbstractMaterializeKNNPreprocessor.java
+++ b/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/AbstractMaterializeKNNPreprocessor.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.preprocessed.knn;
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,14 +28,13 @@ import de.lmu.ifi.dbs.elki.database.datastore.DataStoreFactory;
import de.lmu.ifi.dbs.elki.database.datastore.DataStoreUtil;
import de.lmu.ifi.dbs.elki.database.datastore.WritableDataStore;
import de.lmu.ifi.dbs.elki.database.ids.DBIDRef;
-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.distance.DistanceQuery;
import de.lmu.ifi.dbs.elki.database.query.knn.KNNQuery;
import de.lmu.ifi.dbs.elki.database.query.knn.PreprocessorKNNQuery;
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.distancefunction.EuclideanDistanceFunction;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.KNNResult;
+import de.lmu.ifi.dbs.elki.distance.distancefunction.minkowski.EuclideanDistanceFunction;
import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
import de.lmu.ifi.dbs.elki.index.IndexFactory;
import de.lmu.ifi.dbs.elki.index.KNNIndex;
@@ -56,7 +55,7 @@ import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.ObjectParameter;
* @param <D> Distance type
* @param <T> Result type
*/
-public abstract class AbstractMaterializeKNNPreprocessor<O, D extends Distance<D>, T extends KNNResult<D>> extends AbstractPreprocessorIndex<O, T> implements KNNIndex<O> {
+public abstract class AbstractMaterializeKNNPreprocessor<O, D extends Distance<D>, T extends KNNList<D>> extends AbstractPreprocessorIndex<O, T> implements KNNIndex<O> {
/**
* The query k value.
*/
@@ -124,7 +123,7 @@ public abstract class AbstractMaterializeKNNPreprocessor<O, D extends Distance<D
* @param id Object ID
* @return Neighbors
*/
- public KNNResult<D> get(DBIDRef id) {
+ public KNNList<D> get(DBIDRef id) {
if(storage == null) {
if(getLogger().isDebugging()) {
getLogger().debug("Running kNN preprocessor: " + this.getClass());
@@ -138,14 +137,14 @@ public abstract class AbstractMaterializeKNNPreprocessor<O, D extends Distance<D
* Create the default storage.
*/
void createStorage() {
- WritableDataStore<T> s = DataStoreUtil.makeStorage(relation.getDBIDs(), DataStoreFactory.HINT_HOT, KNNResult.class);
+ WritableDataStore<T> s = DataStoreUtil.makeStorage(relation.getDBIDs(), DataStoreFactory.HINT_HOT, KNNList.class);
storage = s;
}
@Override
- public void insertAll(DBIDs ids) {
+ public void initialize() {
if(storage == null) {
- if(ids.size() > 0) {
+ if(relation.size() > 0) {
preprocess();
}
}
@@ -171,7 +170,7 @@ public abstract class AbstractMaterializeKNNPreprocessor<O, D extends Distance<D
}
// To make compilers happy:
AbstractMaterializeKNNPreprocessor<?, ?, ?> tmp = this;
- return new PreprocessorKNNQuery<O, S, KNNResult<S>>(relation, (AbstractMaterializeKNNPreprocessor<O, S, KNNResult<S>>) tmp);
+ return new PreprocessorKNNQuery<>(relation, (AbstractMaterializeKNNPreprocessor<O, S, KNNList<S>>) tmp);
}
/**
@@ -186,7 +185,7 @@ public abstract class AbstractMaterializeKNNPreprocessor<O, D extends Distance<D
* @param <O> The object type
* @param <D> The distance type
*/
- public abstract static class Factory<O, D extends Distance<D>, T extends KNNResult<D>> implements IndexFactory<O, KNNIndex<O>> {
+ public abstract static class Factory<O, D extends Distance<D>, T extends KNNList<D>> implements IndexFactory<O, KNNIndex<O>> {
/**
* Parameter to specify the number of nearest neighbors of an object to be
* materialized. must be an integer greater than 1.
@@ -287,7 +286,7 @@ public abstract class AbstractMaterializeKNNPreprocessor<O, D extends Distance<D
}
// distance function
- final ObjectParameter<DistanceFunction<? super O, D>> distanceFunctionP = new ObjectParameter<DistanceFunction<? super O, D>>(DISTANCE_FUNCTION_ID, DistanceFunction.class, EuclideanDistanceFunction.class);
+ final ObjectParameter<DistanceFunction<? super O, D>> distanceFunctionP = new ObjectParameter<>(DISTANCE_FUNCTION_ID, DistanceFunction.class, EuclideanDistanceFunction.class);
if(config.grab(distanceFunctionP)) {
distanceFunction = distanceFunctionP.instantiateClass(config);
}
diff --git a/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/CachedDoubleDistanceKNNPreprocessor.java b/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/CachedDoubleDistanceKNNPreprocessor.java
new file mode 100644
index 00000000..c36948be
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/CachedDoubleDistanceKNNPreprocessor.java
@@ -0,0 +1,205 @@
+package de.lmu.ifi.dbs.elki.index.preprocessed.knn;
+
+/*
+ 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.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileChannel.MapMode;
+import java.util.ArrayList;
+
+import de.lmu.ifi.dbs.elki.application.cache.CacheDoubleDistanceKNNLists;
+import de.lmu.ifi.dbs.elki.database.ids.DBIDIter;
+import de.lmu.ifi.dbs.elki.database.ids.DBIDUtil;
+import de.lmu.ifi.dbs.elki.database.ids.distance.DoubleDistanceDBIDPair;
+import de.lmu.ifi.dbs.elki.database.ids.distance.DoubleDistanceKNNList;
+import de.lmu.ifi.dbs.elki.database.ids.generic.DoubleDistanceDBIDPairKNNList;
+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.DoubleDistance;
+import de.lmu.ifi.dbs.elki.logging.Logging;
+import de.lmu.ifi.dbs.elki.persistent.ByteArrayUtil;
+import de.lmu.ifi.dbs.elki.utilities.exceptions.AbortException;
+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.FileParameter;
+
+/**
+ * Preprocessor that loads an existing cached kNN result.
+ *
+ * @author Erich Schubert
+ *
+ * @param <O> Object type
+ */
+public class CachedDoubleDistanceKNNPreprocessor<O> extends AbstractMaterializeKNNPreprocessor<O, DoubleDistance, DoubleDistanceKNNList> {
+ /**
+ * File to load.
+ */
+ private File filename;
+
+ /**
+ * Constructor.
+ *
+ * @param relation Relation to index
+ * @param distanceFunction Distance function
+ * @param k K
+ * @param file File to load
+ */
+ public CachedDoubleDistanceKNNPreprocessor(Relation<O> relation, DistanceFunction<? super O, DoubleDistance> distanceFunction, int k, File file) {
+ super(relation, distanceFunction, k);
+ this.filename = file;
+ }
+
+ /**
+ * Class logger.
+ */
+ private static final Logging LOG = Logging.getLogger(CachedDoubleDistanceKNNPreprocessor.class);
+
+ @Override
+ protected void preprocess() {
+ createStorage();
+ // open file.
+ try (RandomAccessFile file = new RandomAccessFile(filename, "rw");
+ FileChannel channel = file.getChannel()) {
+ // check magic header
+ int header = file.readInt();
+ if (header != CacheDoubleDistanceKNNLists.KNN_CACHE_MAGIC) {
+ throw new AbortException("Cache magic number does not match.");
+ }
+ MappedByteBuffer buffer = channel.map(MapMode.READ_ONLY, 4, file.length() - 4);
+ for (DBIDIter iter = relation.iterDBIDs(); iter.valid(); iter.advance()) {
+ int dbid = ByteArrayUtil.readUnsignedVarint(buffer);
+ int nnsize = ByteArrayUtil.readUnsignedVarint(buffer);
+ if (nnsize < k) {
+ throw new AbortException("kNN cache contains fewer than k objects!");
+ }
+ ArrayList<DoubleDistanceDBIDPair> col = new ArrayList<>(nnsize);
+ for (int i = 0; i < nnsize; i++) {
+ int nid = ByteArrayUtil.readUnsignedVarint(buffer);
+ double dist = buffer.getDouble();
+ col.add(DBIDUtil.newDistancePair(dist, DBIDUtil.importInteger(nid)));
+ }
+ storage.put(DBIDUtil.importInteger(dbid), new DoubleDistanceDBIDPairKNNList(col, nnsize));
+ }
+ if (buffer.hasRemaining()) {
+ LOG.warning("kNN cache has " + buffer.remaining() + " bytes remaining!");
+ }
+ } catch (IOException e) {
+ throw new AbortException("I/O error in loading kNN cache: " + e.getMessage(), e);
+ }
+ }
+
+ @Override
+ protected Logging getLogger() {
+ return LOG;
+ }
+
+ @Override
+ public String getLongName() {
+ return "cached-knn";
+ }
+
+ @Override
+ public String getShortName() {
+ return "cached-knn";
+ }
+
+ @Override
+ public void logStatistics() {
+ // No statistics to log.
+ }
+
+ /**
+ * The parameterizable factory.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.landmark
+ * @apiviz.stereotype factory
+ * @apiviz.uses MaterializeKNNPreprocessor oneway - - «create»
+ *
+ * @param <O> The object type
+ */
+ public static class Factory<O> extends AbstractMaterializeKNNPreprocessor.Factory<O, DoubleDistance, DoubleDistanceKNNList> {
+ /**
+ * Filename to load.
+ */
+ private File filename;
+
+ /**
+ * Index factory.
+ *
+ * @param k k parameter
+ * @param distanceFunction distance function
+ * @param filename Cache file
+ */
+ public Factory(int k, DistanceFunction<? super O, DoubleDistance> distanceFunction, File filename) {
+ super(k, distanceFunction);
+ this.filename = filename;
+ }
+
+ @Override
+ public CachedDoubleDistanceKNNPreprocessor<O> instantiate(Relation<O> relation) {
+ CachedDoubleDistanceKNNPreprocessor<O> instance = new CachedDoubleDistanceKNNPreprocessor<>(relation, distanceFunction, k, filename);
+ return instance;
+ }
+
+ /**
+ * Parameterization class.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.exclude
+ */
+ public static class Parameterizer<O> extends AbstractMaterializeKNNPreprocessor.Factory.Parameterizer<O, DoubleDistance> {
+ /**
+ * Option ID for the kNN file.
+ */
+ public static final OptionID CACHE_ID = new OptionID("external.knnfile", "Filename with the precomputed k nearest neighbors.");
+
+ /**
+ * Filename to load.
+ */
+ private File filename;
+
+ @Override
+ protected void makeOptions(Parameterization config) {
+ super.makeOptions(config);
+
+ // Input file parameter
+ final FileParameter cpar = new FileParameter(CACHE_ID, FileParameter.FileType.INPUT_FILE);
+ if (config.grab(cpar)) {
+ filename = cpar.getValue();
+ }
+ }
+
+ @Override
+ protected Factory<O> makeInstance() {
+ return new Factory<>(k, distanceFunction, filename);
+ }
+ }
+ }
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/KNNChangeEvent.java b/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/KNNChangeEvent.java
index 6c677fda..275c1c97 100644
--- a/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/KNNChangeEvent.java
+++ b/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/KNNChangeEvent.java
@@ -3,7 +3,7 @@ package de.lmu.ifi.dbs.elki.index.preprocessed.knn;
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/preprocessed/knn/KNNJoinMaterializeKNNPreprocessor.java b/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/KNNJoinMaterializeKNNPreprocessor.java
index bb947348..44100604 100644
--- a/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/KNNJoinMaterializeKNNPreprocessor.java
+++ b/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/KNNJoinMaterializeKNNPreprocessor.java
@@ -2,9 +2,9 @@ package de.lmu.ifi.dbs.elki.index.preprocessed.knn;
import de.lmu.ifi.dbs.elki.algorithm.KNNJoin;
import de.lmu.ifi.dbs.elki.data.NumberVector;
+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.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.index.tree.spatial.SpatialEntry;
import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.rstar.RStarTreeNode;
@@ -14,7 +14,7 @@ import de.lmu.ifi.dbs.elki.logging.Logging;
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 @@ import de.lmu.ifi.dbs.elki.logging.Logging;
* @param <V> vector type
* @param <D> distance type
*/
-public class KNNJoinMaterializeKNNPreprocessor<V extends NumberVector<?>, D extends Distance<D>> extends AbstractMaterializeKNNPreprocessor<V, D, KNNResult<D>> {
+public class KNNJoinMaterializeKNNPreprocessor<V extends NumberVector<?>, D extends Distance<D>> extends AbstractMaterializeKNNPreprocessor<V, D, KNNList<D>> {
/**
* Logging class.
*/
@@ -80,6 +80,11 @@ public class KNNJoinMaterializeKNNPreprocessor<V extends NumberVector<?>, D exte
return "knn-join";
}
+ @Override
+ public void logStatistics() {
+ // No statistics to log.
+ }
+
/**
* The parameterizable factory.
*
@@ -92,7 +97,7 @@ public class KNNJoinMaterializeKNNPreprocessor<V extends NumberVector<?>, D exte
* @param <O> The object type
* @param <D> The distance type
*/
- public static class Factory<O extends NumberVector<?>, D extends Distance<D>> extends AbstractMaterializeKNNPreprocessor.Factory<O, D, KNNResult<D>> {
+ public static class Factory<O extends NumberVector<?>, D extends Distance<D>> extends AbstractMaterializeKNNPreprocessor.Factory<O, D, KNNList<D>> {
/**
* Constructor.
*
@@ -105,7 +110,7 @@ public class KNNJoinMaterializeKNNPreprocessor<V extends NumberVector<?>, D exte
@Override
public KNNJoinMaterializeKNNPreprocessor<O, D> instantiate(Relation<O> relation) {
- return new KNNJoinMaterializeKNNPreprocessor<O, D>(relation, distanceFunction, k);
+ return new KNNJoinMaterializeKNNPreprocessor<>(relation, distanceFunction, k);
}
/**
@@ -121,7 +126,7 @@ public class KNNJoinMaterializeKNNPreprocessor<V extends NumberVector<?>, D exte
public static class Parameterizer<O extends NumberVector<?>, D extends Distance<D>> extends AbstractMaterializeKNNPreprocessor.Factory.Parameterizer<O, D> {
@Override
protected KNNJoinMaterializeKNNPreprocessor.Factory<O, D> makeInstance() {
- return new KNNJoinMaterializeKNNPreprocessor.Factory<O, D>(k, distanceFunction);
+ return new KNNJoinMaterializeKNNPreprocessor.Factory<>(k, distanceFunction);
}
}
}
diff --git a/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/KNNListener.java b/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/KNNListener.java
index 4a726ad0..8c78cdc0 100644
--- a/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/KNNListener.java
+++ b/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/KNNListener.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.preprocessed.knn;
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/preprocessed/knn/MaterializeKNNAndRKNNPreprocessor.java b/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/MaterializeKNNAndRKNNPreprocessor.java
index b52b15af..06375d51 100644
--- a/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/MaterializeKNNAndRKNNPreprocessor.java
+++ b/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/MaterializeKNNAndRKNNPreprocessor.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.preprocessed.knn;
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,22 +40,21 @@ 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.DistanceDBIDPair;
-import de.lmu.ifi.dbs.elki.database.ids.DoubleDistanceDBIDPair;
import de.lmu.ifi.dbs.elki.database.ids.HashSetModifiableDBIDs;
import de.lmu.ifi.dbs.elki.database.ids.SetDBIDs;
+import de.lmu.ifi.dbs.elki.database.ids.distance.DistanceDBIDListIter;
+import de.lmu.ifi.dbs.elki.database.ids.distance.DistanceDBIDPair;
+import de.lmu.ifi.dbs.elki.database.ids.distance.DoubleDistanceDBIDPair;
+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.generic.GenericDistanceDBIDList;
import de.lmu.ifi.dbs.elki.database.query.distance.DistanceQuery;
import de.lmu.ifi.dbs.elki.database.query.rknn.PreprocessorRKNNQuery;
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.DistanceUtil;
import de.lmu.ifi.dbs.elki.distance.distancefunction.DistanceFunction;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.DistanceDBIDResultIter;
import de.lmu.ifi.dbs.elki.distance.distanceresultlist.DistanceDBIDResultUtil;
-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.distancevalue.Distance;
import de.lmu.ifi.dbs.elki.index.RKNNIndex;
import de.lmu.ifi.dbs.elki.logging.Logging;
@@ -119,20 +118,20 @@ public class MaterializeKNNAndRKNNPreprocessor<O, D extends Distance<D>> extends
*/
private void materializeKNNAndRKNNs(ArrayDBIDs ids, FiniteProgress progress) {
// add an empty list to each rknn
- Comparator<DistanceDBIDPair<D>> comp = DistanceDBIDResultUtil.distanceComparator();
+ Comparator<? super DistanceDBIDPair<D>> comp = DistanceDBIDResultUtil.distanceComparator();
for(DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) {
if(materialized_RkNN.get(iter) == null) {
- materialized_RkNN.put(iter, new TreeSet<DistanceDBIDPair<D>>(comp));
+ materialized_RkNN.put(iter, new TreeSet<>(comp));
}
}
// knn query
- List<? extends KNNResult<D>> kNNList = knnQuery.getKNNForBulkDBIDs(ids, k);
+ List<? extends KNNList<D>> kNNList = knnQuery.getKNNForBulkDBIDs(ids, k);
int i = 0;
for(DBIDIter id = ids.iter(); id.valid(); id.advance(), i++) {
- KNNResult<D> kNNs = kNNList.get(i);
+ KNNList<D> kNNs = kNNList.get(i);
storage.put(id, kNNs);
- for(DistanceDBIDResultIter<D> iter = kNNs.iter(); iter.valid(); iter.advance()) {
+ for(DistanceDBIDListIter<D> iter = kNNs.iter(); iter.valid(); iter.advance()) {
TreeSet<DistanceDBIDPair<D>> rknns = materialized_RkNN.get(iter);
rknns.add(makePair(iter, id));
}
@@ -147,7 +146,7 @@ public class MaterializeKNNAndRKNNPreprocessor<O, D extends Distance<D>> extends
}
@SuppressWarnings("unchecked")
- private DistanceDBIDPair<D> makePair(DistanceDBIDResultIter<D> iter, DBIDIter id) {
+ private DistanceDBIDPair<D> makePair(DistanceDBIDListIter<D> iter, DBIDIter id) {
if(doubleOptimize) {
return (DistanceDBIDPair<D>) DBIDUtil.newDistancePair(((DoubleDistanceDBIDPair) iter.getDistancePair()).doubleDistance(), id);
}
@@ -194,7 +193,7 @@ public class MaterializeKNNAndRKNNPreprocessor<O, D extends Distance<D>> extends
ArrayModifiableDBIDs rkNN_ids = DBIDUtil.newArray();
DBIDs oldids = DBIDUtil.difference(relation.getDBIDs(), ids);
for(DBIDIter id = oldids.iter(); id.valid(); id.advance()) {
- KNNResult<D> oldkNNs = storage.get(id);
+ KNNList<D> oldkNNs = storage.get(id);
D knnDist = oldkNNs.getKNNDistance();
// look for new kNNs
KNNHeap<D> heap = null;
@@ -203,21 +202,21 @@ public class MaterializeKNNAndRKNNPreprocessor<O, D extends Distance<D>> extends
if(dist.compareTo(knnDist) <= 0) {
// New id changes the kNNs of oldid.
if(heap == null) {
- heap = KNNUtil.newHeap(oldkNNs);
+ heap = DBIDUtil.newHeap(oldkNNs);
}
heap.add(dist, newid);
}
}
// kNNs for oldid have changed:
if(heap != null) {
- KNNResult<D> newkNNs = heap.toKNNList();
+ KNNList<D> newkNNs = heap.toKNNList();
storage.put(id, newkNNs);
// get the difference
int i = 0;
int j = 0;
- GenericDistanceDBIDList<D> added = new GenericDistanceDBIDList<D>();
- GenericDistanceDBIDList<D> removed = new GenericDistanceDBIDList<D>();
+ GenericDistanceDBIDList<D> added = new GenericDistanceDBIDList<>();
+ GenericDistanceDBIDList<D> removed = new GenericDistanceDBIDList<>();
// TODO: use iterators.
while(i < oldkNNs.size() && j < newkNNs.size()) {
DistanceDBIDPair<D> drp1 = oldkNNs.get(i);
@@ -241,12 +240,12 @@ public class MaterializeKNNAndRKNNPreprocessor<O, D extends Distance<D>> extends
}
}
// add new RkNN
- for(DistanceDBIDResultIter<D> newnn = added.iter(); newnn.valid(); newnn.advance()) {
+ for(DistanceDBIDListIter<D> newnn = added.iter(); newnn.valid(); newnn.advance()) {
TreeSet<DistanceDBIDPair<D>> rknns = materialized_RkNN.get(newnn);
rknns.add(makePair(newnn, id));
}
// remove old RkNN
- for(DistanceDBIDResultIter<D> oldnn = removed.iter(); oldnn.valid(); oldnn.advance()) {
+ for(DistanceDBIDListIter<D> oldnn = removed.iter(); oldnn.valid(); oldnn.advance()) {
TreeSet<DistanceDBIDPair<D>> rknns = materialized_RkNN.get(oldnn);
rknns.remove(makePair(oldnn, id));
}
@@ -267,8 +266,8 @@ public class MaterializeKNNAndRKNNPreprocessor<O, D extends Distance<D>> extends
stepprog.beginStep(1, "New deletions ocurred, remove their materialized kNNs and RkNNs.", getLogger());
}
// Temporary storage of removed lists
- List<KNNResult<D>> kNNs = new ArrayList<KNNResult<D>>(ids.size());
- List<TreeSet<DistanceDBIDPair<D>>> rkNNs = new ArrayList<TreeSet<DistanceDBIDPair<D>>>(ids.size());
+ List<KNNList<D>> kNNs = new ArrayList<>(ids.size());
+ List<TreeSet<DistanceDBIDPair<D>>> rkNNs = new ArrayList<>(ids.size());
for(DBIDIter iter = aids.iter(); iter.valid(); iter.advance()) {
kNNs.add(storage.get(iter));
storage.delete(iter);
@@ -285,11 +284,11 @@ public class MaterializeKNNAndRKNNPreprocessor<O, D extends Distance<D>> extends
}
// Recompute the kNN for affected objects (in rkNN lists)
{
- List<? extends KNNResult<D>> kNNList = knnQuery.getKNNForBulkDBIDs(rkNN_ids, k);
+ List<? extends KNNList<D>> kNNList = knnQuery.getKNNForBulkDBIDs(rkNN_ids, k);
int i = 0;
for(DBIDIter reknn = rkNN_ids.iter(); reknn.valid(); reknn.advance(), i++) {
storage.put(reknn, kNNList.get(i));
- for(DistanceDBIDResultIter<D> it = kNNList.get(i).iter(); it.valid(); it.advance()) {
+ for(DistanceDBIDListIter<D> it = kNNList.get(i).iter(); it.valid(); it.advance()) {
materialized_RkNN.get(it).add(makePair(it, reknn));
}
}
@@ -325,9 +324,9 @@ public class MaterializeKNNAndRKNNPreprocessor<O, D extends Distance<D>> extends
* @param remove the ids to remove
* @return the DBIDs in the given collection
*/
- protected ArrayDBIDs affectedkNN(List<? extends KNNResult<D>> extraxt, DBIDs remove) {
+ protected ArrayDBIDs affectedkNN(List<? extends KNNList<D>> extraxt, DBIDs remove) {
HashSetModifiableDBIDs ids = DBIDUtil.newHashSet();
- for(KNNResult<D> drps : extraxt) {
+ for(KNNList<D> drps : extraxt) {
for(DBIDIter iter = drps.iter(); iter.valid(); iter.advance()) {
ids.add(iter);
}
@@ -362,7 +361,7 @@ public class MaterializeKNNAndRKNNPreprocessor<O, D extends Distance<D>> extends
* @param id the query id
* @return the kNNs
*/
- public KNNResult<D> getKNN(DBID id) {
+ public KNNList<D> getKNN(DBID id) {
return storage.get(id);
}
@@ -377,7 +376,7 @@ public class MaterializeKNNAndRKNNPreprocessor<O, D extends Distance<D>> extends
if(rKNN == null) {
return null;
}
- GenericDistanceDBIDList<D> ret = new GenericDistanceDBIDList<D>(rKNN.size());
+ GenericDistanceDBIDList<D> ret = new GenericDistanceDBIDList<>(rKNN.size());
for(DistanceDBIDPair<D> pair : rKNN) {
ret.add(pair);
}
@@ -400,7 +399,7 @@ public class MaterializeKNNAndRKNNPreprocessor<O, D extends Distance<D>> extends
break;
}
}
- return new PreprocessorRKNNQuery<O, S>(relation, (MaterializeKNNAndRKNNPreprocessor<O, S>) this);
+ return new PreprocessorRKNNQuery<>(relation, (MaterializeKNNAndRKNNPreprocessor<O, S>) this);
}
@Override
@@ -439,7 +438,7 @@ public class MaterializeKNNAndRKNNPreprocessor<O, D extends Distance<D>> extends
@Override
public MaterializeKNNAndRKNNPreprocessor<O, D> instantiate(Relation<O> relation) {
- MaterializeKNNAndRKNNPreprocessor<O, D> instance = new MaterializeKNNAndRKNNPreprocessor<O, D>(relation, distanceFunction, k);
+ MaterializeKNNAndRKNNPreprocessor<O, D> instance = new MaterializeKNNAndRKNNPreprocessor<>(relation, distanceFunction, k);
return instance;
}
@@ -453,7 +452,7 @@ public class MaterializeKNNAndRKNNPreprocessor<O, D extends Distance<D>> extends
public static class Parameterizer<O, D extends Distance<D>> extends MaterializeKNNPreprocessor.Factory.Parameterizer<O, D> {
@Override
protected Factory<O, D> makeInstance() {
- return new Factory<O, D>(k, distanceFunction);
+ return new Factory<>(k, distanceFunction);
}
}
}
diff --git a/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/MaterializeKNNPreprocessor.java b/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/MaterializeKNNPreprocessor.java
index f792833e..3f79d748 100644
--- a/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/MaterializeKNNPreprocessor.java
+++ b/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/MaterializeKNNPreprocessor.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.preprocessed.knn;
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,17 +34,19 @@ 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.SetDBIDs;
+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.DatabaseQuery;
import de.lmu.ifi.dbs.elki.database.query.knn.KNNQuery;
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.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.DynamicIndex;
import de.lmu.ifi.dbs.elki.logging.Logging;
import de.lmu.ifi.dbs.elki.logging.progress.FiniteProgress;
import de.lmu.ifi.dbs.elki.logging.progress.StepProgress;
+import de.lmu.ifi.dbs.elki.logging.statistics.Duration;
+import de.lmu.ifi.dbs.elki.logging.statistics.LongStatistic;
import de.lmu.ifi.dbs.elki.utilities.documentation.Description;
import de.lmu.ifi.dbs.elki.utilities.documentation.Title;
@@ -52,7 +54,7 @@ import de.lmu.ifi.dbs.elki.utilities.documentation.Title;
* A preprocessor for annotation of the k nearest neighbors (and their
* distances) to each database object.
*
- * Used for example by {@link de.lmu.ifi.dbs.elki.algorithm.outlier.LOF}.
+ * Used for example by {@link de.lmu.ifi.dbs.elki.algorithm.outlier.lof.LOF}.
*
* @author Erich Schubert
*
@@ -65,7 +67,7 @@ import de.lmu.ifi.dbs.elki.utilities.documentation.Title;
*/
@Title("Materialize kNN Neighborhood preprocessor")
@Description("Materializes the k nearest neighbors of objects of a database.")
-public class MaterializeKNNPreprocessor<O, D extends Distance<D>> extends AbstractMaterializeKNNPreprocessor<O, D, KNNResult<D>> {
+public class MaterializeKNNPreprocessor<O, D extends Distance<D>> extends AbstractMaterializeKNNPreprocessor<O, D, KNNList<D>> implements DynamicIndex {
/**
* Logger to use.
*/
@@ -108,35 +110,44 @@ public class MaterializeKNNPreprocessor<O, D extends Distance<D>> extends Abstra
createStorage();
ArrayDBIDs ids = DBIDUtil.ensureArray(relation.getDBIDs());
- FiniteProgress progress = getLogger().isVerbose() ? new FiniteProgress("Materializing k nearest neighbors (k=" + k + ")", ids.size(), getLogger()) : null;
+ if (LOG.isStatistics()) {
+ LOG.statistics(new LongStatistic(this.getClass().getName() + ".k", k));
+ }
+ Duration duration = LOG.isStatistics() ? LOG.newDuration(this.getClass().getName() + ".precomputation-time") : null;
+ if (duration != null) {
+ duration.begin();
+ }
+ FiniteProgress progress = getLogger().isVerbose() ? new FiniteProgress("Materializing k nearest neighbors (k=" + k + ")", ids.size(), getLogger()) : null;
// Try bulk
- List<? extends KNNResult<D>> kNNList = null;
- if(usebulk) {
+ List<? extends KNNList<D>> kNNList = null;
+ if (usebulk) {
kNNList = knnQuery.getKNNForBulkDBIDs(ids, k);
- if(kNNList != null) {
+ if (kNNList != null) {
int i = 0;
- for(DBIDIter id = ids.iter(); id.valid(); id.advance(), i++) {
+ for (DBIDIter id = ids.iter(); id.valid(); id.advance(), i++) {
storage.put(id, kNNList.get(i));
- if(progress != null) {
+ if (progress != null) {
progress.incrementProcessed(getLogger());
}
}
}
- }
- else {
- for(DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) {
- KNNResult<D> knn = knnQuery.getKNNForDBID(iter, k);
+ } else {
+ for (DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) {
+ KNNList<D> knn = knnQuery.getKNNForDBID(iter, k);
storage.put(iter, knn);
- if(progress != null) {
+ if (progress != null) {
progress.incrementProcessed(getLogger());
}
}
}
-
- if(progress != null) {
+ if (progress != null) {
progress.ensureCompleted(getLogger());
}
+ if (duration != null) {
+ duration.end();
+ LOG.statistics(duration);
+ }
}
@Override
@@ -146,10 +157,9 @@ public class MaterializeKNNPreprocessor<O, D extends Distance<D>> extends Abstra
@Override
public void insertAll(DBIDs ids) {
- if(storage == null && ids.size() > 0) {
+ if (storage == null && ids.size() > 0) {
preprocess();
- }
- else {
+ } else {
objectsInserted(ids);
}
}
@@ -176,30 +186,30 @@ public class MaterializeKNNPreprocessor<O, D extends Distance<D>> extends Abstra
ArrayDBIDs aids = DBIDUtil.ensureArray(ids);
// materialize the new kNNs
- if(stepprog != null) {
+ if (stepprog != null) {
stepprog.beginStep(1, "New insertions ocurred, materialize their new kNNs.", getLogger());
}
// Bulk-query kNNs
- List<? extends KNNResult<D>> kNNList = knnQuery.getKNNForBulkDBIDs(aids, k);
+ List<? extends KNNList<D>> kNNList = knnQuery.getKNNForBulkDBIDs(aids, k);
// Store in storage
DBIDIter iter = aids.iter();
- for(int i = 0; i < aids.size(); i++, iter.advance()) {
+ for (int i = 0; i < aids.size(); i++, iter.advance()) {
storage.put(iter, kNNList.get(i));
}
// update the affected kNNs
- if(stepprog != null) {
+ if (stepprog != null) {
stepprog.beginStep(2, "New insertions ocurred, update the affected kNNs.", getLogger());
}
ArrayDBIDs rkNN_ids = updateKNNsAfterInsertion(ids);
// inform listener
- if(stepprog != null) {
+ if (stepprog != null) {
stepprog.beginStep(3, "New insertions ocurred, inform listeners.", getLogger());
}
fireKNNsInserted(ids, rkNN_ids);
- if(stepprog != null) {
+ if (stepprog != null) {
stepprog.setCompleted(getLogger());
}
}
@@ -215,21 +225,21 @@ public class MaterializeKNNPreprocessor<O, D extends Distance<D>> extends Abstra
private ArrayDBIDs updateKNNsAfterInsertion(DBIDs ids) {
ArrayModifiableDBIDs rkNN_ids = DBIDUtil.newArray();
DBIDs oldids = DBIDUtil.difference(relation.getDBIDs(), ids);
- for(DBIDIter iter = oldids.iter(); iter.valid(); iter.advance()) {
- KNNResult<D> kNNs = storage.get(iter);
+ for (DBIDIter iter = oldids.iter(); iter.valid(); iter.advance()) {
+ KNNList<D> kNNs = storage.get(iter);
D knnDist = kNNs.get(kNNs.size() - 1).getDistance();
// look for new kNNs
KNNHeap<D> heap = null;
- for(DBIDIter iter2 = ids.iter(); iter2.valid(); iter2.advance()) {
+ for (DBIDIter iter2 = ids.iter(); iter2.valid(); iter2.advance()) {
D dist = distanceQuery.distance(iter, iter2);
- if(dist.compareTo(knnDist) <= 0) {
- if(heap == null) {
- heap = KNNUtil.newHeap(kNNs);
+ if (dist.compareTo(knnDist) <= 0) {
+ if (heap == null) {
+ heap = DBIDUtil.newHeap(kNNs);
}
heap.add(dist, iter2);
}
}
- if(heap != null) {
+ if (heap != null) {
kNNs = heap.toKNNList();
storage.put(iter, kNNs);
rkNN_ids.add(iter);
@@ -248,10 +258,10 @@ public class MaterializeKNNPreprocessor<O, D extends Distance<D>> extends Abstra
private ArrayDBIDs updateKNNsAfterDeletion(DBIDs ids) {
SetDBIDs idsSet = DBIDUtil.ensureSet(ids);
ArrayModifiableDBIDs rkNN_ids = DBIDUtil.newArray();
- for(DBIDIter iditer = relation.iterDBIDs(); iditer.valid(); iditer.advance()) {
- KNNResult<D> kNNs = storage.get(iditer);
- for(DBIDIter it = kNNs.iter(); it.valid(); it.advance()) {
- if(idsSet.contains(it)) {
+ for (DBIDIter iditer = relation.iterDBIDs(); iditer.valid(); iditer.advance()) {
+ KNNList<D> kNNs = storage.get(iditer);
+ for (DBIDIter it = kNNs.iter(); it.valid(); it.advance()) {
+ if (idsSet.contains(it)) {
rkNN_ids.add(iditer);
break;
}
@@ -259,9 +269,9 @@ public class MaterializeKNNPreprocessor<O, D extends Distance<D>> extends Abstra
}
// update the kNNs of the RkNNs
- List<? extends KNNResult<D>> kNNList = knnQuery.getKNNForBulkDBIDs(rkNN_ids, k);
+ List<? extends KNNList<D>> kNNList = knnQuery.getKNNForBulkDBIDs(rkNN_ids, k);
DBIDIter iter = rkNN_ids.iter();
- for(int i = 0; i < rkNN_ids.size(); i++, iter.advance()) {
+ for (int i = 0; i < rkNN_ids.size(); i++, iter.advance()) {
storage.put(iter, kNNList.get(i));
}
@@ -278,26 +288,26 @@ public class MaterializeKNNPreprocessor<O, D extends Distance<D>> extends Abstra
StepProgress stepprog = getLogger().isVerbose() ? new StepProgress(3) : null;
// delete the materialized (old) kNNs
- if(stepprog != null) {
+ if (stepprog != null) {
stepprog.beginStep(1, "New deletions ocurred, remove their materialized kNNs.", getLogger());
}
- for(DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) {
+ for (DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) {
storage.delete(iter);
}
// update the affected kNNs
- if(stepprog != null) {
+ if (stepprog != null) {
stepprog.beginStep(2, "New deletions ocurred, update the affected kNNs.", getLogger());
}
ArrayDBIDs rkNN_ids = updateKNNsAfterDeletion(ids);
// inform listener
- if(stepprog != null) {
+ if (stepprog != null) {
stepprog.beginStep(3, "New deletions ocurred, inform listeners.", getLogger());
}
fireKNNsRemoved(ids, rkNN_ids);
- if(stepprog != null) {
+ if (stepprog != null) {
stepprog.ensureCompleted(getLogger());
}
}
@@ -314,8 +324,8 @@ public class MaterializeKNNPreprocessor<O, D extends Distance<D>> extends Abstra
protected void fireKNNsInserted(DBIDs insertions, DBIDs updates) {
KNNChangeEvent e = new KNNChangeEvent(this, KNNChangeEvent.Type.INSERT, insertions, updates);
Object[] listeners = listenerList.getListenerList();
- for(int i = listeners.length - 2; i >= 0; i -= 2) {
- if(listeners[i] == KNNListener.class) {
+ for (int i = listeners.length - 2; i >= 0; i -= 2) {
+ if (listeners[i] == KNNListener.class) {
((KNNListener) listeners[i + 1]).kNNsChanged(e);
}
}
@@ -332,8 +342,8 @@ public class MaterializeKNNPreprocessor<O, D extends Distance<D>> extends Abstra
protected void fireKNNsRemoved(DBIDs removals, DBIDs updates) {
KNNChangeEvent e = new KNNChangeEvent(this, KNNChangeEvent.Type.DELETE, removals, updates);
Object[] listeners = listenerList.getListenerList();
- for(int i = listeners.length - 2; i >= 0; i -= 2) {
- if(listeners[i] == KNNListener.class) {
+ for (int i = listeners.length - 2; i >= 0; i -= 2) {
+ if (listeners[i] == KNNListener.class) {
((KNNListener) listeners[i + 1]).kNNsChanged(e);
}
}
@@ -374,6 +384,11 @@ public class MaterializeKNNPreprocessor<O, D extends Distance<D>> extends Abstra
}
@Override
+ public void logStatistics() {
+ // TODO: can we log some sensible statistics?
+ }
+
+ @Override
protected Logging getLogger() {
return LOG;
}
@@ -390,7 +405,7 @@ public class MaterializeKNNPreprocessor<O, D extends Distance<D>> extends Abstra
* @param <O> The object type
* @param <D> The distance type
*/
- public static class Factory<O, D extends Distance<D>> extends AbstractMaterializeKNNPreprocessor.Factory<O, D, KNNResult<D>> {
+ public static class Factory<O, D extends Distance<D>> extends AbstractMaterializeKNNPreprocessor.Factory<O, D, KNNList<D>> {
/**
* Index factory.
*
@@ -403,7 +418,7 @@ public class MaterializeKNNPreprocessor<O, D extends Distance<D>> extends Abstra
@Override
public MaterializeKNNPreprocessor<O, D> instantiate(Relation<O> relation) {
- MaterializeKNNPreprocessor<O, D> instance = new MaterializeKNNPreprocessor<O, D>(relation, distanceFunction, k);
+ MaterializeKNNPreprocessor<O, D> instance = new MaterializeKNNPreprocessor<>(relation, distanceFunction, k);
return instance;
}
@@ -417,8 +432,8 @@ public class MaterializeKNNPreprocessor<O, D extends Distance<D>> extends Abstra
public static class Parameterizer<O, D extends Distance<D>> extends AbstractMaterializeKNNPreprocessor.Factory.Parameterizer<O, D> {
@Override
protected Factory<O, D> makeInstance() {
- return new Factory<O, D>(k, distanceFunction);
+ return new Factory<>(k, distanceFunction);
}
}
}
-} \ No newline at end of file
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/MetricalIndexApproximationMaterializeKNNPreprocessor.java b/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/MetricalIndexApproximationMaterializeKNNPreprocessor.java
index b82e9c77..1f17e6b4 100644
--- a/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/MetricalIndexApproximationMaterializeKNNPreprocessor.java
+++ b/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/MetricalIndexApproximationMaterializeKNNPreprocessor.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.preprocessed.knn;
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,12 +32,11 @@ import de.lmu.ifi.dbs.elki.database.ids.ArrayModifiableDBIDs;
import de.lmu.ifi.dbs.elki.database.ids.DBIDIter;
import de.lmu.ifi.dbs.elki.database.ids.DBIDPair;
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.relation.Relation;
import de.lmu.ifi.dbs.elki.distance.distancefunction.DistanceFunction;
-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.LeafEntry;
import de.lmu.ifi.dbs.elki.index.tree.Node;
@@ -55,7 +54,7 @@ import de.lmu.ifi.dbs.elki.utilities.documentation.Title;
* A preprocessor for annotation of the k nearest neighbors (and their
* distances) to each database object.
*
- * Used for example by {@link de.lmu.ifi.dbs.elki.algorithm.outlier.LOF}.
+ * Used for example by {@link de.lmu.ifi.dbs.elki.algorithm.outlier.lof.LOF}.
*
* TODO correct handling of datastore events
*
@@ -70,7 +69,7 @@ import de.lmu.ifi.dbs.elki.utilities.documentation.Title;
*/
@Title("Spatial Approximation Materialize kNN Preprocessor")
@Description("Caterializes the (approximate) k nearest neighbors of objects of a database using a spatial approximation.")
-public class MetricalIndexApproximationMaterializeKNNPreprocessor<O extends NumberVector<?>, D extends Distance<D>, N extends Node<E>, E extends MTreeEntry<D>> extends AbstractMaterializeKNNPreprocessor<O, D, KNNResult<D>> {
+public class MetricalIndexApproximationMaterializeKNNPreprocessor<O extends NumberVector<?>, D extends Distance<D>, N extends Node<E>, E extends MTreeEntry> extends AbstractMaterializeKNNPreprocessor<O, D, KNNList<D>> {
/**
* Logger to use
*/
@@ -114,9 +113,9 @@ public class MetricalIndexApproximationMaterializeKNNPreprocessor<O extends Numb
for(int i = 0; i < size; i++) {
ids.add(((LeafEntry) node.getEntry(i)).getDBID());
}
- HashMap<DBIDPair, D> cache = new HashMap<DBIDPair, D>((size * size * 3) >> 2);
+ HashMap<DBIDPair, D> cache = new HashMap<>((size * size * 3) >> 2);
for(DBIDIter id = ids.iter(); id.valid(); id.advance()) {
- KNNHeap<D> kNN = KNNUtil.newHeap(distanceFunction, k);
+ KNNHeap<D> kNN = DBIDUtil.newHeap(distanceFunction.getDistanceFactory(), k);
for(DBIDIter id2 = ids.iter(); id2.valid(); id2.advance()) {
DBIDPair key = DBIDUtil.newPair(id, id2);
D d = cache.remove(key);
@@ -190,6 +189,11 @@ public class MetricalIndexApproximationMaterializeKNNPreprocessor<O extends Numb
return LOG;
}
+ @Override
+ public void logStatistics() {
+ // No statistics to log.
+ }
+
/**
* The parameterizable factory.
*
@@ -204,7 +208,7 @@ public class MetricalIndexApproximationMaterializeKNNPreprocessor<O extends Numb
* @param <N> the type of spatial nodes in the spatial index
* @param <E> the type of spatial entries in the spatial index
*/
- public static class Factory<O extends NumberVector<?>, D extends Distance<D>, N extends Node<E>, E extends MTreeEntry<D>> extends AbstractMaterializeKNNPreprocessor.Factory<O, D, KNNResult<D>> {
+ public static class Factory<O extends NumberVector<?>, D extends Distance<D>, N extends Node<E>, E extends MTreeEntry> extends AbstractMaterializeKNNPreprocessor.Factory<O, D, KNNList<D>> {
/**
* Constructor.
*
@@ -217,7 +221,7 @@ public class MetricalIndexApproximationMaterializeKNNPreprocessor<O extends Numb
@Override
public MetricalIndexApproximationMaterializeKNNPreprocessor<O, D, N, E> instantiate(Relation<O> relation) {
- MetricalIndexApproximationMaterializeKNNPreprocessor<O, D, N, E> instance = new MetricalIndexApproximationMaterializeKNNPreprocessor<O, D, N, E>(relation, distanceFunction, k);
+ MetricalIndexApproximationMaterializeKNNPreprocessor<O, D, N, E> instance = new MetricalIndexApproximationMaterializeKNNPreprocessor<>(relation, distanceFunction, k);
return instance;
}
@@ -228,10 +232,10 @@ public class MetricalIndexApproximationMaterializeKNNPreprocessor<O extends Numb
*
* @apiviz.exclude
*/
- public static class Parameterizer<O extends NumberVector<?>, D extends Distance<D>, N extends Node<E>, E extends MTreeEntry<D>> extends AbstractMaterializeKNNPreprocessor.Factory.Parameterizer<O, D> {
+ public static class Parameterizer<O extends NumberVector<?>, D extends Distance<D>, N extends Node<E>, E extends MTreeEntry> extends AbstractMaterializeKNNPreprocessor.Factory.Parameterizer<O, D> {
@Override
protected Factory<O, D, N, E> makeInstance() {
- return new Factory<O, D, N, E>(k, distanceFunction);
+ return new Factory<>(k, distanceFunction);
}
}
}
diff --git a/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/PartitionApproximationMaterializeKNNPreprocessor.java b/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/PartitionApproximationMaterializeKNNPreprocessor.java
index 353e227d..1d2a2a1b 100644
--- a/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/PartitionApproximationMaterializeKNNPreprocessor.java
+++ b/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/PartitionApproximationMaterializeKNNPreprocessor.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.preprocessed.knn;
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,12 +32,11 @@ import de.lmu.ifi.dbs.elki.database.ids.DBIDArrayIter;
import de.lmu.ifi.dbs.elki.database.ids.DBIDIter;
import de.lmu.ifi.dbs.elki.database.ids.DBIDPair;
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.relation.Relation;
import de.lmu.ifi.dbs.elki.distance.distancefunction.DistanceFunction;
-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.logging.Logging;
import de.lmu.ifi.dbs.elki.logging.progress.FiniteProgress;
@@ -55,7 +54,7 @@ import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.RandomParameter;
* A preprocessor for annotation of the k nearest neighbors (and their
* distances) to each database object.
*
- * Used for example by {@link de.lmu.ifi.dbs.elki.algorithm.outlier.LOF}.
+ * Used for example by {@link de.lmu.ifi.dbs.elki.algorithm.outlier.lof.LOF}.
*
* @author Erich Schubert
*
@@ -64,7 +63,7 @@ import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.RandomParameter;
*/
@Title("Partitioning Approximate kNN Preprocessor")
@Description("Caterializes the (approximate) k nearest neighbors of objects of a database by partitioning and only computing kNN within each partition.")
-public class PartitionApproximationMaterializeKNNPreprocessor<O, D extends Distance<D>> extends AbstractMaterializeKNNPreprocessor<O, D, KNNResult<D>> {
+public class PartitionApproximationMaterializeKNNPreprocessor<O, D extends Distance<D>> extends AbstractMaterializeKNNPreprocessor<O, D, KNNList<D>> {
/**
* Logger to use
*/
@@ -98,7 +97,7 @@ public class PartitionApproximationMaterializeKNNPreprocessor<O, D extends Dista
@Override
protected void preprocess() {
DistanceQuery<O, D> distanceQuery = relation.getDatabase().getDistanceQuery(relation, distanceFunction);
- storage = DataStoreUtil.makeStorage(relation.getDBIDs(), DataStoreFactory.HINT_STATIC, KNNResult.class);
+ storage = DataStoreUtil.makeStorage(relation.getDBIDs(), DataStoreFactory.HINT_STATIC, KNNList.class);
MeanVariance ksize = new MeanVariance();
if (LOG.isVerbose()) {
LOG.verbose("Approximating nearest neighbor lists to database objects");
@@ -126,9 +125,9 @@ public class PartitionApproximationMaterializeKNNPreprocessor<O, D extends Dista
ids.add(iter);
}
}
- HashMap<DBIDPair, D> cache = new HashMap<DBIDPair, D>((size * size * 3) >> 3);
+ HashMap<DBIDPair, D> cache = new HashMap<>((size * size * 3) >> 3);
for (DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) {
- KNNHeap<D> kNN = KNNUtil.newHeap(distanceFunction, k);
+ KNNHeap<D> kNN = DBIDUtil.newHeap(distanceFunction.getDistanceFactory(), k);
for (DBIDIter iter2 = ids.iter(); iter2.valid(); iter2.advance()) {
DBIDPair key = DBIDUtil.newPair(iter, iter2);
D d = cache.remove(key);
@@ -179,6 +178,11 @@ public class PartitionApproximationMaterializeKNNPreprocessor<O, D extends Dista
return "random-partition-knn";
}
+ @Override
+ public void logStatistics() {
+ // No statistics to log.
+ }
+
/**
* The parameterizable factory.
*
@@ -191,7 +195,7 @@ public class PartitionApproximationMaterializeKNNPreprocessor<O, D extends Dista
* @param <O> The object type
* @param <D> The distance type
*/
- public static class Factory<O, D extends Distance<D>> extends AbstractMaterializeKNNPreprocessor.Factory<O, D, KNNResult<D>> {
+ public static class Factory<O, D extends Distance<D>> extends AbstractMaterializeKNNPreprocessor.Factory<O, D, KNNList<D>> {
/**
* The number of partitions to use
*/
@@ -218,7 +222,7 @@ public class PartitionApproximationMaterializeKNNPreprocessor<O, D extends Dista
@Override
public PartitionApproximationMaterializeKNNPreprocessor<O, D> instantiate(Relation<O> relation) {
- PartitionApproximationMaterializeKNNPreprocessor<O, D> instance = new PartitionApproximationMaterializeKNNPreprocessor<O, D>(relation, distanceFunction, k, partitions, rnd);
+ PartitionApproximationMaterializeKNNPreprocessor<O, D> instance = new PartitionApproximationMaterializeKNNPreprocessor<>(relation, distanceFunction, k, partitions, rnd);
return instance;
}
@@ -273,7 +277,7 @@ public class PartitionApproximationMaterializeKNNPreprocessor<O, D extends Dista
@Override
protected Factory<O, D> makeInstance() {
- return new Factory<O, D>(k, distanceFunction, partitions, rnd);
+ return new Factory<>(k, distanceFunction, partitions, rnd);
}
}
}
diff --git a/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/RandomSampleKNNPreprocessor.java b/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/RandomSampleKNNPreprocessor.java
index 592a1206..cb3f1638 100644
--- a/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/RandomSampleKNNPreprocessor.java
+++ b/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/RandomSampleKNNPreprocessor.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.preprocessed.knn;
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,16 +29,16 @@ import de.lmu.ifi.dbs.elki.database.ids.ArrayDBIDs;
import de.lmu.ifi.dbs.elki.database.ids.DBIDIter;
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.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.relation.Relation;
import de.lmu.ifi.dbs.elki.distance.distancefunction.DistanceFunction;
-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.logging.Logging;
import de.lmu.ifi.dbs.elki.logging.progress.FiniteProgress;
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.OptionID;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.constraints.GreaterConstraint;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.constraints.LessConstraint;
@@ -49,12 +49,22 @@ import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.RandomParameter;
/**
* Class that computed the kNN only on a random sample.
*
+ * Used in:
+ * <p>
+ * Subsampling for Efficient and Effective Unsupervised Outlier Detection
+ * Ensembles<br />
+ * A. Zimek and M. Gaudet and R. J. G. B. Campello and J. Sander<br />
+ * In: Proc. 19th ACM SIGKDD International Conference on Knowledge Discovery and
+ * Data Mining, KDD '13
+ * </p>
+ *
* @author Erich Schubert
*
* @param <O> Object type
* @param <D> Distance type
*/
-public class RandomSampleKNNPreprocessor<O, D extends Distance<D>> extends AbstractMaterializeKNNPreprocessor<O, D, KNNResult<D>> {
+@Reference(title = "Subsampling for Efficient and Effective Unsupervised Outlier Detection Ensembles", authors = "A. Zimek and M. Gaudet and R. J. G. B. Campello and J. Sander", booktitle = "Proc. 19th ACM SIGKDD International Conference on Knowledge Discovery and Data Mining, KDD '13")
+public class RandomSampleKNNPreprocessor<O, D extends Distance<D>> extends AbstractMaterializeKNNPreprocessor<O, D, KNNList<D>> {
/**
* Logger
*/
@@ -88,14 +98,14 @@ public class RandomSampleKNNPreprocessor<O, D extends Distance<D>> extends Abstr
@Override
protected void preprocess() {
DistanceQuery<O, D> distanceQuery = relation.getDatabase().getDistanceQuery(relation, distanceFunction);
- storage = DataStoreUtil.makeStorage(relation.getDBIDs(), DataStoreFactory.HINT_STATIC, KNNResult.class);
+ storage = DataStoreUtil.makeStorage(relation.getDBIDs(), DataStoreFactory.HINT_STATIC, KNNList.class);
FiniteProgress progress = getLogger().isVerbose() ? new FiniteProgress("Materializing random-sample k nearest neighbors (k=" + k + ")", relation.size(), getLogger()) : null;
final ArrayDBIDs ids = DBIDUtil.ensureArray(relation.getDBIDs());
final int samplesize = (int) (ids.size() * share);
for (DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) {
- KNNHeap<D> kNN = KNNUtil.newHeap(distanceFunction, k);
+ KNNHeap<D> kNN = DBIDUtil.newHeap(distanceFunction.getDistanceFactory(), k);
DBIDs rsamp = DBIDUtil.randomSample(ids, samplesize, rnd);
for (DBIDIter iter2 = rsamp.iter(); iter2.valid(); iter2.advance()) {
@@ -129,6 +139,11 @@ public class RandomSampleKNNPreprocessor<O, D extends Distance<D>> extends Abstr
return "random-sample-knn";
}
+ @Override
+ public void logStatistics() {
+ // No statistics to log.
+ }
+
/**
* The parameterizable factory.
*
@@ -141,7 +156,7 @@ public class RandomSampleKNNPreprocessor<O, D extends Distance<D>> extends Abstr
* @param <O> The object type
* @param <D> The distance type
*/
- public static class Factory<O, D extends Distance<D>> extends AbstractMaterializeKNNPreprocessor.Factory<O, D, KNNResult<D>> {
+ public static class Factory<O, D extends Distance<D>> extends AbstractMaterializeKNNPreprocessor.Factory<O, D, KNNList<D>> {
/**
* Relative share of objects to get
*/
@@ -168,7 +183,7 @@ public class RandomSampleKNNPreprocessor<O, D extends Distance<D>> extends Abstr
@Override
public RandomSampleKNNPreprocessor<O, D> instantiate(Relation<O> relation) {
- return new RandomSampleKNNPreprocessor<O, D>(relation, distanceFunction, k, share, rnd);
+ return new RandomSampleKNNPreprocessor<>(relation, distanceFunction, k, share, rnd);
}
/**
@@ -228,7 +243,7 @@ public class RandomSampleKNNPreprocessor<O, D extends Distance<D>> extends Abstr
@Override
protected RandomSampleKNNPreprocessor.Factory<O, D> makeInstance() {
- return new RandomSampleKNNPreprocessor.Factory<O, D>(k, distanceFunction, share, rnd);
+ return new RandomSampleKNNPreprocessor.Factory<>(k, distanceFunction, share, rnd);
}
}
}
diff --git a/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/SpatialApproximationMaterializeKNNPreprocessor.java b/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/SpatialApproximationMaterializeKNNPreprocessor.java
index c7963e14..739dcc7c 100644
--- a/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/SpatialApproximationMaterializeKNNPreprocessor.java
+++ b/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/SpatialApproximationMaterializeKNNPreprocessor.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.preprocessed.knn;
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,12 +34,11 @@ import de.lmu.ifi.dbs.elki.database.ids.ArrayModifiableDBIDs;
import de.lmu.ifi.dbs.elki.database.ids.DBIDIter;
import de.lmu.ifi.dbs.elki.database.ids.DBIDPair;
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.relation.Relation;
import de.lmu.ifi.dbs.elki.distance.distancefunction.DistanceFunction;
-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.LeafEntry;
import de.lmu.ifi.dbs.elki.index.tree.spatial.SpatialEntry;
@@ -57,7 +56,7 @@ import de.lmu.ifi.dbs.elki.utilities.exceptions.AbortException;
* A preprocessor for annotation of the k nearest neighbors (and their
* distances) to each database object.
*
- * Used for example by {@link de.lmu.ifi.dbs.elki.algorithm.outlier.LOF}.
+ * Used for example by {@link de.lmu.ifi.dbs.elki.algorithm.outlier.lof.LOF}.
*
* TODO correct handling of datastore events
*
@@ -71,7 +70,7 @@ import de.lmu.ifi.dbs.elki.utilities.exceptions.AbortException;
*/
@Title("Spatial Approximation Materialize kNN Preprocessor")
@Description("Caterializes the (approximate) k nearest neighbors of objects of a database using a spatial approximation.")
-public class SpatialApproximationMaterializeKNNPreprocessor<O extends NumberVector<?>, D extends Distance<D>, N extends SpatialNode<N, E>, E extends SpatialEntry> extends AbstractMaterializeKNNPreprocessor<O, D, KNNResult<D>> {
+public class SpatialApproximationMaterializeKNNPreprocessor<O extends NumberVector<?>, D extends Distance<D>, N extends SpatialNode<N, E>, E extends SpatialEntry> extends AbstractMaterializeKNNPreprocessor<O, D, KNNList<D>> {
/**
* Logger to use
*/
@@ -98,7 +97,7 @@ public class SpatialApproximationMaterializeKNNPreprocessor<O extends NumberVect
}
SpatialIndexTree<N, E> index = indexes.iterator().next();
- storage = DataStoreUtil.makeStorage(relation.getDBIDs(), DataStoreFactory.HINT_STATIC, KNNResult.class);
+ storage = DataStoreUtil.makeStorage(relation.getDBIDs(), DataStoreFactory.HINT_STATIC, KNNList.class);
MeanVariance pagesize = new MeanVariance();
MeanVariance ksize = new MeanVariance();
if(getLogger().isVerbose()) {
@@ -119,9 +118,9 @@ public class SpatialApproximationMaterializeKNNPreprocessor<O extends NumberVect
for(int i = 0; i < size; i++) {
ids.add(((LeafEntry) node.getEntry(i)).getDBID());
}
- HashMap<DBIDPair, D> cache = new HashMap<DBIDPair, D>((size * size * 3) >> 3);
+ HashMap<DBIDPair, D> cache = new HashMap<>((size * size * 3) >> 3);
for(DBIDIter id = ids.iter(); id.valid(); id.advance()) {
- KNNHeap<D> kNN = KNNUtil.newHeap(distanceFunction, k);
+ KNNHeap<D> kNN = DBIDUtil.newHeap(distanceFunction.getDistanceFactory(), k);
for(DBIDIter id2 = ids.iter(); id2.valid(); id2.advance()) {
DBIDPair key = DBIDUtil.newPair(id, id2);
D d = cache.remove(key);
@@ -174,6 +173,11 @@ public class SpatialApproximationMaterializeKNNPreprocessor<O extends NumberVect
return "spatial-approximate-knn";
}
+ @Override
+ public void logStatistics() {
+ // No statistics to log.
+ }
+
/**
* The actual preprocessor instance.
*
@@ -187,7 +191,7 @@ public class SpatialApproximationMaterializeKNNPreprocessor<O extends NumberVect
* @param <N> the type of spatial nodes in the spatial index
* @param <E> the type of spatial entries in the spatial index
*/
- public static class Factory<D extends Distance<D>, N extends SpatialNode<N, E>, E extends SpatialEntry> extends AbstractMaterializeKNNPreprocessor.Factory<NumberVector<?>, D, KNNResult<D>> {
+ public static class Factory<D extends Distance<D>, N extends SpatialNode<N, E>, E extends SpatialEntry> extends AbstractMaterializeKNNPreprocessor.Factory<NumberVector<?>, D, KNNList<D>> {
/**
* Constructor.
*
@@ -200,7 +204,7 @@ public class SpatialApproximationMaterializeKNNPreprocessor<O extends NumberVect
@Override
public SpatialApproximationMaterializeKNNPreprocessor<NumberVector<?>, D, N, E> instantiate(Relation<NumberVector<?>> relation) {
- SpatialApproximationMaterializeKNNPreprocessor<NumberVector<?>, D, N, E> instance = new SpatialApproximationMaterializeKNNPreprocessor<NumberVector<?>, D, N, E>(relation, distanceFunction, k);
+ SpatialApproximationMaterializeKNNPreprocessor<NumberVector<?>, D, N, E> instance = new SpatialApproximationMaterializeKNNPreprocessor<>(relation, distanceFunction, k);
return instance;
}
@@ -214,7 +218,7 @@ public class SpatialApproximationMaterializeKNNPreprocessor<O extends NumberVect
public static class Parameterizer<D extends Distance<D>, N extends SpatialNode<N, E>, E extends SpatialEntry> extends AbstractMaterializeKNNPreprocessor.Factory.Parameterizer<NumberVector<?>, D> {
@Override
protected Factory<D, N, E> makeInstance() {
- return new Factory<D, N, E>(k, distanceFunction);
+ return new Factory<>(k, distanceFunction);
}
}
}
diff --git a/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/package-info.java b/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/package-info.java
index 1780cdc0..47339bb4 100644
--- a/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/package-info.java
+++ b/src/de/lmu/ifi/dbs/elki/index/preprocessed/knn/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/preprocessed/localpca/AbstractFilteredPCAIndex.java b/src/de/lmu/ifi/dbs/elki/index/preprocessed/localpca/AbstractFilteredPCAIndex.java
index 371dbca6..67a2effc 100644
--- a/src/de/lmu/ifi/dbs/elki/index/preprocessed/localpca/AbstractFilteredPCAIndex.java
+++ b/src/de/lmu/ifi/dbs/elki/index/preprocessed/localpca/AbstractFilteredPCAIndex.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.preprocessed.localpca;
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,10 @@ import de.lmu.ifi.dbs.elki.database.datastore.DataStoreFactory;
import de.lmu.ifi.dbs.elki.database.datastore.DataStoreUtil;
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.distance.DistanceDBIDList;
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.distancefunction.EuclideanDistanceFunction;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.DistanceDBIDResult;
+import de.lmu.ifi.dbs.elki.distance.distancefunction.minkowski.EuclideanDistanceFunction;
import de.lmu.ifi.dbs.elki.distance.distancevalue.DoubleDistance;
import de.lmu.ifi.dbs.elki.index.preprocessed.AbstractPreprocessorIndex;
import de.lmu.ifi.dbs.elki.logging.progress.FiniteProgress;
@@ -78,10 +78,8 @@ public abstract class AbstractFilteredPCAIndex<NV extends NumberVector<?>> exten
this.pca = pca;
}
- /**
- * Preprocessing step.
- */
- protected void preprocess() {
+ @Override
+ public void initialize() {
if(relation == null || relation.size() <= 0) {
throw new IllegalArgumentException(ExceptionMessages.DATABASE_EMPTY);
}
@@ -99,7 +97,7 @@ public abstract class AbstractFilteredPCAIndex<NV extends NumberVector<?>> exten
// TODO: use a bulk operation?
for(DBIDIter iditer = relation.iterDBIDs(); iditer.valid(); iditer.advance()) {
- DistanceDBIDResult<DoubleDistance> objects = objectsForPCA(iditer);
+ DistanceDBIDList<DoubleDistance> objects = objectsForPCA(iditer);
PCAFilteredResult pcares = pca.processQueryResult(objects, relation);
@@ -123,7 +121,7 @@ public abstract class AbstractFilteredPCAIndex<NV extends NumberVector<?>> exten
@Override
public PCAFilteredResult getLocalProjection(DBIDRef objid) {
if(storage == null) {
- preprocess();
+ initialize();
}
return storage.get(objid);
}
@@ -136,7 +134,7 @@ public abstract class AbstractFilteredPCAIndex<NV extends NumberVector<?>> exten
* @return the list of the objects (i.e. the ids and the distances to the
* query object) to be considered within the PCA
*/
- protected abstract DistanceDBIDResult<DoubleDistance> objectsForPCA(DBIDRef id);
+ protected abstract DistanceDBIDList<DoubleDistance> objectsForPCA(DBIDRef id);
/**
* Factory class.
@@ -207,7 +205,7 @@ public abstract class AbstractFilteredPCAIndex<NV extends NumberVector<?>> exten
@Override
protected void makeOptions(Parameterization config) {
super.makeOptions(config);
- final ObjectParameter<DistanceFunction<NV, DoubleDistance>> pcaDistanceFunctionP = new ObjectParameter<DistanceFunction<NV, DoubleDistance>>(PCA_DISTANCE_ID, DistanceFunction.class, EuclideanDistanceFunction.class);
+ final ObjectParameter<DistanceFunction<NV, DoubleDistance>> pcaDistanceFunctionP = new ObjectParameter<>(PCA_DISTANCE_ID, DistanceFunction.class, EuclideanDistanceFunction.class);
if(config.grab(pcaDistanceFunctionP)) {
pcaDistanceFunction = pcaDistanceFunctionP.instantiateClass(config);
diff --git a/src/de/lmu/ifi/dbs/elki/index/preprocessed/localpca/FilteredLocalPCAIndex.java b/src/de/lmu/ifi/dbs/elki/index/preprocessed/localpca/FilteredLocalPCAIndex.java
index d0780751..2d64cbc0 100644
--- a/src/de/lmu/ifi/dbs/elki/index/preprocessed/localpca/FilteredLocalPCAIndex.java
+++ b/src/de/lmu/ifi/dbs/elki/index/preprocessed/localpca/FilteredLocalPCAIndex.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.preprocessed.localpca;
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/preprocessed/localpca/KNNQueryFilteredPCAIndex.java b/src/de/lmu/ifi/dbs/elki/index/preprocessed/localpca/KNNQueryFilteredPCAIndex.java
index 00ce11b8..e6320833 100644
--- a/src/de/lmu/ifi/dbs/elki/index/preprocessed/localpca/KNNQueryFilteredPCAIndex.java
+++ b/src/de/lmu/ifi/dbs/elki/index/preprocessed/localpca/KNNQueryFilteredPCAIndex.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.preprocessed.localpca;
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,10 +26,11 @@ package de.lmu.ifi.dbs.elki.index.preprocessed.localpca;
import de.lmu.ifi.dbs.elki.data.NumberVector;
import de.lmu.ifi.dbs.elki.database.QueryUtil;
import de.lmu.ifi.dbs.elki.database.ids.DBIDRef;
+import de.lmu.ifi.dbs.elki.database.ids.distance.KNNList;
import de.lmu.ifi.dbs.elki.database.query.knn.KNNQuery;
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.distanceresultlist.KNNResult;
import de.lmu.ifi.dbs.elki.distance.distancevalue.DoubleDistance;
import de.lmu.ifi.dbs.elki.logging.Logging;
import de.lmu.ifi.dbs.elki.math.linearalgebra.pca.PCAFilteredRunner;
@@ -74,19 +75,24 @@ public class KNNQueryFilteredPCAIndex<NV extends NumberVector<?>> extends Abstra
/**
* Constructor.
*
- * @param database Database to use
+ * @param relation Database to use
* @param pca PCA Runner to use
* @param knnQuery KNN Query to use
* @param k k value
*/
- public KNNQueryFilteredPCAIndex(Relation<NV> database, PCAFilteredRunner<NV> pca, KNNQuery<NV, DoubleDistance> knnQuery, int k) {
- super(database, pca);
+ public KNNQueryFilteredPCAIndex(Relation<NV> relation, PCAFilteredRunner<NV> pca, KNNQuery<NV, DoubleDistance> knnQuery, int k) {
+ super(relation, pca);
this.knnQuery = knnQuery;
this.k = k;
+ // Sanity check:
+ int dim = RelationUtil.dimensionality(relation);
+ if (dim > 0 && k <= dim) {
+ LOG.warning("PCA results with k < dim are meaningless. Choose k much larger than the dimensionality.");
+ }
}
@Override
- protected KNNResult<DoubleDistance> objectsForPCA(DBIDRef id) {
+ protected KNNList<DoubleDistance> objectsForPCA(DBIDRef id) {
return knnQuery.getKNNForDBID(id, k);
}
@@ -105,6 +111,11 @@ public class KNNQueryFilteredPCAIndex<NV extends NumberVector<?>> extends Abstra
return LOG;
}
+ @Override
+ public void logStatistics() {
+ // No statistics to log.
+ }
+
/**
* Factory class.
*
@@ -150,7 +161,7 @@ public class KNNQueryFilteredPCAIndex<NV extends NumberVector<?>> extends Abstra
public KNNQueryFilteredPCAIndex<V> instantiate(Relation<V> relation) {
// TODO: set bulk flag, once the parent class supports bulk.
KNNQuery<V, DoubleDistance> knnquery = QueryUtil.getKNNQuery(relation, pcaDistanceFunction, k);
- return new KNNQueryFilteredPCAIndex<V>(relation, pca, knnquery, k);
+ return new KNNQueryFilteredPCAIndex<>(relation, pca, knnquery, k);
}
/**
@@ -168,16 +179,15 @@ public class KNNQueryFilteredPCAIndex<NV extends NumberVector<?>> extends Abstra
super.makeOptions(config);
final IntParameter kP = new IntParameter(K_ID);
kP.addConstraint(new GreaterConstraint(0));
- kP.setOptional(true);
- if(config.grab(kP)) {
+ if (config.grab(kP)) {
k = kP.getValue();
}
}
@Override
protected Factory<NV> makeInstance() {
- return new Factory<NV>(pcaDistanceFunction, pca, k);
+ return new Factory<>(pcaDistanceFunction, pca, k);
}
}
}
-} \ No newline at end of file
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/preprocessed/localpca/RangeQueryFilteredPCAIndex.java b/src/de/lmu/ifi/dbs/elki/index/preprocessed/localpca/RangeQueryFilteredPCAIndex.java
index bbc00c64..03b49df3 100644
--- a/src/de/lmu/ifi/dbs/elki/index/preprocessed/localpca/RangeQueryFilteredPCAIndex.java
+++ b/src/de/lmu/ifi/dbs/elki/index/preprocessed/localpca/RangeQueryFilteredPCAIndex.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.preprocessed.localpca;
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,10 +26,10 @@ package de.lmu.ifi.dbs.elki.index.preprocessed.localpca;
import de.lmu.ifi.dbs.elki.data.NumberVector;
import de.lmu.ifi.dbs.elki.database.QueryUtil;
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.range.RangeQuery;
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.DistanceDBIDResult;
import de.lmu.ifi.dbs.elki.distance.distancevalue.DoubleDistance;
import de.lmu.ifi.dbs.elki.logging.Logging;
import de.lmu.ifi.dbs.elki.math.linearalgebra.pca.PCAFilteredRunner;
@@ -84,7 +84,7 @@ public class RangeQueryFilteredPCAIndex<NV extends NumberVector<?>> extends Abst
}
@Override
- protected DistanceDBIDResult<DoubleDistance> objectsForPCA(DBIDRef id) {
+ protected DistanceDBIDList<DoubleDistance> objectsForPCA(DBIDRef id) {
return rangeQuery.getRangeForDBID(id, epsilon);
}
@@ -99,10 +99,15 @@ public class RangeQueryFilteredPCAIndex<NV extends NumberVector<?>> extends Abst
}
@Override
- public Logging getLogger() {
+ protected Logging getLogger() {
return LOG;
}
+ @Override
+ public void logStatistics() {
+ // No statistics to log.
+ }
+
/**
* Factory class.
*
@@ -142,7 +147,7 @@ public class RangeQueryFilteredPCAIndex<NV extends NumberVector<?>> extends Abst
public RangeQueryFilteredPCAIndex<V> instantiate(Relation<V> relation) {
// TODO: set bulk flag, once the parent class supports bulk.
RangeQuery<V, DoubleDistance> rangequery = QueryUtil.getRangeQuery(relation, pcaDistanceFunction);
- return new RangeQueryFilteredPCAIndex<V>(relation, pca, rangequery, epsilon);
+ return new RangeQueryFilteredPCAIndex<>(relation, pca, rangequery, epsilon);
}
/**
@@ -158,7 +163,7 @@ public class RangeQueryFilteredPCAIndex<NV extends NumberVector<?>> extends Abst
@Override
protected void makeOptions(Parameterization config) {
super.makeOptions(config);
- DistanceParameter<DoubleDistance> epsilonP = new DistanceParameter<DoubleDistance>(EPSILON_ID, pcaDistanceFunction != null ? pcaDistanceFunction.getDistanceFactory() : null);
+ DistanceParameter<DoubleDistance> epsilonP = new DistanceParameter<>(EPSILON_ID, pcaDistanceFunction != null ? pcaDistanceFunction.getDistanceFactory() : null);
if(config.grab(epsilonP)) {
epsilon = epsilonP.getValue();
}
@@ -166,7 +171,7 @@ public class RangeQueryFilteredPCAIndex<NV extends NumberVector<?>> extends Abst
@Override
protected Factory<NV> makeInstance() {
- return new Factory<NV>(pcaDistanceFunction, pca, epsilon);
+ return new Factory<>(pcaDistanceFunction, pca, epsilon);
}
}
}
diff --git a/src/de/lmu/ifi/dbs/elki/index/preprocessed/localpca/package-info.java b/src/de/lmu/ifi/dbs/elki/index/preprocessed/localpca/package-info.java
index 2bd9cc7d..536dbb3c 100644
--- a/src/de/lmu/ifi/dbs/elki/index/preprocessed/localpca/package-info.java
+++ b/src/de/lmu/ifi/dbs/elki/index/preprocessed/localpca/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/preprocessed/package-info.java b/src/de/lmu/ifi/dbs/elki/index/preprocessed/package-info.java
index 98a55d88..2edb1244 100644
--- a/src/de/lmu/ifi/dbs/elki/index/preprocessed/package-info.java
+++ b/src/de/lmu/ifi/dbs/elki/index/preprocessed/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/preprocessed/preference/AbstractPreferenceVectorIndex.java b/src/de/lmu/ifi/dbs/elki/index/preprocessed/preference/AbstractPreferenceVectorIndex.java
index 56b09dba..dd43e027 100644
--- a/src/de/lmu/ifi/dbs/elki/index/preprocessed/preference/AbstractPreferenceVectorIndex.java
+++ b/src/de/lmu/ifi/dbs/elki/index/preprocessed/preference/AbstractPreferenceVectorIndex.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.preprocessed.preference;
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,15 +50,10 @@ public abstract class AbstractPreferenceVectorIndex<NV extends NumberVector<?>>
super(relation);
}
- /**
- * Preprocessing step.
- */
- protected abstract void preprocess();
-
@Override
public BitSet getPreferenceVector(DBIDRef objid) {
if(storage == null) {
- preprocess();
+ initialize();
}
return storage.get(objid);
}
diff --git a/src/de/lmu/ifi/dbs/elki/index/preprocessed/preference/DiSHPreferenceVectorIndex.java b/src/de/lmu/ifi/dbs/elki/index/preprocessed/preference/DiSHPreferenceVectorIndex.java
index 2b02e7d6..1d1662a7 100644
--- a/src/de/lmu/ifi/dbs/elki/index/preprocessed/preference/DiSHPreferenceVectorIndex.java
+++ b/src/de/lmu/ifi/dbs/elki/index/preprocessed/preference/DiSHPreferenceVectorIndex.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.preprocessed.preference;
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
@@ -44,13 +44,13 @@ import de.lmu.ifi.dbs.elki.database.ids.DBIDIter;
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.DistanceDBIDList;
import de.lmu.ifi.dbs.elki.database.query.distance.PrimitiveDistanceQuery;
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.datasource.bundle.SingleObjectBundle;
import de.lmu.ifi.dbs.elki.distance.distancefunction.subspace.DimensionSelectingDistanceFunction;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.DistanceDBIDResult;
import de.lmu.ifi.dbs.elki.distance.distancevalue.DoubleDistance;
import de.lmu.ifi.dbs.elki.logging.Logging;
import de.lmu.ifi.dbs.elki.logging.progress.FiniteProgress;
@@ -131,7 +131,7 @@ public class DiSHPreferenceVectorIndex<V extends NumberVector<?>> extends Abstra
}
@Override
- protected void preprocess() {
+ public void initialize() {
if(relation == null || relation.size() == 0) {
throw new IllegalArgumentException(ExceptionMessages.DATABASE_EMPTY);
}
@@ -172,7 +172,7 @@ public class DiSHPreferenceVectorIndex<V extends NumberVector<?>> extends Abstra
// determine neighbors in each dimension
ModifiableDBIDs[] allNeighbors = new ModifiableDBIDs[dim];
for(int d = 0; d < dim; d++) {
- DistanceDBIDResult<DoubleDistance> qrList = rangeQueries[d].getRangeForDBID(it, epsilon[d]);
+ DistanceDBIDList<DoubleDistance> qrList = rangeQueries[d].getRangeForDBID(it, epsilon[d]);
allNeighbors[d] = DBIDUtil.newHashSet(qrList);
}
@@ -249,7 +249,7 @@ public class DiSHPreferenceVectorIndex<V extends NumberVector<?>> extends Abstra
// database for apriori
UpdatableDatabase apriori_db = new HashmapDatabase();
- SimpleTypeInformation<?> bitmeta = new VectorFieldTypeInformation<BitVector>(BitVector.class, dimensionality);
+ SimpleTypeInformation<?> bitmeta = new VectorFieldTypeInformation<>(BitVector.class, dimensionality);
for(DBIDIter it = relation.iterDBIDs(); it.valid(); it.advance()) {
Bit[] bits = new Bit[dimensionality];
boolean allFalse = true;
@@ -311,7 +311,7 @@ public class DiSHPreferenceVectorIndex<V extends NumberVector<?>> extends Abstra
int dimensionality = neighborIDs.length;
BitSet preferenceVector = new BitSet(dimensionality);
- Map<Integer, ModifiableDBIDs> candidates = new HashMap<Integer, ModifiableDBIDs>(dimensionality);
+ Map<Integer, ModifiableDBIDs> candidates = new HashMap<>(dimensionality);
for(int i = 0; i < dimensionality; i++) {
ModifiableDBIDs s_i = neighborIDs[i];
if(s_i.size() > minpts) {
@@ -409,7 +409,7 @@ public class DiSHPreferenceVectorIndex<V extends NumberVector<?>> extends Abstra
Class<RangeQuery<V, DoubleDistance>> rqcls = ClassGenericsUtil.uglyCastIntoSubclass(RangeQuery.class);
RangeQuery<V, DoubleDistance>[] rangeQueries = ClassGenericsUtil.newArrayOfNull(dimensionality, rqcls);
for(int d = 0; d < dimensionality; d++) {
- rangeQueries[d] = relation.getDatabase().getRangeQuery(new PrimitiveDistanceQuery<V, DoubleDistance>(relation, new DimensionSelectingDistanceFunction(d)));
+ rangeQueries[d] = relation.getDatabase().getRangeQuery(new PrimitiveDistanceQuery<>(relation, new DimensionSelectingDistanceFunction(d)));
}
return rangeQueries;
}
@@ -429,6 +429,11 @@ public class DiSHPreferenceVectorIndex<V extends NumberVector<?>> extends Abstra
return "dish-pref";
}
+ @Override
+ public void logStatistics() {
+ // No statistics to log.
+ }
+
/**
* Factory class.
*
@@ -532,7 +537,7 @@ public class DiSHPreferenceVectorIndex<V extends NumberVector<?>> extends Abstra
@Override
public DiSHPreferenceVectorIndex<V> instantiate(Relation<V> relation) {
- return new DiSHPreferenceVectorIndex<V>(relation, epsilon, minpts, strategy);
+ return new DiSHPreferenceVectorIndex<>(relation, epsilon, minpts, strategy);
}
/**
@@ -578,7 +583,7 @@ public class DiSHPreferenceVectorIndex<V extends NumberVector<?>> extends Abstra
// parameter epsilon
// todo: constraint auf positive werte
- List<Double> defaultEps = new ArrayList<Double>();
+ List<Double> defaultEps = new ArrayList<>();
defaultEps.add(DEFAULT_EPSILON.doubleValue());
final DoubleListParameter epsilonP = new DoubleListParameter(EPSILON_ID, true);
epsilonP.setDefaultValue(defaultEps);
@@ -595,7 +600,7 @@ public class DiSHPreferenceVectorIndex<V extends NumberVector<?>> extends Abstra
}
// parameter strategy
- final EnumParameter<Strategy> strategyP = new EnumParameter<Strategy>(STRATEGY_ID, Strategy.class, DEFAULT_STRATEGY);
+ final EnumParameter<Strategy> strategyP = new EnumParameter<>(STRATEGY_ID, Strategy.class, DEFAULT_STRATEGY);
if(config.grab(strategyP)) {
strategy = strategyP.getValue();
}
@@ -603,7 +608,7 @@ public class DiSHPreferenceVectorIndex<V extends NumberVector<?>> extends Abstra
@Override
protected Factory<V> makeInstance() {
- return new Factory<V>(epsilon, minpts, strategy);
+ return new Factory<>(epsilon, minpts, strategy);
}
}
}
diff --git a/src/de/lmu/ifi/dbs/elki/index/preprocessed/preference/HiSCPreferenceVectorIndex.java b/src/de/lmu/ifi/dbs/elki/index/preprocessed/preference/HiSCPreferenceVectorIndex.java
index fd6aa0bf..e5dcf2f4 100644
--- a/src/de/lmu/ifi/dbs/elki/index/preprocessed/preference/HiSCPreferenceVectorIndex.java
+++ b/src/de/lmu/ifi/dbs/elki/index/preprocessed/preference/HiSCPreferenceVectorIndex.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.preprocessed.preference;
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,11 +34,11 @@ 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.knn.KNNQuery;
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.EuclideanDistanceFunction;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.KNNResult;
+import de.lmu.ifi.dbs.elki.distance.distancefunction.minkowski.EuclideanDistanceFunction;
import de.lmu.ifi.dbs.elki.distance.distancevalue.DoubleDistance;
import de.lmu.ifi.dbs.elki.logging.Logging;
import de.lmu.ifi.dbs.elki.logging.progress.FiniteProgress;
@@ -97,7 +97,7 @@ public class HiSCPreferenceVectorIndex<V extends NumberVector<?>> extends Abstra
}
@Override
- protected void preprocess() {
+ public void initialize() {
if (relation == null || relation.size() <= 0) {
throw new IllegalArgumentException(ExceptionMessages.DATABASE_EMPTY);
}
@@ -118,7 +118,7 @@ public class HiSCPreferenceVectorIndex<V extends NumberVector<?>> extends Abstra
msg.append("\n knns: ");
}
- KNNResult<DoubleDistance> knns = knnQuery.getKNNForDBID(it, k);
+ KNNList<DoubleDistance> knns = knnQuery.getKNNForDBID(it, k);
BitSet preferenceVector = determinePreferenceVector(relation, it, knns, msg);
storage.put(it, preferenceVector);
@@ -190,6 +190,11 @@ public class HiSCPreferenceVectorIndex<V extends NumberVector<?>> extends Abstra
return "hisc-pref";
}
+ @Override
+ public void logStatistics() {
+ // No statistics to log.
+ }
+
/**
* Factory class.
*
@@ -261,7 +266,7 @@ public class HiSCPreferenceVectorIndex<V extends NumberVector<?>> extends Abstra
} else {
usek = k;
}
- return new HiSCPreferenceVectorIndex<V>(relation, alpha, usek);
+ return new HiSCPreferenceVectorIndex<>(relation, alpha, usek);
}
/**
@@ -302,7 +307,7 @@ public class HiSCPreferenceVectorIndex<V extends NumberVector<?>> extends Abstra
@Override
protected Factory<V> makeInstance() {
- return new Factory<V>(alpha, k);
+ return new Factory<>(alpha, k);
}
}
}
diff --git a/src/de/lmu/ifi/dbs/elki/index/preprocessed/preference/PreferenceVectorIndex.java b/src/de/lmu/ifi/dbs/elki/index/preprocessed/preference/PreferenceVectorIndex.java
index a212c2cd..87a9d3dd 100644
--- a/src/de/lmu/ifi/dbs/elki/index/preprocessed/preference/PreferenceVectorIndex.java
+++ b/src/de/lmu/ifi/dbs/elki/index/preprocessed/preference/PreferenceVectorIndex.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.preprocessed.preference;
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/preprocessed/preference/package-info.java b/src/de/lmu/ifi/dbs/elki/index/preprocessed/preference/package-info.java
index 69d0855b..e840bfd0 100644
--- a/src/de/lmu/ifi/dbs/elki/index/preprocessed/preference/package-info.java
+++ b/src/de/lmu/ifi/dbs/elki/index/preprocessed/preference/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/preprocessed/snn/SharedNearestNeighborIndex.java b/src/de/lmu/ifi/dbs/elki/index/preprocessed/snn/SharedNearestNeighborIndex.java
index 3aa0c523..cdb1d0bb 100644
--- a/src/de/lmu/ifi/dbs/elki/index/preprocessed/snn/SharedNearestNeighborIndex.java
+++ b/src/de/lmu/ifi/dbs/elki/index/preprocessed/snn/SharedNearestNeighborIndex.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.preprocessed.snn;
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/preprocessed/snn/SharedNearestNeighborPreprocessor.java b/src/de/lmu/ifi/dbs/elki/index/preprocessed/snn/SharedNearestNeighborPreprocessor.java
index d57aeb8f..9b1aee0f 100644
--- a/src/de/lmu/ifi/dbs/elki/index/preprocessed/snn/SharedNearestNeighborPreprocessor.java
+++ b/src/de/lmu/ifi/dbs/elki/index/preprocessed/snn/SharedNearestNeighborPreprocessor.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.preprocessed.snn;
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,11 +32,11 @@ import de.lmu.ifi.dbs.elki.database.ids.ArrayModifiableDBIDs;
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.distance.KNNList;
import de.lmu.ifi.dbs.elki.database.query.knn.KNNQuery;
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.distancefunction.EuclideanDistanceFunction;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.KNNResult;
+import de.lmu.ifi.dbs.elki.distance.distancefunction.minkowski.EuclideanDistanceFunction;
import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
import de.lmu.ifi.dbs.elki.index.preprocessed.AbstractPreprocessorIndex;
import de.lmu.ifi.dbs.elki.index.preprocessed.knn.MaterializeKNNPreprocessor;
@@ -102,10 +102,8 @@ public class SharedNearestNeighborPreprocessor<O, D extends Distance<D>> extends
this.distanceFunction = distanceFunction;
}
- /**
- * Preprocessing step.
- */
- protected void preprocess() {
+ @Override
+ public void initialize() {
if(getLogger().isVerbose()) {
getLogger().verbose("Assigning nearest neighbor lists to database objects");
}
@@ -115,7 +113,7 @@ public class SharedNearestNeighborPreprocessor<O, D extends Distance<D>> extends
FiniteProgress progress = getLogger().isVerbose() ? new FiniteProgress("assigning nearest neighbor lists", relation.size(), getLogger()) : null;
for(DBIDIter iditer = relation.iterDBIDs(); iditer.valid(); iditer.advance()) {
ArrayModifiableDBIDs neighbors = DBIDUtil.newArray(numberOfNeighbors);
- KNNResult<D> kNN = knnquery.getKNNForDBID(iditer, numberOfNeighbors);
+ KNNList<D> kNN = knnquery.getKNNForDBID(iditer, numberOfNeighbors);
for (DBIDIter iter = kNN.iter(); iter.valid(); iter.advance()) {
// if(!id.equals(nid)) {
neighbors.add(iter);
@@ -139,7 +137,7 @@ public class SharedNearestNeighborPreprocessor<O, D extends Distance<D>> extends
@Override
public ArrayDBIDs getNearestNeighborSet(DBIDRef objid) {
if(storage == null) {
- preprocess();
+ initialize();
}
return storage.get(objid);
}
@@ -159,6 +157,11 @@ public class SharedNearestNeighborPreprocessor<O, D extends Distance<D>> extends
return "SNN-index";
}
+ @Override
+ public void logStatistics() {
+ // No statistics to log.
+ }
+
/**
* Get the number of neighbors
*
@@ -228,7 +231,7 @@ public class SharedNearestNeighborPreprocessor<O, D extends Distance<D>> extends
@Override
public SharedNearestNeighborPreprocessor<O, D> instantiate(Relation<O> relation) {
- return new SharedNearestNeighborPreprocessor<O, D>(relation, numberOfNeighbors, distanceFunction);
+ return new SharedNearestNeighborPreprocessor<>(relation, numberOfNeighbors, distanceFunction);
}
/**
@@ -273,7 +276,7 @@ public class SharedNearestNeighborPreprocessor<O, D extends Distance<D>> extends
numberOfNeighbors = numberOfNeighborsP.getValue();
}
- final ObjectParameter<DistanceFunction<O, D>> distanceFunctionP = new ObjectParameter<DistanceFunction<O, D>>(DISTANCE_FUNCTION_ID, DistanceFunction.class, EuclideanDistanceFunction.class);
+ final ObjectParameter<DistanceFunction<O, D>> distanceFunctionP = new ObjectParameter<>(DISTANCE_FUNCTION_ID, DistanceFunction.class, EuclideanDistanceFunction.class);
if(config.grab(distanceFunctionP)) {
distanceFunction = distanceFunctionP.instantiateClass(config);
}
@@ -281,7 +284,7 @@ public class SharedNearestNeighborPreprocessor<O, D extends Distance<D>> extends
@Override
protected Factory<O, D> makeInstance() {
- return new Factory<O, D>(numberOfNeighbors, distanceFunction);
+ return new Factory<>(numberOfNeighbors, distanceFunction);
}
}
}
diff --git a/src/de/lmu/ifi/dbs/elki/index/preprocessed/snn/package-info.java b/src/de/lmu/ifi/dbs/elki/index/preprocessed/snn/package-info.java
index 98065df6..5612f655 100644
--- a/src/de/lmu/ifi/dbs/elki/index/preprocessed/snn/package-info.java
+++ b/src/de/lmu/ifi/dbs/elki/index/preprocessed/snn/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/preprocessed/subspaceproj/AbstractSubspaceProjectionIndex.java b/src/de/lmu/ifi/dbs/elki/index/preprocessed/subspaceproj/AbstractSubspaceProjectionIndex.java
index 1d23681d..1bad7db0 100644
--- a/src/de/lmu/ifi/dbs/elki/index/preprocessed/subspaceproj/AbstractSubspaceProjectionIndex.java
+++ b/src/de/lmu/ifi/dbs/elki/index/preprocessed/subspaceproj/AbstractSubspaceProjectionIndex.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.preprocessed.subspaceproj;
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,13 +32,13 @@ import de.lmu.ifi.dbs.elki.database.datastore.DataStoreFactory;
import de.lmu.ifi.dbs.elki.database.datastore.DataStoreUtil;
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.DistanceDBIDPair;
+import de.lmu.ifi.dbs.elki.database.ids.distance.DistanceDBIDList;
+import de.lmu.ifi.dbs.elki.database.ids.distance.DistanceDBIDPair;
+import de.lmu.ifi.dbs.elki.database.ids.generic.GenericDistanceDBIDList;
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.distancefunction.DistanceFunction;
-import de.lmu.ifi.dbs.elki.distance.distancefunction.EuclideanDistanceFunction;
-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.distancefunction.minkowski.EuclideanDistanceFunction;
import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
import de.lmu.ifi.dbs.elki.index.preprocessed.AbstractPreprocessorIndex;
import de.lmu.ifi.dbs.elki.logging.progress.FiniteProgress;
@@ -97,10 +97,8 @@ public abstract class AbstractSubspaceProjectionIndex<NV extends NumberVector<?>
this.minpts = minpts;
}
- /**
- * Preprocessing step.
- */
- protected void preprocess() {
+ @Override
+ public void initialize() {
if(relation == null || relation.size() <= 0) {
throw new IllegalArgumentException(ExceptionMessages.DATABASE_EMPTY);
}
@@ -115,7 +113,7 @@ public abstract class AbstractSubspaceProjectionIndex<NV extends NumberVector<?>
FiniteProgress progress = getLogger().isVerbose() ? new FiniteProgress(this.getClass().getName(), relation.size(), getLogger()) : null;
for(DBIDIter iditer = relation.iterDBIDs(); iditer.valid(); iditer.advance()) {
- DistanceDBIDResult<D> neighbors = rangeQuery.getRangeForDBID(iditer, epsilon);
+ DistanceDBIDList<D> neighbors = rangeQuery.getRangeForDBID(iditer, epsilon);
final P pres;
if(neighbors.size() >= minpts) {
@@ -123,7 +121,7 @@ public abstract class AbstractSubspaceProjectionIndex<NV extends NumberVector<?>
}
else {
DistanceDBIDPair<D> firstQR = neighbors.iter().getDistancePair();
- GenericDistanceDBIDList<D> newne = new GenericDistanceDBIDList<D>();
+ GenericDistanceDBIDList<D> newne = new GenericDistanceDBIDList<>();
newne.add(firstQR);
pres = computeProjection(iditer, newne, relation);
}
@@ -148,7 +146,7 @@ public abstract class AbstractSubspaceProjectionIndex<NV extends NumberVector<?>
@Override
public P getLocalProjection(DBIDRef objid) {
if(storage == null) {
- preprocess();
+ initialize();
}
return storage.get(objid);
}
@@ -167,7 +165,7 @@ public abstract class AbstractSubspaceProjectionIndex<NV extends NumberVector<?>
*
* @return local subspace projection
*/
- protected abstract P computeProjection(DBIDRef id, DistanceDBIDResult<D> neighbors, Relation<NV> relation);
+ protected abstract P computeProjection(DBIDRef id, DistanceDBIDList<D> neighbors, Relation<NV> relation);
/**
* Factory class
@@ -247,7 +245,7 @@ public abstract class AbstractSubspaceProjectionIndex<NV extends NumberVector<?>
}
protected void configRangeQueryDistanceFunction(Parameterization config) {
- ObjectParameter<DistanceFunction<NV, D>> rangeQueryDistanceP = new ObjectParameter<DistanceFunction<NV, D>>(AbstractProjectedDBSCAN.INNER_DISTANCE_FUNCTION_ID, DistanceFunction.class, EuclideanDistanceFunction.class);
+ ObjectParameter<DistanceFunction<NV, D>> rangeQueryDistanceP = new ObjectParameter<>(AbstractProjectedDBSCAN.INNER_DISTANCE_FUNCTION_ID, DistanceFunction.class, EuclideanDistanceFunction.class);
if(config.grab(rangeQueryDistanceP)) {
rangeQueryDistanceFunction = rangeQueryDistanceP.instantiateClass(config);
}
@@ -255,7 +253,7 @@ public abstract class AbstractSubspaceProjectionIndex<NV extends NumberVector<?>
protected void configEpsilon(Parameterization config, DistanceFunction<NV, D> rangeQueryDistanceFunction) {
D distanceParser = rangeQueryDistanceFunction != null ? rangeQueryDistanceFunction.getDistanceFactory() : null;
- DistanceParameter<D> epsilonP = new DistanceParameter<D>(AbstractProjectedDBSCAN.EPSILON_ID, distanceParser);
+ DistanceParameter<D> epsilonP = new DistanceParameter<>(AbstractProjectedDBSCAN.EPSILON_ID, distanceParser);
// parameter epsilon
if(config.grab(epsilonP)) {
epsilon = epsilonP.getValue();
diff --git a/src/de/lmu/ifi/dbs/elki/index/preprocessed/subspaceproj/FourCSubspaceIndex.java b/src/de/lmu/ifi/dbs/elki/index/preprocessed/subspaceproj/FourCSubspaceIndex.java
index 80212981..a6e59f3f 100644
--- a/src/de/lmu/ifi/dbs/elki/index/preprocessed/subspaceproj/FourCSubspaceIndex.java
+++ b/src/de/lmu/ifi/dbs/elki/index/preprocessed/subspaceproj/FourCSubspaceIndex.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.preprocessed.subspaceproj;
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,9 +30,9 @@ 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.ids.distance.DistanceDBIDList;
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.DistanceDBIDResult;
import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
import de.lmu.ifi.dbs.elki.logging.Logging;
import de.lmu.ifi.dbs.elki.logging.LoggingUtil;
@@ -93,7 +93,7 @@ public class FourCSubspaceIndex<V extends NumberVector<?>, D extends Distance<D>
}
@Override
- protected PCAFilteredResult computeProjection(DBIDRef id, DistanceDBIDResult<D> neighbors, Relation<V> database) {
+ protected PCAFilteredResult computeProjection(DBIDRef id, DistanceDBIDList<D> neighbors, Relation<V> database) {
ModifiableDBIDs ids = DBIDUtil.newArray(neighbors.size());
for (DBIDIter neighbor = neighbors.iter(); neighbor.valid(); neighbor.advance()) {
ids.add(neighbor);
@@ -124,6 +124,11 @@ public class FourCSubspaceIndex<V extends NumberVector<?>, D extends Distance<D>
return "4C-subspaces";
}
+ @Override
+ public void logStatistics() {
+ // No statistics to log.
+ }
+
/**
* Factory class for 4C preprocessors.
*
@@ -161,7 +166,7 @@ public class FourCSubspaceIndex<V extends NumberVector<?>, D extends Distance<D>
@Override
public FourCSubspaceIndex<V, D> instantiate(Relation<V> relation) {
- return new FourCSubspaceIndex<V, D>(relation, epsilon, rangeQueryDistanceFunction, minpts, pca);
+ return new FourCSubspaceIndex<>(relation, epsilon, rangeQueryDistanceFunction, minpts, pca);
}
/**
@@ -236,20 +241,20 @@ public class FourCSubspaceIndex<V extends NumberVector<?>, D extends Distance<D>
LoggingUtil.warning("Error in internal parameterization: " + e.getMessage());
}
- final ArrayList<ParameterConstraint<? super Double>> deltaCons = new ArrayList<ParameterConstraint<? super Double>>();
+ final ArrayList<ParameterConstraint<? super Double>> deltaCons = new ArrayList<>();
// TODO: this constraint is already set in the parameter itself, since
// it
// also applies to the relative case, right? -- erich
// deltaCons.add(new GreaterEqualConstraint(0));
deltaCons.add(new LessEqualConstraint(1));
- GlobalParameterConstraint gpc = new ParameterFlagGlobalConstraint<Double>(deltaP, deltaCons, absoluteF, false);
+ GlobalParameterConstraint gpc = new ParameterFlagGlobalConstraint<>(deltaP, deltaCons, absoluteF, false);
config.checkConstraint(gpc);
}
@Override
protected Factory<V, D> makeInstance() {
- return new Factory<V, D>(epsilon, rangeQueryDistanceFunction, minpts, pca);
+ return new Factory<>(epsilon, rangeQueryDistanceFunction, minpts, pca);
}
}
}
diff --git a/src/de/lmu/ifi/dbs/elki/index/preprocessed/subspaceproj/PreDeConSubspaceIndex.java b/src/de/lmu/ifi/dbs/elki/index/preprocessed/subspaceproj/PreDeConSubspaceIndex.java
index 17590804..69882c50 100644
--- a/src/de/lmu/ifi/dbs/elki/index/preprocessed/subspaceproj/PreDeConSubspaceIndex.java
+++ b/src/de/lmu/ifi/dbs/elki/index/preprocessed/subspaceproj/PreDeConSubspaceIndex.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.preprocessed.subspaceproj;
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,9 +26,9 @@ package de.lmu.ifi.dbs.elki.index.preprocessed.subspaceproj;
import de.lmu.ifi.dbs.elki.data.NumberVector;
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.distance.DistanceDBIDList;
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.DistanceDBIDResult;
import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
import de.lmu.ifi.dbs.elki.logging.Logging;
import de.lmu.ifi.dbs.elki.math.linearalgebra.Matrix;
@@ -86,7 +86,7 @@ public class PreDeConSubspaceIndex<V extends NumberVector<?>, D extends Distance
}
@Override
- protected SubspaceProjectionResult computeProjection(DBIDRef id, DistanceDBIDResult<D> neighbors, Relation<V> database) {
+ protected SubspaceProjectionResult computeProjection(DBIDRef id, DistanceDBIDList<D> neighbors, Relation<V> database) {
StringBuilder msg = null;
int referenceSetSize = neighbors.size();
@@ -170,6 +170,11 @@ public class PreDeConSubspaceIndex<V extends NumberVector<?>, D extends Distance
return LOG;
}
+ @Override
+ public void logStatistics() {
+ // No statistics to log.
+ }
+
/**
* Factory.
*
@@ -212,7 +217,7 @@ public class PreDeConSubspaceIndex<V extends NumberVector<?>, D extends Distance
@Override
public PreDeConSubspaceIndex<V, D> instantiate(Relation<V> relation) {
- return new PreDeConSubspaceIndex<V, D>(relation, epsilon, rangeQueryDistanceFunction, minpts, delta);
+ return new PreDeConSubspaceIndex<>(relation, epsilon, rangeQueryDistanceFunction, minpts, delta);
}
/**
@@ -241,7 +246,7 @@ public class PreDeConSubspaceIndex<V extends NumberVector<?>, D extends Distance
@Override
protected Factory<V, D> makeInstance() {
- return new Factory<V, D>(epsilon, rangeQueryDistanceFunction, minpts, delta);
+ return new Factory<>(epsilon, rangeQueryDistanceFunction, minpts, delta);
}
}
}
diff --git a/src/de/lmu/ifi/dbs/elki/index/preprocessed/subspaceproj/SubspaceProjectionIndex.java b/src/de/lmu/ifi/dbs/elki/index/preprocessed/subspaceproj/SubspaceProjectionIndex.java
index 67cc1701..f0fbbd35 100644
--- a/src/de/lmu/ifi/dbs/elki/index/preprocessed/subspaceproj/SubspaceProjectionIndex.java
+++ b/src/de/lmu/ifi/dbs/elki/index/preprocessed/subspaceproj/SubspaceProjectionIndex.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.preprocessed.subspaceproj;
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/preprocessed/subspaceproj/package-info.java b/src/de/lmu/ifi/dbs/elki/index/preprocessed/subspaceproj/package-info.java
index f6e5e925..4c529c66 100644
--- a/src/de/lmu/ifi/dbs/elki/index/preprocessed/subspaceproj/package-info.java
+++ b/src/de/lmu/ifi/dbs/elki/index/preprocessed/subspaceproj/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/projected/LatLngAsECEFIndex.java b/src/de/lmu/ifi/dbs/elki/index/projected/LatLngAsECEFIndex.java
new file mode 100644
index 00000000..8449996b
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/index/projected/LatLngAsECEFIndex.java
@@ -0,0 +1,292 @@
+package de.lmu.ifi.dbs.elki.index.projected;
+
+/*
+ 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.projection.LatLngToECEFProjection;
+import de.lmu.ifi.dbs.elki.data.projection.Projection;
+import de.lmu.ifi.dbs.elki.database.datastore.DataStoreFactory;
+import de.lmu.ifi.dbs.elki.database.datastore.DataStoreUtil;
+import de.lmu.ifi.dbs.elki.database.datastore.WritableDataStore;
+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.DatabaseQuery;
+import de.lmu.ifi.dbs.elki.database.query.distance.DistanceQuery;
+import de.lmu.ifi.dbs.elki.database.query.distance.SpatialPrimitiveDistanceQuery;
+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.query.rknn.RKNNQuery;
+import de.lmu.ifi.dbs.elki.database.relation.MaterializedRelation;
+import de.lmu.ifi.dbs.elki.database.relation.ProjectedView;
+import de.lmu.ifi.dbs.elki.database.relation.Relation;
+import de.lmu.ifi.dbs.elki.distance.distancefunction.geo.LatLngDistanceFunction;
+import de.lmu.ifi.dbs.elki.distance.distancefunction.minkowski.EuclideanDistanceFunction;
+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.Index;
+import de.lmu.ifi.dbs.elki.index.IndexFactory;
+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.math.geodesy.EarthModel;
+import de.lmu.ifi.dbs.elki.math.geodesy.SphericalVincentyEarthModel;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.AbstractParameterizer;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.Flag;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.ObjectParameter;
+
+/**
+ * Index a 2d data set (consisting of Lat/Lng pairs) by using a projection to 3D
+ * coordinates (WGS-86 to ECEF).
+ *
+ * Earth-Centered, Earth-Fixed (ECEF) is a 3D coordinate system, sometimes also
+ * referred to as XYZ, that uses 3 cartesian axes. The center is at the earths
+ * center of mass, the z axis points to the north pole. X axis is to the prime
+ * meridan at the equator (so latitude 0, longitude 0), and the Y axis is
+ * orthogonal going to the east (latitude 0, longitude 90°E).
+ *
+ * The Euclidean distance in this coordinate system is a lower bound for the
+ * great-circle distance, and Euclidean coordinates are supposedly easier to
+ * index.
+ *
+ * Note: this index will <b>only</b> support the distance function
+ * {@link LatLngDistanceFunction}, as it uses a projection that will map data
+ * according to this great circle distance. If the query hint
+ * {@link DatabaseQuery#HINT_EXACT} is set, it will not be used.
+ *
+ * @author Erich Schubert
+ *
+ * @param <O> Object type
+ */
+public class LatLngAsECEFIndex<O extends NumberVector<?>> extends ProjectedIndex<O, O> {
+ /**
+ * Constructor.
+ *
+ * @param relation Relation to index.
+ * @param proj Projection to use.
+ * @param view View to use.
+ * @param inner Index to wrap.
+ * @param norefine Refinement disable flag.
+ */
+ public LatLngAsECEFIndex(Relation<O> relation, Projection<O, O> proj, Relation<O> view, Index inner, boolean norefine) {
+ super(relation, proj, view, inner, norefine, 1.0);
+ }
+
+ @Override
+ public String getLongName() {
+ return "projected " + inner.getLongName();
+ }
+
+ @Override
+ public String getShortName() {
+ return "proj-" + inner.getShortName();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <D extends Distance<D>> KNNQuery<O, D> getKNNQuery(DistanceQuery<O, D> distanceQuery, Object... hints) {
+ if (!(inner instanceof KNNIndex)) {
+ return null;
+ }
+ if (distanceQuery.getRelation() != relation) {
+ return null;
+ }
+ if (!LatLngDistanceFunction.class.isInstance(distanceQuery.getDistanceFunction())) {
+ return null;
+ }
+ for (Object o : hints) {
+ if (o == DatabaseQuery.HINT_EXACT) {
+ return null;
+ }
+ }
+ SpatialPrimitiveDistanceQuery<O, DoubleDistance> innerQuery = EuclideanDistanceFunction.STATIC.instantiate(view);
+ KNNQuery<O, DoubleDistance> innerq = ((KNNIndex<O>) inner).getKNNQuery(innerQuery, hints);
+ if (innerq == null) {
+ return null;
+ }
+ return (KNNQuery<O, D>) new ProjectedKNNQuery<DoubleDistance>((DistanceQuery<O, DoubleDistance>) distanceQuery, innerq);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <D extends Distance<D>> RangeQuery<O, D> getRangeQuery(DistanceQuery<O, D> distanceQuery, Object... hints) {
+ if (!(inner instanceof RangeIndex)) {
+ return null;
+ }
+ if (distanceQuery.getRelation() != relation) {
+ return null;
+ }
+ if (!LatLngDistanceFunction.class.isInstance(distanceQuery.getDistanceFunction())) {
+ return null;
+ }
+ for (Object o : hints) {
+ if (o == DatabaseQuery.HINT_EXACT) {
+ return null;
+ }
+ }
+ SpatialPrimitiveDistanceQuery<O, DoubleDistance> innerQuery = EuclideanDistanceFunction.STATIC.instantiate(view);
+ RangeQuery<O, DoubleDistance> innerq = ((RangeIndex<O>) inner).getRangeQuery(innerQuery, hints);
+ if (innerq == null) {
+ return null;
+ }
+ return (RangeQuery<O, D>) new ProjectedRangeQuery<DoubleDistance>((DistanceQuery<O, DoubleDistance>) distanceQuery, innerq);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <D extends Distance<D>> RKNNQuery<O, D> getRKNNQuery(DistanceQuery<O, D> distanceQuery, Object... hints) {
+ if (!(inner instanceof RKNNIndex)) {
+ return null;
+ }
+ if (distanceQuery.getRelation() != relation) {
+ return null;
+ }
+ if (!LatLngDistanceFunction.class.isInstance(distanceQuery.getDistanceFunction())) {
+ return null;
+ }
+ for (Object o : hints) {
+ if (o == DatabaseQuery.HINT_EXACT) {
+ return null;
+ }
+ }
+ SpatialPrimitiveDistanceQuery<O, DoubleDistance> innerQuery = EuclideanDistanceFunction.STATIC.instantiate(view);
+ RKNNQuery<O, DoubleDistance> innerq = ((RKNNIndex<O>) inner).getRKNNQuery(innerQuery, hints);
+ if (innerq == null) {
+ return null;
+ }
+ return (RKNNQuery<O, D>) new ProjectedRKNNQuery<DoubleDistance>((DistanceQuery<O, DoubleDistance>) distanceQuery, innerq);
+ }
+
+ /**
+ * Index factory.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.has LatLngAsECEFIndex
+ *
+ * @param <O> Data type.
+ */
+ public static class Factory<O extends NumberVector<?>> extends ProjectedIndex.Factory<O, O> {
+ /**
+ * Disable refinement of distances.
+ */
+ boolean norefine = false;
+
+ /**
+ * Constructor.
+ *
+ * @param inner Inner index
+ * @param materialize Flag to materialize the projection
+ * @param norefine Flag to disable refinement of distances
+ * @param model Earth model
+ */
+ public Factory(IndexFactory<O, ?> inner, boolean materialize, boolean norefine, EarthModel model) {
+ super(new LatLngToECEFProjection<O>(model), inner, materialize, norefine, 1.0);
+ }
+
+ @Override
+ public ProjectedIndex<O, O> instantiate(Relation<O> relation) {
+ if (!proj.getInputDataTypeInformation().isAssignableFromType(relation.getDataTypeInformation())) {
+ return null;
+ }
+ proj.initialize(relation.getDataTypeInformation());
+ final Relation<O> view;
+ if (materialize) {
+ DBIDs ids = relation.getDBIDs();
+ WritableDataStore<O> content = DataStoreUtil.makeStorage(ids, DataStoreFactory.HINT_DB, proj.getOutputDataTypeInformation().getRestrictionClass());
+ for (DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) {
+ content.put(iter, proj.project(relation.get(iter)));
+ }
+ view = new MaterializedRelation<>("ECEF Projection", "ecef-projection", proj.getOutputDataTypeInformation(), content, ids);
+ } else {
+ view = new ProjectedView<>(relation, proj);
+ }
+ Index inneri = inner.instantiate(view);
+ if (inneri == null) {
+ return null;
+ }
+ return new LatLngAsECEFIndex<>(relation, proj, view, inneri, norefine);
+ }
+
+ /**
+ * Parameterization class.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.exclude
+ *
+ * @param <O> Outer object type.
+ */
+ public static class Parameterizer<O extends NumberVector<?>> extends AbstractParameterizer {
+ /**
+ * Inner index factory.
+ */
+ IndexFactory<O, ?> inner;
+
+ /**
+ * Whether to use a materialized view, or a virtual view.
+ */
+ boolean materialize = false;
+
+ /**
+ * Disable refinement of distances.
+ */
+ boolean norefine = false;
+
+ /**
+ * Earth model to use.
+ */
+ EarthModel model;
+
+ @Override
+ protected void makeOptions(Parameterization config) {
+ super.makeOptions(config);
+ ObjectParameter<EarthModel> modelP = new ObjectParameter<>(EarthModel.MODEL_ID, EarthModel.class, SphericalVincentyEarthModel.class);
+ if (config.grab(modelP)) {
+ model = modelP.instantiateClass(config);
+ }
+
+ ObjectParameter<IndexFactory<O, ?>> innerP = new ObjectParameter<>(ProjectedIndex.Factory.Parameterizer.INDEX_ID, IndexFactory.class);
+ if (config.grab(innerP)) {
+ inner = innerP.instantiateClass(config);
+ }
+
+ Flag materializeF = new Flag(ProjectedIndex.Factory.Parameterizer.MATERIALIZE_FLAG);
+ if (config.grab(materializeF)) {
+ materialize = materializeF.isTrue();
+ }
+
+ Flag norefineF = new Flag(ProjectedIndex.Factory.Parameterizer.DISABLE_REFINE_FLAG);
+ if (config.grab(norefineF)) {
+ norefine = norefineF.isTrue();
+ }
+ }
+
+ @Override
+ protected Factory<O> makeInstance() {
+ return new Factory<>(inner, materialize, norefine, model);
+ }
+ }
+ }
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/projected/LngLatAsECEFIndex.java b/src/de/lmu/ifi/dbs/elki/index/projected/LngLatAsECEFIndex.java
new file mode 100644
index 00000000..4bf97659
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/index/projected/LngLatAsECEFIndex.java
@@ -0,0 +1,287 @@
+package de.lmu.ifi.dbs.elki.index.projected;
+
+/*
+ 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.projection.LngLatToECEFProjection;
+import de.lmu.ifi.dbs.elki.data.projection.Projection;
+import de.lmu.ifi.dbs.elki.database.datastore.DataStoreFactory;
+import de.lmu.ifi.dbs.elki.database.datastore.DataStoreUtil;
+import de.lmu.ifi.dbs.elki.database.datastore.WritableDataStore;
+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.DatabaseQuery;
+import de.lmu.ifi.dbs.elki.database.query.distance.DistanceQuery;
+import de.lmu.ifi.dbs.elki.database.query.distance.SpatialPrimitiveDistanceQuery;
+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.query.rknn.RKNNQuery;
+import de.lmu.ifi.dbs.elki.database.relation.MaterializedRelation;
+import de.lmu.ifi.dbs.elki.database.relation.ProjectedView;
+import de.lmu.ifi.dbs.elki.database.relation.Relation;
+import de.lmu.ifi.dbs.elki.distance.distancefunction.geo.LngLatDistanceFunction;
+import de.lmu.ifi.dbs.elki.distance.distancefunction.minkowski.EuclideanDistanceFunction;
+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.Index;
+import de.lmu.ifi.dbs.elki.index.IndexFactory;
+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.math.geodesy.EarthModel;
+import de.lmu.ifi.dbs.elki.math.geodesy.SphericalVincentyEarthModel;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.AbstractParameterizer;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.Flag;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.ObjectParameter;
+
+/**
+ * Index a 2d data set (consisting of Lng/Lat pairs) by using a projection to 3D
+ * coordinates (WGS-86 to ECEF).
+ *
+ * Earth-Centered, Earth-Fixed (ECEF) is a 3D coordinate system, sometimes also
+ * referred to as XYZ, that uses 3 cartesian axes. The center is at the earths
+ * center of mass, the z axis points to the north pole. X axis is to the prime
+ * meridan at the equator (so latitude 0, longitude 0), and the Y axis is
+ * orthogonal going to the east (latitude 0, longitude 90°E).
+ *
+ * The Euclidean distance in this coordinate system is a lower bound for the
+ * great-circle distance, and Euclidean coordinates are supposedly easier to
+ * index.
+ *
+ * Note: this index will <b>only</b> support the distance function
+ * {@link LngLatDistanceFunction}, as it uses a projection that will map data
+ * according to this great circle distance. If the query hint
+ * {@link DatabaseQuery#HINT_EXACT} is set, it will not be used.
+ *
+ * @author Erich Schubert
+ *
+ * @param <O> Object type
+ */
+public class LngLatAsECEFIndex<O extends NumberVector<?>> extends ProjectedIndex<O, O> {
+ /**
+ * Constructor.
+ *
+ * @param relation Relation to index.
+ * @param proj Projection to use.
+ * @param view View to use.
+ * @param inner Index to wrap.
+ * @param norefine Refinement disable flag.
+ */
+ public LngLatAsECEFIndex(Relation<O> relation, Projection<O, O> proj, Relation<O> view, Index inner, boolean norefine) {
+ super(relation, proj, view, inner, norefine, 1.0);
+ }
+
+ @Override
+ public String getLongName() {
+ return "projected " + inner.getLongName();
+ }
+
+ @Override
+ public String getShortName() {
+ return "proj-" + inner.getShortName();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <D extends Distance<D>> KNNQuery<O, D> getKNNQuery(DistanceQuery<O, D> distanceQuery, Object... hints) {
+ if (!(inner instanceof KNNIndex)) {
+ return null;
+ }
+ if (distanceQuery.getRelation() != relation) {
+ return null;
+ }
+ if (!LngLatDistanceFunction.class.isInstance(distanceQuery.getDistanceFunction())) {
+ return null;
+ }
+ for (Object o : hints) {
+ if (o == DatabaseQuery.HINT_EXACT) {
+ return null;
+ }
+ }
+ SpatialPrimitiveDistanceQuery<O, DoubleDistance> innerQuery = EuclideanDistanceFunction.STATIC.instantiate(view);
+ KNNQuery<O, DoubleDistance> innerq = ((KNNIndex<O>) inner).getKNNQuery(innerQuery, hints);
+ if (innerq == null) {
+ return null;
+ }
+ return (KNNQuery<O, D>) new ProjectedKNNQuery<DoubleDistance>((DistanceQuery<O, DoubleDistance>) distanceQuery, innerq);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <D extends Distance<D>> RangeQuery<O, D> getRangeQuery(DistanceQuery<O, D> distanceQuery, Object... hints) {
+ if (!(inner instanceof RangeIndex)) {
+ return null;
+ }
+ if (distanceQuery.getRelation() != relation) {
+ return null;
+ }
+ if (!LngLatDistanceFunction.class.isInstance(distanceQuery.getDistanceFunction())) {
+ return null;
+ }
+ for (Object o : hints) {
+ if (o == DatabaseQuery.HINT_EXACT) {
+ return null;
+ }
+ }
+ SpatialPrimitiveDistanceQuery<O, DoubleDistance> innerQuery = EuclideanDistanceFunction.STATIC.instantiate(view);
+ RangeQuery<O, DoubleDistance> innerq = ((RangeIndex<O>) inner).getRangeQuery(innerQuery, hints);
+ if (innerq == null) {
+ return null;
+ }
+ return (RangeQuery<O, D>) new ProjectedRangeQuery<DoubleDistance>((DistanceQuery<O, DoubleDistance>) distanceQuery, innerq);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <D extends Distance<D>> RKNNQuery<O, D> getRKNNQuery(DistanceQuery<O, D> distanceQuery, Object... hints) {
+ if (!(inner instanceof RKNNIndex)) {
+ return null;
+ }
+ if (distanceQuery.getRelation() != relation) {
+ return null;
+ }
+ if (!LngLatDistanceFunction.class.isInstance(distanceQuery.getDistanceFunction())) {
+ return null;
+ }
+ for (Object o : hints) {
+ if (o == DatabaseQuery.HINT_EXACT) {
+ return null;
+ }
+ }
+ SpatialPrimitiveDistanceQuery<O, DoubleDistance> innerQuery = EuclideanDistanceFunction.STATIC.instantiate(view);
+ RKNNQuery<O, DoubleDistance> innerq = ((RKNNIndex<O>) inner).getRKNNQuery(innerQuery, hints);
+ if (innerq == null) {
+ return null;
+ }
+ return (RKNNQuery<O, D>) new ProjectedRKNNQuery<DoubleDistance>((DistanceQuery<O, DoubleDistance>) distanceQuery, innerq);
+ }
+
+ /**
+ * Index factory.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.has LngLatAsECEFIndex
+ *
+ * @param <O> Data type.
+ */
+ public static class Factory<O extends NumberVector<?>> extends ProjectedIndex.Factory<O, O> {
+ /**
+ * Constructor.
+ *
+ * @param inner Inner index
+ * @param materialize Flag to materialize the projection
+ * @param norefine Flag to disable refinement of distances
+ * @param model Earth model
+ */
+ public Factory(IndexFactory<O, ?> inner, boolean materialize, boolean norefine, EarthModel model) {
+ super(new LngLatToECEFProjection<O>(model), inner, materialize, norefine, 1.0);
+ }
+
+ @Override
+ public ProjectedIndex<O, O> instantiate(Relation<O> relation) {
+ if (!proj.getInputDataTypeInformation().isAssignableFromType(relation.getDataTypeInformation())) {
+ return null;
+ }
+ proj.initialize(relation.getDataTypeInformation());
+ final Relation<O> view;
+ if (materialize) {
+ DBIDs ids = relation.getDBIDs();
+ WritableDataStore<O> content = DataStoreUtil.makeStorage(ids, DataStoreFactory.HINT_DB, proj.getOutputDataTypeInformation().getRestrictionClass());
+ for (DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) {
+ content.put(iter, proj.project(relation.get(iter)));
+ }
+ view = new MaterializedRelation<>("ECEF Projection", "ecef-projection", proj.getOutputDataTypeInformation(), content, ids);
+ } else {
+ view = new ProjectedView<>(relation, proj);
+ }
+ Index inneri = inner.instantiate(view);
+ if (inneri == null) {
+ return null;
+ }
+ return new LngLatAsECEFIndex<>(relation, proj, view, inneri, norefine);
+ }
+
+ /**
+ * Parameterization class.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.exclude
+ *
+ * @param <O> Outer object type.
+ */
+ public static class Parameterizer<O extends NumberVector<?>> extends AbstractParameterizer {
+ /**
+ * Inner index factory.
+ */
+ IndexFactory<O, ?> inner;
+
+ /**
+ * Whether to use a materialized view, or a virtual view.
+ */
+ boolean materialize = false;
+
+ /**
+ * Disable refinement of distances.
+ */
+ boolean norefine = false;
+
+ /**
+ * Earth model to use.
+ */
+ EarthModel model;
+
+ @Override
+ protected void makeOptions(Parameterization config) {
+ super.makeOptions(config);
+ ObjectParameter<EarthModel> modelP = new ObjectParameter<>(EarthModel.MODEL_ID, EarthModel.class, SphericalVincentyEarthModel.class);
+ if (config.grab(modelP)) {
+ model = modelP.instantiateClass(config);
+ }
+
+ ObjectParameter<IndexFactory<O, ?>> innerP = new ObjectParameter<>(ProjectedIndex.Factory.Parameterizer.INDEX_ID, IndexFactory.class);
+ if (config.grab(innerP)) {
+ inner = innerP.instantiateClass(config);
+ }
+
+ Flag materializeF = new Flag(ProjectedIndex.Factory.Parameterizer.MATERIALIZE_FLAG);
+ if (config.grab(materializeF)) {
+ materialize = materializeF.isTrue();
+ }
+
+ Flag norefineF = new Flag(ProjectedIndex.Factory.Parameterizer.DISABLE_REFINE_FLAG);
+ if (config.grab(norefineF)) {
+ norefine = norefineF.isTrue();
+ }
+ }
+
+ @Override
+ protected Factory<O> makeInstance() {
+ return new Factory<>(inner, materialize, norefine, model);
+ }
+ }
+ }
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/projected/PINN.java b/src/de/lmu/ifi/dbs/elki/index/projected/PINN.java
new file mode 100644
index 00000000..bfb18fa8
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/index/projected/PINN.java
@@ -0,0 +1,166 @@
+package de.lmu.ifi.dbs.elki.index.projected;
+
+/*
+ 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.projection.RandomProjection;
+import de.lmu.ifi.dbs.elki.index.IndexFactory;
+import de.lmu.ifi.dbs.elki.math.linearalgebra.randomprojections.AchlioptasRandomProjectionFamily;
+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.constraints.GreaterEqualConstraint;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.IntParameter;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.ObjectParameter;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.RandomParameter;
+
+/**
+ * Projection-Indexed nearest-neighbors (PINN) is an index to retrieve the
+ * nearest neighbors in high dimensional spaces by using a random projection
+ * based index.
+ *
+ * Reference:
+ * <p>
+ * Finding local anomalies in very high dimensional space<br />
+ * T. de Vries, S. Chawla, M. E. Houle<br />
+ * In: Proc. IEEE 10th International Conference on Data Mining (ICDM)
+ * </p>
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.composedOf AchlioptasRandomProjection
+ *
+ * @param <O> Object type
+ */
+@Reference(title = "Finding local anomalies in very high dimensional space", authors = "T. de Vries, S. Chawla, M. E. Houle", booktitle = "Proc. IEEE 10th International Conference on Data Mining (ICDM)", url = "http://dx.doi.org/10.1109/ICDM.2010.151")
+public class PINN<O extends NumberVector<?>> extends ProjectedIndex.Factory<O, O> {
+ /**
+ * Constructor.
+ *
+ * @param inner Inner index
+ * @param t Target dimensionality
+ * @param s Sparsity
+ * @param h Neighborhood size multiplicator
+ * @param random Random generator factory
+ */
+ public PINN(IndexFactory<O, ?> inner, int t, double s, double h, RandomFactory random) {
+ super(new RandomProjection<O>(t, new AchlioptasRandomProjectionFamily(s, random)), inner, true, false, h);
+ }
+
+ /**
+ * Parameterization class.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.exclude
+ *
+ * @param <O> Outer object type.
+ */
+ public static class Parameterizer<O extends NumberVector<?>> extends AbstractParameterizer {
+ /**
+ * Target dimensionality.
+ */
+ public static final OptionID T_ID = new OptionID("pinn.t", "Target dimensionality.");
+
+ /**
+ * Sparsity option.
+ */
+ public static final OptionID S_ID = new OptionID("pinn.s", "Sparsity of the random projection.");
+
+ /**
+ * Neighborhood size.
+ */
+ public static final OptionID H_ID = new OptionID("pinn.hmult", "Multiplicator for neighborhood size.");
+
+ /**
+ * Random generator.
+ */
+ public static final OptionID RANDOM_ID = new OptionID("pinn.seed", "Random generator seed.");
+
+ /**
+ * Inner index factory.
+ */
+ IndexFactory<O, ?> inner;
+
+ /**
+ * Dimensionality.
+ */
+ int t;
+
+ /**
+ * Sparsity.
+ */
+ double s;
+
+ /**
+ * Multiplicator.
+ */
+ double h;
+
+ /**
+ * Random generator.
+ */
+ RandomFactory random;
+
+ @Override
+ protected void makeOptions(Parameterization config) {
+ super.makeOptions(config);
+ ObjectParameter<IndexFactory<O, ?>> innerP = new ObjectParameter<>(ProjectedIndex.Factory.Parameterizer.INDEX_ID, IndexFactory.class);
+ if (config.grab(innerP)) {
+ inner = innerP.instantiateClass(config);
+ }
+
+ IntParameter tP = new IntParameter(T_ID);
+ tP.addConstraint(new GreaterEqualConstraint(1));
+ if (config.grab(tP)) {
+ t = tP.intValue();
+ }
+
+ DoubleParameter sP = new DoubleParameter(S_ID, 1.);
+ sP.addConstraint(new GreaterEqualConstraint(1.));
+ if (config.grab(sP)) {
+ s = sP.doubleValue();
+ }
+
+ DoubleParameter hP = new DoubleParameter(H_ID, 3.);
+ hP.addConstraint(new GreaterEqualConstraint(1.));
+ if (config.grab(hP)) {
+ h = hP.doubleValue();
+ }
+
+ RandomParameter randomP = new RandomParameter(RANDOM_ID);
+ if (config.grab(randomP)) {
+ random = randomP.getValue();
+ }
+ }
+
+ @Override
+ protected PINN<O> makeInstance() {
+ return new PINN<>(inner, t, s, h, random);
+ }
+ }
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/projected/ProjectedIndex.java b/src/de/lmu/ifi/dbs/elki/index/projected/ProjectedIndex.java
new file mode 100644
index 00000000..d5dc86f9
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/index/projected/ProjectedIndex.java
@@ -0,0 +1,648 @@
+package de.lmu.ifi.dbs.elki.index.projected;
+
+/*
+ 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.List;
+
+import de.lmu.ifi.dbs.elki.data.projection.Projection;
+import de.lmu.ifi.dbs.elki.data.type.TypeInformation;
+import de.lmu.ifi.dbs.elki.database.datastore.DataStoreFactory;
+import de.lmu.ifi.dbs.elki.database.datastore.DataStoreUtil;
+import de.lmu.ifi.dbs.elki.database.datastore.WritableDataStore;
+import de.lmu.ifi.dbs.elki.database.ids.ArrayDBIDs;
+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.DistanceDBIDListIter;
+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.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.distance.ModifiableDoubleDistanceDBIDList;
+import de.lmu.ifi.dbs.elki.database.ids.generic.GenericDistanceDBIDList;
+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;
+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.MaterializedRelation;
+import de.lmu.ifi.dbs.elki.database.relation.ProjectedView;
+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.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.index.Index;
+import de.lmu.ifi.dbs.elki.index.IndexFactory;
+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.logging.Logging;
+import de.lmu.ifi.dbs.elki.logging.statistics.Counter;
+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.GreaterEqualConstraint;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.Flag;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.ObjectParameter;
+
+/**
+ * Class to index data in an arbitrary projection only.
+ *
+ * Note: be <b>careful</b> when using this class, as it may/will yield incorrect
+ * distances, depending on your projection! It may be desirable to use a
+ * modified index that corrects for this error, or supports specific
+ * combiantions only.
+ *
+ * See {@link LatLngAsECEFIndex} and {@link LngLatAsECEFIndex} for example
+ * indexes that support only a specific (good) combination.
+ *
+ * FIXME: add refinement to bulk queries!
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.composedOf ProjectedKNNQuery
+ * @apiviz.composedOf ProjectedRangeQuery
+ * @apiviz.composedOf ProjectedRKNNQuery
+ *
+ * @param <O> Outer object type.
+ * @param <I> Inner object type.
+ */
+public class ProjectedIndex<O, I> implements KNNIndex<O>, RKNNIndex<O>, RangeIndex<O> {
+ /**
+ * Class logger
+ */
+ private static final Logging LOG = Logging.getLogger(ProjectedIndex.class);
+
+ /**
+ * Inner index.
+ */
+ Index inner;
+
+ /**
+ * Projection.
+ */
+ Projection<O, I> proj;
+
+ /**
+ * The relation we predend to index.
+ */
+ Relation<O> relation;
+
+ /**
+ * The view that we really index.
+ */
+ Relation<I> view;
+
+ /**
+ * Refinement disable flag.
+ */
+ boolean norefine;
+
+ /**
+ * Multiplier for k.
+ */
+ double kmulti = 1.0;
+
+ /**
+ * Count the number of distance refinements computed.
+ */
+ final Counter refinements;
+
+ /**
+ * Constructor.
+ *
+ * @param relation Relation to index.
+ * @param proj Projection to use.
+ * @param view View to use.
+ * @param inner Index to wrap.
+ * @param norefine Refinement disable flag.
+ * @param kmulti Multiplicator for k
+ */
+ public ProjectedIndex(Relation<O> relation, Projection<O, I> proj, Relation<I> view, Index inner, boolean norefine, double kmulti) {
+ super();
+ this.relation = relation;
+ this.view = view;
+ this.inner = inner;
+ this.proj = proj;
+ this.norefine = norefine;
+ this.kmulti = kmulti;
+ this.refinements = LOG.isStatistics() ? LOG.newCounter(this.getClass().getName() + ".refinements") : null;
+ }
+
+ /**
+ * Count a single distance refinement.
+ */
+ private void countRefinement() {
+ if(refinements != null) {
+ refinements.increment();
+ }
+ }
+
+ @Override
+ public void initialize() {
+ inner.initialize();
+ }
+
+ @Override
+ public String getLongName() {
+ return "projected " + inner.getLongName();
+ }
+
+ @Override
+ public String getShortName() {
+ return "proj-" + inner.getShortName();
+ }
+
+ @Override
+ public void logStatistics() {
+ if(refinements != null) {
+ LOG.statistics(refinements);
+ }
+ inner.logStatistics();
+ }
+
+ @Override
+ public <D extends Distance<D>> KNNQuery<O, D> getKNNQuery(DistanceQuery<O, D> distanceQuery, Object... hints) {
+ if(!(inner instanceof KNNIndex)) {
+ return null;
+ }
+ if(distanceQuery.getRelation() != relation) {
+ return null;
+ }
+ for(Object o : hints) {
+ if(o == DatabaseQuery.HINT_EXACT) {
+ return null;
+ }
+ }
+ @SuppressWarnings("unchecked")
+ DistanceQuery<I, D> innerQuery = ((DistanceFunction<? super I, D>) distanceQuery.getDistanceFunction()).instantiate(view);
+ @SuppressWarnings("unchecked")
+ KNNQuery<I, D> innerq = ((KNNIndex<I>) inner).getKNNQuery(innerQuery, hints);
+ if(innerq == null) {
+ return null;
+ }
+ return new ProjectedKNNQuery<>(distanceQuery, innerq);
+ }
+
+ @Override
+ public <D extends Distance<D>> RangeQuery<O, D> getRangeQuery(DistanceQuery<O, D> distanceQuery, Object... hints) {
+ if(!(inner instanceof RangeIndex)) {
+ return null;
+ }
+ if(distanceQuery.getRelation() != relation) {
+ return null;
+ }
+ for(Object o : hints) {
+ if(o == DatabaseQuery.HINT_EXACT) {
+ return null;
+ }
+ }
+ @SuppressWarnings("unchecked")
+ DistanceQuery<I, D> innerQuery = ((DistanceFunction<? super I, D>) distanceQuery.getDistanceFunction()).instantiate(view);
+ @SuppressWarnings("unchecked")
+ RangeQuery<I, D> innerq = ((RangeIndex<I>) inner).getRangeQuery(innerQuery, hints);
+ if(innerq == null) {
+ return null;
+ }
+ return new ProjectedRangeQuery<>(distanceQuery, innerq);
+ }
+
+ @Override
+ public <D extends Distance<D>> RKNNQuery<O, D> getRKNNQuery(DistanceQuery<O, D> distanceQuery, Object... hints) {
+ if(!(inner instanceof RKNNIndex)) {
+ return null;
+ }
+ if(distanceQuery.getRelation() != relation) {
+ return null;
+ }
+ for(Object o : hints) {
+ if(o == DatabaseQuery.HINT_EXACT) {
+ return null;
+ }
+ }
+ @SuppressWarnings("unchecked")
+ DistanceQuery<I, D> innerQuery = ((DistanceFunction<? super I, D>) distanceQuery.getDistanceFunction()).instantiate(view);
+ @SuppressWarnings("unchecked")
+ RKNNQuery<I, D> innerq = ((RKNNIndex<I>) inner).getRKNNQuery(innerQuery, hints);
+ if(innerq == null) {
+ return null;
+ }
+ return new ProjectedRKNNQuery<>(distanceQuery, innerq);
+ }
+
+ /**
+ * Class to proxy kNN queries.
+ *
+ * @author Erich Schubert
+ *
+ * @param <D> Distance type
+ */
+ class ProjectedKNNQuery<D extends Distance<D>> implements KNNQuery<O, D> {
+ /**
+ * Inner kNN query.
+ */
+ KNNQuery<I, D> inner;
+
+ /**
+ * Distance query for refinement.
+ */
+ DistanceQuery<O, D> distq;
+
+ /**
+ * Constructor.
+ *
+ * @param inner Inner kNN query.
+ */
+ public ProjectedKNNQuery(DistanceQuery<O, D> distanceQuery, KNNQuery<I, D> inner) {
+ super();
+ this.inner = inner;
+ this.distq = distanceQuery;
+ }
+
+ @Override
+ public KNNList<D> getKNNForDBID(DBIDRef id, int k) {
+ // So we have to project the query point only once:
+ return getKNNForObject(relation.get(id), k);
+ }
+
+ @Override
+ public List<? extends KNNList<D>> getKNNForBulkDBIDs(ArrayDBIDs ids, int k) {
+ return inner.getKNNForBulkDBIDs(ids, k);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public KNNList<D> getKNNForObject(O obj, int k) {
+ final I pobj = proj.project(obj);
+ if(norefine) {
+ return inner.getKNNForObject(pobj, k);
+ }
+ KNNList<D> ilist = inner.getKNNForObject(pobj, (int) Math.ceil(k * kmulti));
+ if(distq.getDistanceFunction() instanceof PrimitiveDoubleDistanceFunction) {
+ PrimitiveDoubleDistanceFunction<? super O> df = (PrimitiveDoubleDistanceFunction<? super O>) distq.getDistanceFunction();
+ DoubleDistanceKNNHeap heap = (DoubleDistanceKNNHeap) DBIDUtil.newHeap(DoubleDistance.FACTORY, k);
+ for(DistanceDBIDListIter<D> iter = ilist.iter(); iter.valid(); iter.advance()) {
+ heap.add(df.doubleDistance(obj, distq.getRelation().get(iter)), iter);
+ countRefinement();
+ }
+ return (KNNList<D>) heap.toKNNList();
+ }
+ else {
+ KNNHeap<D> heap = DBIDUtil.newHeap(distq.getDistanceFactory(), k);
+ for(DistanceDBIDListIter<D> iter = ilist.iter(); iter.valid(); iter.advance()) {
+ heap.add(distq.distance(obj, iter), iter);
+ countRefinement();
+ }
+ return heap.toKNNList();
+ }
+ }
+ }
+
+ /**
+ * Class to proxy range queries.
+ *
+ * @author Erich Schubert
+ *
+ * @param <D> Distance type
+ */
+ class ProjectedRangeQuery<D extends Distance<D>> implements RangeQuery<O, D> {
+ /**
+ * Inner range query.
+ */
+ RangeQuery<I, D> inner;
+
+ /**
+ * Distance query for refinement.
+ */
+ DistanceQuery<O, D> distq;
+
+ /**
+ * Constructor.
+ *
+ * @param inner Inner range query.
+ */
+ public ProjectedRangeQuery(DistanceQuery<O, D> distanceQuery, RangeQuery<I, D> inner) {
+ super();
+ this.inner = inner;
+ this.distq = distanceQuery;
+ }
+
+ @Override
+ public DistanceDBIDList<D> getRangeForDBID(DBIDRef id, D range) {
+ // So we have to project the query point only once:
+ return getRangeForObject(relation.get(id), range);
+ }
+
+ @SuppressWarnings({ "unchecked" })
+ @Override
+ public DistanceDBIDList<D> getRangeForObject(O obj, D range) {
+ final I pobj = proj.project(obj);
+ DistanceDBIDList<D> ilist = inner.getRangeForObject(pobj, range);
+ if(norefine) {
+ return ilist;
+ }
+ if(distq.getDistanceFunction() instanceof PrimitiveDoubleDistanceFunction) {
+ PrimitiveDoubleDistanceFunction<? super O> df = (PrimitiveDoubleDistanceFunction<? super O>) distq.getDistanceFunction();
+ double drange = ((DoubleDistance) range).doubleValue();
+ ModifiableDoubleDistanceDBIDList olist = new DoubleDistanceDBIDPairList(ilist.size());
+ for(DistanceDBIDListIter<D> iter = ilist.iter(); iter.valid(); iter.advance()) {
+ final double dist = df.doubleDistance(obj, distq.getRelation().get(iter));
+ countRefinement();
+ if(dist <= drange) {
+ olist.add(dist, iter);
+ }
+ }
+ return (DistanceDBIDList<D>) olist;
+ }
+ else {
+ ModifiableDistanceDBIDList<D> olist = new GenericDistanceDBIDList<>(ilist.size());
+ for(DistanceDBIDListIter<D> iter = ilist.iter(); iter.valid(); iter.advance()) {
+ D dist = distq.distance(obj, iter);
+ countRefinement();
+ if(range.compareTo(dist) <= 0) {
+ olist.add(dist, iter);
+ }
+ }
+ return olist;
+ }
+ }
+ }
+
+ /**
+ * Class to proxy RkNN queries.
+ *
+ * @author Erich Schubert
+ *
+ * @param <D> Distance type
+ */
+ class ProjectedRKNNQuery<D extends Distance<D>> implements RKNNQuery<O, D> {
+ /**
+ * Inner RkNN query.
+ */
+ RKNNQuery<I, D> inner;
+
+ /**
+ * Distance query for refinement.
+ */
+ DistanceQuery<O, D> distq;
+
+ /**
+ * Constructor.
+ *
+ * @param inner Inner RkNN query.
+ */
+ public ProjectedRKNNQuery(DistanceQuery<O, D> distanceQuery, RKNNQuery<I, D> inner) {
+ super();
+ this.inner = inner;
+ this.distq = distanceQuery;
+ }
+
+ @Override
+ public DistanceDBIDList<D> getRKNNForDBID(DBIDRef id, int k) {
+ // So we have to project the query point only once:
+ return getRKNNForObject(relation.get(id), k);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public DistanceDBIDList<D> getRKNNForObject(O obj, int k) {
+ final I pobj = proj.project(obj);
+ if(norefine) {
+ return inner.getRKNNForObject(pobj, k);
+ }
+ DistanceDBIDList<D> ilist = inner.getRKNNForObject(pobj, (int) Math.ceil(k * kmulti));
+ if(distq.getDistanceFunction() instanceof PrimitiveDoubleDistanceFunction) {
+ PrimitiveDoubleDistanceFunction<? super O> df = (PrimitiveDoubleDistanceFunction<? super O>) distq.getDistanceFunction();
+ ModifiableDoubleDistanceDBIDList olist = new DoubleDistanceDBIDPairList(ilist.size());
+ for(DistanceDBIDListIter<D> iter = ilist.iter(); iter.valid(); iter.advance()) {
+ final double dist = df.doubleDistance(obj, distq.getRelation().get(iter));
+ countRefinement();
+ olist.add(dist, iter);
+ }
+ return (DistanceDBIDList<D>) olist;
+ }
+ else {
+ ModifiableDistanceDBIDList<D> olist = new GenericDistanceDBIDList<>(ilist.size());
+ for(DistanceDBIDListIter<D> iter = ilist.iter(); iter.valid(); iter.advance()) {
+ D dist = distq.distance(obj, iter);
+ countRefinement();
+ olist.add(dist, iter);
+ }
+ return olist;
+ }
+ }
+
+ @Override
+ public List<? extends DistanceDBIDList<D>> getRKNNForBulkDBIDs(ArrayDBIDs ids, int k) {
+ return inner.getRKNNForBulkDBIDs(ids, k);
+ }
+ }
+
+ /**
+ * Index factory.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.has ProjectedIndex
+ *
+ * @param <O> Outer object type.
+ * @param <I> Inner object type.
+ */
+ public static class Factory<O, I> implements IndexFactory<O, ProjectedIndex<O, I>> {
+ /**
+ * Projection to use.
+ */
+ Projection<O, I> proj;
+
+ /**
+ * Inner index factory.
+ */
+ IndexFactory<I, ?> inner;
+
+ /**
+ * Whether to use a materialized view, or a virtual view.
+ */
+ boolean materialize = false;
+
+ /**
+ * Disable refinement of distances.
+ */
+ boolean norefine = false;
+
+ /**
+ * Multiplier for k.
+ */
+ double kmulti = 1.0;
+
+ /**
+ * Constructor.
+ *
+ * @param proj Projection
+ * @param inner Inner index
+ * @param materialize Flag for materializing
+ * @param norefine Disable refinement of distances
+ * @param kmulti Multiplicator for k.
+ */
+ public Factory(Projection<O, I> proj, IndexFactory<I, ?> inner, boolean materialize, boolean norefine, double kmulti) {
+ super();
+ this.proj = proj;
+ this.inner = inner;
+ this.materialize = materialize;
+ this.kmulti = kmulti;
+ }
+
+ @Override
+ public ProjectedIndex<O, I> instantiate(Relation<O> relation) {
+ if(!proj.getInputDataTypeInformation().isAssignableFromType(relation.getDataTypeInformation())) {
+ return null;
+ }
+ // FIXME: non re-entrant!
+ proj.initialize(relation.getDataTypeInformation());
+ Index inneri = null;
+ Relation<I> view = null;
+ if(materialize) {
+ DBIDs ids = relation.getDBIDs();
+ WritableDataStore<I> content = DataStoreUtil.makeStorage(ids, DataStoreFactory.HINT_DB, proj.getOutputDataTypeInformation().getRestrictionClass());
+ for(DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) {
+ content.put(iter, proj.project(relation.get(iter)));
+ }
+ view = new MaterializedRelation<>("Projected Index", "projected-index", proj.getOutputDataTypeInformation(), content, ids);
+ }
+ else {
+ view = new ProjectedView<>(relation, proj);
+ }
+ inneri = inner.instantiate(view);
+ if(inneri == null) {
+ return null;
+ }
+ return new ProjectedIndex<>(relation, proj, view, inneri, norefine, kmulti);
+ }
+
+ @Override
+ public TypeInformation getInputTypeRestriction() {
+ return proj.getInputDataTypeInformation();
+ }
+
+ /**
+ * Parameterization class.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.exclude
+ *
+ * @param <O> Outer object type.
+ * @param <I> Inner object type.
+ */
+ public static class Parameterizer<O, I> extends AbstractParameterizer {
+ /**
+ * Option ID for the projection to use.
+ */
+ public static final OptionID PROJ_ID = new OptionID("projindex.proj", "Projection to use for the projected index.");
+
+ /**
+ * Option ID for the inner index to use.
+ */
+ public static final OptionID INDEX_ID = new OptionID("projindex.inner", "Index to use on the projected data.");
+
+ /**
+ * Option ID for materialization.
+ */
+ public static final OptionID MATERIALIZE_FLAG = new OptionID("projindex.materialize", "Flag to materialize the projected data.");
+
+ /**
+ * Option ID for disabling refinement.
+ */
+ public static final OptionID DISABLE_REFINE_FLAG = new OptionID("projindex.disable-refine", "Flag to disable refinement of distances.");
+
+ /**
+ * Option ID for querying a larger k.
+ */
+ public static final OptionID K_MULTIPLIER_ID = new OptionID("projindex.kmulti", "Multiplier for k.");
+
+ /**
+ * Projection to use.
+ */
+ Projection<O, I> proj;
+
+ /**
+ * Inner index factory.
+ */
+ IndexFactory<I, ?> inner;
+
+ /**
+ * Whether to use a materialized view, or a virtual view.
+ */
+ boolean materialize = false;
+
+ /**
+ * Disable refinement of distances.
+ */
+ boolean norefine = false;
+
+ /**
+ * Multiplier for k.
+ */
+ double kmulti = 1.0;
+
+ @Override
+ protected void makeOptions(Parameterization config) {
+ super.makeOptions(config);
+ ObjectParameter<Projection<O, I>> projP = new ObjectParameter<>(PROJ_ID, Projection.class);
+ if(config.grab(projP)) {
+ proj = projP.instantiateClass(config);
+ }
+ ObjectParameter<IndexFactory<I, ?>> innerP = new ObjectParameter<>(INDEX_ID, IndexFactory.class);
+ if(config.grab(innerP)) {
+ inner = innerP.instantiateClass(config);
+ }
+ Flag materializeF = new Flag(MATERIALIZE_FLAG);
+ if(config.grab(materializeF)) {
+ materialize = materializeF.isTrue();
+ }
+ Flag norefineF = new Flag(DISABLE_REFINE_FLAG);
+ if(config.grab(norefineF)) {
+ norefine = norefineF.isTrue();
+ }
+ if(!norefine) {
+ DoubleParameter kmultP = new DoubleParameter(K_MULTIPLIER_ID);
+ kmultP.setDefaultValue(1.0);
+ kmultP.addConstraint(new GreaterEqualConstraint(1.0));
+ if(config.grab(kmultP)) {
+ kmulti = kmultP.doubleValue();
+ }
+ }
+ }
+
+ @Override
+ protected Factory<O, I> makeInstance() {
+ return new Factory<>(proj, inner, materialize, norefine, kmulti);
+ }
+ }
+ }
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/projected/package-info.java b/src/de/lmu/ifi/dbs/elki/index/projected/package-info.java
new file mode 100644
index 00000000..8a311292
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/index/projected/package-info.java
@@ -0,0 +1,26 @@
+/**
+ * <p>Projected indexes for data.</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.projected;
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
diff --git a/src/de/lmu/ifi/dbs/elki/index/vafile/PartialVAFile.java b/src/de/lmu/ifi/dbs/elki/index/vafile/PartialVAFile.java
index 37fbe994..0cbb7c56 100644
--- a/src/de/lmu/ifi/dbs/elki/index/vafile/PartialVAFile.java
+++ b/src/de/lmu/ifi/dbs/elki/index/vafile/PartialVAFile.java
@@ -38,7 +38,9 @@ import de.lmu.ifi.dbs.elki.data.type.TypeUtil;
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.DBIDUtil;
-import de.lmu.ifi.dbs.elki.database.ids.DBIDs;
+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.DoubleDistanceKNNList;
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;
@@ -46,21 +48,19 @@ 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.LPNormDistanceFunction;
+import de.lmu.ifi.dbs.elki.distance.distancefunction.minkowski.LPNormDistanceFunction;
import de.lmu.ifi.dbs.elki.distance.distancefunction.subspace.SubspaceLPNormDistanceFunction;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.DoubleDistanceDBIDList;
-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.Distance;
import de.lmu.ifi.dbs.elki.distance.distancevalue.DoubleDistance;
import de.lmu.ifi.dbs.elki.index.AbstractRefiningIndex;
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.index.tree.TreeIndexFactory;
import de.lmu.ifi.dbs.elki.logging.Logging;
+import de.lmu.ifi.dbs.elki.logging.statistics.Counter;
import de.lmu.ifi.dbs.elki.math.MathUtil;
import de.lmu.ifi.dbs.elki.math.linearalgebra.Vector;
+import de.lmu.ifi.dbs.elki.persistent.AbstractPageFileFactory;
import de.lmu.ifi.dbs.elki.persistent.ByteArrayUtil;
import de.lmu.ifi.dbs.elki.utilities.datastructures.heap.DoubleMaxHeap;
import de.lmu.ifi.dbs.elki.utilities.documentation.Reference;
@@ -89,7 +89,7 @@ import de.lmu.ifi.dbs.elki.utilities.pairs.DoubleObjPair;
* @apiviz.landmark
*
* @apiviz.composedOf DAFile
- * @apiviz.uses PartialVACandidate
+ * @apiviz.has PartialVACandidate
* @apiviz.has PartialVAFileRangeQuery
* @apiviz.has PartialVAFileKNNQuery
*
@@ -143,11 +143,11 @@ public class PartialVAFile<V extends NumberVector<?>> extends AbstractRefiningIn
super(relation);
this.pageSize = pageSize;
this.partitions = partitions;
- this.stats = new Statistics();
+ this.stats = new Statistics(this.getClass().getName());
}
@Override
- public void initialize(Relation<V> relation, DBIDs ids) throws IllegalStateException {
+ public void initialize() throws IllegalStateException {
if(splitPartitions != null) {
throw new IllegalStateException("Data already inserted.");
}
@@ -159,15 +159,15 @@ public class PartialVAFile<V extends NumberVector<?>> extends AbstractRefiningIn
final int dimensions = RelationUtil.dimensionality(relation);
splitPartitions = new double[dimensions][];
- daFiles = new ArrayList<DAFile>(dimensions);
+ daFiles = new ArrayList<>(dimensions);
for(int d = 0; d < dimensions; d++) {
final DAFile f = new DAFile(relation, d, partitions);
splitPartitions[d] = f.getSplitPositions();
daFiles.add(f);
}
- vectorApprox = new ArrayList<VectorApproximation>();
- for (DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) {
+ vectorApprox = new ArrayList<>();
+ for(DBIDIter iter = relation.iterDBIDs(); iter.valid(); iter.advance()) {
DBID id = DBIDUtil.deref(iter);
V dv = relation.get(id);
VectorApproximation va = calculateFullApproximation(id, dv);
@@ -185,6 +185,16 @@ public class PartialVAFile<V extends NumberVector<?>> extends AbstractRefiningIn
return "partial va-file";
}
+ @Override
+ public Logging getLogger() {
+ return LOG;
+ }
+
+ @Override
+ public void logStatistics() {
+ stats.logStatistics();
+ }
+
/**
* Fake subspace (full-dimensional).
*
@@ -298,21 +308,21 @@ public class PartialVAFile<V extends NumberVector<?>> extends AbstractRefiningIn
final int dimensions = query.getDimensionality();
double[] lowerVals = new double[dimensions];
double[] upperVals = new double[dimensions];
-
+
VectorApproximation queryApprox = calculatePartialApproximation(null, query, daFiles);
-
+
for(int i = 0; i < dimensions; i++) {
final double val = query.doubleValue(i);
lowerVals[i] = val - epsilon;
upperVals[i] = val + epsilon;
}
-
+
Vector lowerEpsilon = new Vector(lowerVals);
VectorApproximation lowerEpsilonPartitions = calculatePartialApproximation(null, lowerEpsilon, daFiles);
-
+
Vector upperEpsilon = new Vector(upperVals);
VectorApproximation upperEpsilonPartitions = calculatePartialApproximation(null, upperEpsilon, daFiles);
-
+
for(int i = 0; i < daFiles.size(); i++) {
int coeff = (queryApprox.getApproximation(i) - lowerEpsilonPartitions.getApproximation(i)) + (upperEpsilonPartitions.getApproximation(i) - queryApprox.getApproximation(i)) + 1;
daFiles.get(i).first = coeff;
@@ -334,7 +344,7 @@ public class PartialVAFile<V extends NumberVector<?>> extends AbstractRefiningIn
double[] borders = daFiles.get(i).second.getSplitPositions();
assert borders != null : "borders are null";
int lastBorderIndex = borders.length - 1;
-
+
// value is lower outlier
if(val < borders[0]) {
approximation[i] = 0;
@@ -361,13 +371,59 @@ public class PartialVAFile<V extends NumberVector<?>> extends AbstractRefiningIn
* @apiviz.exclude
*/
public static class Statistics {
- public long scannedBytes = 0;
+ private Counter scannedBytes;
+
+ private Counter queryTime;
+
+ private Counter issuedQueries;
+
+ private Counter refinements;
+
+ protected Statistics(String parent) {
+ scannedBytes = LOG.isStatistics() ? LOG.newCounter(parent + ".scannedBytes") : null;
+ queryTime = LOG.isStatistics() ? LOG.newCounter(parent + ".queryTime") : null;
+ issuedQueries = LOG.isStatistics() ? LOG.newCounter(parent + ".issuedQueries") : null;
+ refinements = LOG.isStatistics() ? LOG.newCounter(parent + ".refinements") : null;
+ }
+
+ public void logStatistics() {
+ if(scannedBytes != null) {
+ LOG.statistics(scannedBytes);
+ }
+ if(queryTime != null) {
+ LOG.statistics(queryTime);
+ }
+ if(issuedQueries != null) {
+ LOG.statistics(issuedQueries);
+ }
+ if(refinements != null) {
+ LOG.statistics(refinements);
+ }
+ }
+
+ protected void incrementScannedBytes(long bytes) {
+ if(scannedBytes != null) {
+ scannedBytes.increment(bytes);
+ }
+ }
- public long queryTime = 0;
+ protected void incrementQueryTime(long time) {
+ if(queryTime != null) {
+ queryTime.increment(time);
+ }
+ }
- public int issuedQueries = 0;
+ protected void incrementIssuedQueries() {
+ if(issuedQueries != null) {
+ issuedQueries.increment();
+ }
+ }
- public int refinements = 0;
+ protected void incrementRefinements() {
+ if(refinements != null) {
+ refinements.increment();
+ }
+ }
}
/**
@@ -453,8 +509,8 @@ public class PartialVAFile<V extends NumberVector<?>> extends AbstractRefiningIn
}
@Override
- public DoubleDistanceDBIDList getRangeForObject(V query, DoubleDistance range) {
- stats.issuedQueries++;
+ public DoubleDistanceDBIDPairList getRangeForObject(V query, DoubleDistance range) {
+ stats.incrementIssuedQueries();
long t = System.nanoTime();
final double epsilonP = Math.pow(range.doubleValue(), p);
@@ -468,10 +524,10 @@ public class PartialVAFile<V extends NumberVector<?>> extends AbstractRefiningIn
// filter step
// calculate selectivity coefficients
- List<DoubleObjPair<DAFile>> subspaceDAFiles = new ArrayList<DoubleObjPair<DAFile>>(subspace.cardinality());
+ List<DoubleObjPair<DAFile>> subspaceDAFiles = new ArrayList<>(subspace.cardinality());
for(int d = subspace.nextSetBit(0); d >= 0; d = subspace.nextSetBit(d + 1)) {
DAFile daFile = daFiles.get(d);
- subspaceDAFiles.add(new DoubleObjPair<DAFile>(-1, daFile));
+ subspaceDAFiles.add(new DoubleObjPair<>(-1, daFile));
}
calculateSelectivityCoeffs(subspaceDAFiles, query, range.doubleValue());
// sort DA files by selectivity
@@ -481,7 +537,7 @@ public class PartialVAFile<V extends NumberVector<?>> extends AbstractRefiningIn
// create candidate list (all objects) and prune candidates w.r.t.
// mindist (i.e. remove them from the list)
// important: this structure contains the maxDist values for refinement!
- DoubleDistanceDBIDList result = new DoubleDistanceDBIDList();
+ DoubleDistanceDBIDPairList result = new DoubleDistanceDBIDPairList();
int candidates = 0;
for(VectorApproximation va : vectorApprox) {
DBID id = va.getId();
@@ -508,7 +564,7 @@ public class PartialVAFile<V extends NumberVector<?>> extends AbstractRefiningIn
}
else { // refine candidate - true refinement
DoubleDistance dis = refine(id, query);
- stats.refinements += 1;
+ stats.incrementRefinements();
if(dis.doubleValue() <= range.doubleValue()) {
result.add(dis.doubleValue(), id);
}
@@ -517,9 +573,9 @@ public class PartialVAFile<V extends NumberVector<?>> extends AbstractRefiningIn
}
result.sort();
- stats.scannedBytes += relation.size() * VectorApproximation.byteOnDisk(subspace.cardinality(), partitions);
+ stats.incrementScannedBytes(relation.size() * VectorApproximation.byteOnDisk(subspace.cardinality(), partitions));
- stats.queryTime += System.nanoTime() - t;
+ stats.incrementQueryTime(System.nanoTime() - t);
if(LOG.isDebuggingFine()) {
LOG.fine("query = " + query);
@@ -562,7 +618,7 @@ public class PartialVAFile<V extends NumberVector<?>> extends AbstractRefiningIn
@Override
public DoubleDistanceKNNList getKNNForObject(V query, int k) {
- stats.issuedQueries++;
+ stats.incrementIssuedQueries();
long t = System.nanoTime();
// generate query approximation and lookup table
@@ -603,9 +659,9 @@ public class PartialVAFile<V extends NumberVector<?>> extends AbstractRefiningIn
if(candidates2 != null) {
candidates1 = candidates2;
}
- candidates2 = new LinkedList<PartialVACandidate>();
+ candidates2 = new LinkedList<>();
- DoubleMaxHeap kMinMaxDists = new DoubleMaxHeap(k+1);
+ DoubleMaxHeap kMinMaxDists = new DoubleMaxHeap(k + 1);
for(PartialVACandidate va : candidates1) {
int dimension = daFiles.get(addition).getDimension();
int objectCell = va.getApproximation(dimension);
@@ -628,21 +684,21 @@ public class PartialVAFile<V extends NumberVector<?>> extends AbstractRefiningIn
}
}
- stats.scannedBytes += relation.size() * VectorApproximation.byteOnDisk(addition, partitions);
+ stats.incrementScannedBytes(relation.size() * VectorApproximation.byteOnDisk(addition, partitions));
// refinement step
- ArrayList<PartialVACandidate> sortedCandidates = new ArrayList<PartialVACandidate>(candidates2);
+ ArrayList<PartialVACandidate> sortedCandidates = new ArrayList<>(candidates2);
// sort candidates by lower bound (minDist)
Collections.sort(sortedCandidates);
DoubleDistanceKNNList result = retrieveAccurateDistances(sortedCandidates, k, subspace, query);
- stats.queryTime += System.nanoTime() - t;
+ stats.incrementQueryTime(System.nanoTime() - t);
return result;
}
private LinkedList<PartialVACandidate> filter1(int k, int reducedDims, List<DAFile> daFiles, VectorApproximation queryApprox, int subspaceDims, VALPNormDistance dist) {
- LinkedList<PartialVACandidate> candidates1 = new LinkedList<PartialVACandidate>();
- DoubleMaxHeap minmaxdist = new DoubleMaxHeap(k+1);
+ LinkedList<PartialVACandidate> candidates1 = new LinkedList<>();
+ DoubleMaxHeap minmaxdist = new DoubleMaxHeap(k + 1);
for(VectorApproximation va : vectorApprox) {
PartialVACandidate pva = new PartialVACandidate(va);
@@ -704,7 +760,7 @@ public class PartialVAFile<V extends NumberVector<?>> extends AbstractRefiningIn
*/
public List<DAFile> getWorstCaseDistOrder(VALPNormDistance dist, BitSet subspace) {
int subspaceLength = subspace.cardinality();
- List<DAFile> result = new ArrayList<DAFile>(subspaceLength);
+ List<DAFile> result = new ArrayList<>(subspaceLength);
for(int i = subspace.nextSetBit(0); i >= 0; i = subspace.nextSetBit(i + 1)) {
result.add(daFiles.get(i));
}
@@ -713,13 +769,13 @@ public class PartialVAFile<V extends NumberVector<?>> extends AbstractRefiningIn
}
protected DoubleDistanceKNNList retrieveAccurateDistances(List<PartialVACandidate> sortedCandidates, int k, BitSet subspace, V query) {
- DoubleDistanceKNNHeap result = new DoubleDistanceKNNHeap(k);
+ DoubleDistanceKNNHeap result = (DoubleDistanceKNNHeap) DBIDUtil.newHeap(DoubleDistance.FACTORY, k);
for(PartialVACandidate va : sortedCandidates) {
double stopdist = result.doubleKNNDistance();
DBID currentID = va.getId();
if(result.size() < k || va.minDistP < stopdist) {
DoubleDistance dist = refine(currentID, query);
- stats.refinements += 1;
+ stats.incrementRefinements();
if(dist.doubleValue() < stopdist) {
result.add(dist.doubleValue(), currentID);
}
@@ -791,7 +847,7 @@ public class PartialVAFile<V extends NumberVector<?>> extends AbstractRefiningIn
@Override
public PartialVAFile<V> instantiate(Relation<V> relation) {
- return new PartialVAFile<V>(pagesize, relation, numpart);
+ return new PartialVAFile<>(pagesize, relation, numpart);
}
@Override
@@ -820,7 +876,7 @@ public class PartialVAFile<V extends NumberVector<?>> extends AbstractRefiningIn
@Override
protected void makeOptions(Parameterization config) {
super.makeOptions(config);
- IntParameter pagesizeP = new IntParameter(TreeIndexFactory.PAGE_SIZE_ID, 1024);
+ IntParameter pagesizeP = new IntParameter(AbstractPageFileFactory.Parameterizer.PAGE_SIZE_ID, 1024);
pagesizeP.addConstraint(new GreaterConstraint(0));
if(config.grab(pagesizeP)) {
pagesize = pagesizeP.getValue();
@@ -834,8 +890,8 @@ public class PartialVAFile<V extends NumberVector<?>> extends AbstractRefiningIn
@Override
protected Factory<?> makeInstance() {
- return new Factory<NumberVector<?>>(pagesize, numpart);
+ return new Factory<>(pagesize, numpart);
}
}
}
-} \ No newline at end of file
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/vafile/VAFile.java b/src/de/lmu/ifi/dbs/elki/index/vafile/VAFile.java
index 09b91be7..e6da2ec9 100644
--- a/src/de/lmu/ifi/dbs/elki/index/vafile/VAFile.java
+++ b/src/de/lmu/ifi/dbs/elki/index/vafile/VAFile.java
@@ -34,7 +34,9 @@ import de.lmu.ifi.dbs.elki.data.type.TypeUtil;
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.DBIDUtil;
-import de.lmu.ifi.dbs.elki.database.ids.DBIDs;
+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.DoubleDistanceKNNList;
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;
@@ -42,18 +44,15 @@ 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.LPNormDistanceFunction;
-import de.lmu.ifi.dbs.elki.distance.distanceresultlist.DoubleDistanceDBIDList;
-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.distancefunction.minkowski.LPNormDistanceFunction;
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.AbstractRefiningIndex;
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.index.tree.TreeIndexFactory;
import de.lmu.ifi.dbs.elki.logging.Logging;
+import de.lmu.ifi.dbs.elki.persistent.AbstractPageFileFactory;
import de.lmu.ifi.dbs.elki.utilities.datastructures.heap.DoubleMaxHeap;
import de.lmu.ifi.dbs.elki.utilities.documentation.Reference;
import de.lmu.ifi.dbs.elki.utilities.documentation.Title;
@@ -131,13 +130,13 @@ public class VAFile<V extends NumberVector<?>> extends AbstractRefiningIndex<V>
this.partitions = partitions;
this.pageSize = pageSize;
this.scans = 0;
- this.vectorApprox = new ArrayList<VectorApproximation>();
+ this.vectorApprox = new ArrayList<>();
}
@Override
- protected void initialize(Relation<V> relation, DBIDs ids) {
+ public void initialize() {
setPartitions(relation);
- for (DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) {
+ for (DBIDIter iter = relation.iterDBIDs(); iter.valid(); iter.advance()) {
DBID id = DBIDUtil.deref(iter);
vectorApprox.add(calculateApproximation(id, relation.get(id)));
}
@@ -150,7 +149,7 @@ public class VAFile<V extends NumberVector<?>> extends AbstractRefiningIndex<V>
* @throws IllegalArgumentException
*/
public void setPartitions(Relation<V> relation) throws IllegalArgumentException {
- if((Math.log(partitions) / Math.log(2)) != (int) (Math.log(partitions) / Math.log(2))) {
+ if ((Math.log(partitions) / Math.log(2)) != (int) (Math.log(partitions) / Math.log(2))) {
throw new IllegalArgumentException("Number of partitions must be a power of 2!");
}
@@ -158,16 +157,16 @@ public class VAFile<V extends NumberVector<?>> extends AbstractRefiningIndex<V>
final int size = relation.size();
splitPositions = new double[dimensions][partitions + 1];
- for(int d = 0; d < dimensions; d++) {
+ for (int d = 0; d < dimensions; d++) {
double[] tempdata = new double[size];
int j = 0;
- for(DBIDIter iditer = relation.iterDBIDs(); iditer.valid(); iditer.advance()) {
+ for (DBIDIter iditer = relation.iterDBIDs(); iditer.valid(); iditer.advance()) {
tempdata[j] = relation.get(iditer).doubleValue(d);
j += 1;
}
Arrays.sort(tempdata);
- for(int b = 0; b < partitions; b++) {
+ for (int b = 0; b < partitions; b++) {
int start = (int) (b * size / (double) partitions);
splitPositions[d][b] = tempdata[start];
}
@@ -185,20 +184,20 @@ public class VAFile<V extends NumberVector<?>> extends AbstractRefiningIndex<V>
*/
public VectorApproximation calculateApproximation(DBID id, V dv) {
int approximation[] = new int[dv.getDimensionality()];
- for(int d = 0; d < splitPositions.length; d++) {
+ for (int d = 0; d < splitPositions.length; d++) {
final double val = dv.doubleValue(d);
final int lastBorderIndex = splitPositions[d].length - 1;
// Value is below data grid
- if(val < splitPositions[d][0]) {
+ if (val < splitPositions[d][0]) {
approximation[d] = 0;
- if(id != null) {
+ if (id != null) {
LOG.warning("Vector outside of VAFile grid!");
}
} // Value is above data grid
- else if(val > splitPositions[d][lastBorderIndex]) {
+ else if (val > splitPositions[d][lastBorderIndex]) {
approximation[d] = lastBorderIndex - 1;
- if(id != null) {
+ if (id != null) {
LOG.warning("Vector outside of VAFile grid!");
}
} // normal case
@@ -212,24 +211,10 @@ public class VAFile<V extends NumberVector<?>> extends AbstractRefiningIndex<V>
return new VectorApproximation(id, approximation);
}
- @Override
- public long getReadOperations() {
- return getRandomReadOnly() + getScannedPages();
- }
-
- /**
- * Get the number of random read operations only.
- *
- * @return Random read operations.
- */
- public long getRandomReadOnly() {
- return super.getReadOperations();
- }
-
/**
* Get the number of scanned bytes.
*
- * @return Numebr of scanned bytes.
+ * @return Number of scanned bytes.
*/
public long getScannedPages() {
int vacapacity = pageSize / VectorApproximation.byteOnDisk(splitPositions.length, partitions);
@@ -238,15 +223,15 @@ public class VAFile<V extends NumberVector<?>> extends AbstractRefiningIndex<V>
}
@Override
- public long getWriteOperations() {
- return -1;
+ public Logging getLogger() {
+ return LOG;
}
@Override
- public void resetPageAccess() {
- super.resetPageAccess();
- scans = 0;
- // FIXME: writes
+ public void logStatistics() {
+ super.logStatistics();
+ // FIXME:
+ LOG.statistics("scanned pages:" + getScannedPages());
}
@Override
@@ -262,14 +247,14 @@ public class VAFile<V extends NumberVector<?>> extends AbstractRefiningIndex<V>
@SuppressWarnings("unchecked")
@Override
public <D extends Distance<D>> KNNQuery<V, D> getKNNQuery(DistanceQuery<V, D> distanceQuery, Object... hints) {
- for(Object hint : hints) {
- if(hint == DatabaseQuery.HINT_BULK) {
+ for (Object hint : hints) {
+ if (hint == DatabaseQuery.HINT_BULK) {
// FIXME: support bulk?
return null;
}
}
DistanceFunction<? super V, ?> df = distanceQuery.getDistanceFunction();
- if(df instanceof LPNormDistanceFunction) {
+ if (df instanceof LPNormDistanceFunction) {
double p = ((LPNormDistanceFunction) df).getP();
DistanceQuery<V, ?> ddq = (DistanceQuery<V, ?>) distanceQuery;
KNNQuery<V, ?> dq = new VAFileKNNQuery((DistanceQuery<V, DoubleDistance>) ddq, p);
@@ -283,7 +268,7 @@ public class VAFile<V extends NumberVector<?>> extends AbstractRefiningIndex<V>
@Override
public <D extends Distance<D>> RangeQuery<V, D> getRangeQuery(DistanceQuery<V, D> distanceQuery, Object... hints) {
DistanceFunction<? super V, ?> df = distanceQuery.getDistanceFunction();
- if(df instanceof LPNormDistanceFunction) {
+ if (df instanceof LPNormDistanceFunction) {
double p = ((LPNormDistanceFunction) df).getP();
DistanceQuery<V, ?> ddq = (DistanceQuery<V, ?>) distanceQuery;
RangeQuery<V, ?> dq = new VAFileRangeQuery((DistanceQuery<V, DoubleDistance>) ddq, p);
@@ -317,7 +302,7 @@ public class VAFile<V extends NumberVector<?>> extends AbstractRefiningIndex<V>
}
@Override
- public DoubleDistanceDBIDList getRangeForObject(V query, DoubleDistance range) {
+ public DoubleDistanceDBIDPairList getRangeForObject(V query, DoubleDistance range) {
final double eps = range.doubleValue();
// generate query approximation and lookup table
VectorApproximation queryApprox = calculateApproximation(null, query);
@@ -328,13 +313,13 @@ public class VAFile<V extends NumberVector<?>> extends AbstractRefiningIndex<V>
// Count a VA file scan
scans += 1;
- DoubleDistanceDBIDList result = new DoubleDistanceDBIDList();
+ DoubleDistanceDBIDPairList result = new DoubleDistanceDBIDPairList();
// Approximation step
- for(int i = 0; i < vectorApprox.size(); i++) {
+ for (int i = 0; i < vectorApprox.size(); i++) {
VectorApproximation va = vectorApprox.get(i);
double minDist = vadist.getMinDist(va);
- if(minDist > eps) {
+ if (minDist > eps) {
continue;
}
@@ -343,7 +328,7 @@ public class VAFile<V extends NumberVector<?>> extends AbstractRefiningIndex<V>
// refine the next element
final double dist = refine(va.id, query).doubleValue();
- if(dist <= eps) {
+ if (dist <= eps) {
result.add(dist, va.id);
}
}
@@ -383,29 +368,29 @@ public class VAFile<V extends NumberVector<?>> extends AbstractRefiningIndex<V>
VALPNormDistance vadist = new VALPNormDistance(p, splitPositions, query, queryApprox);
// Heap for the kth smallest maximum distance (yes, we need a max heap!)
- DoubleMaxHeap minMaxHeap = new DoubleMaxHeap(k+1);
+ DoubleMaxHeap minMaxHeap = new DoubleMaxHeap(k + 1);
double minMaxDist = Double.POSITIVE_INFINITY;
// Candidates with minDist <= kth maxDist
- ArrayList<DoubleObjPair<DBID>> candidates = new ArrayList<DoubleObjPair<DBID>>(vectorApprox.size());
+ ArrayList<DoubleObjPair<DBID>> candidates = new ArrayList<>(vectorApprox.size());
// Count a VA file scan
scans += 1;
// Approximation step
- for(int i = 0; i < vectorApprox.size(); i++) {
+ for (int i = 0; i < vectorApprox.size(); i++) {
VectorApproximation va = vectorApprox.get(i);
double minDist = vadist.getMinDist(va);
double maxDist = vadist.getMaxDist(va);
// Skip excess candidate generation:
- if(minDist > minMaxDist) {
+ if (minDist > minMaxDist) {
continue;
}
- candidates.add(new DoubleObjPair<DBID>(minDist, va.id));
+ candidates.add(new DoubleObjPair<>(minDist, va.id));
// Update candidate pruning heap
minMaxHeap.add(maxDist, k);
- if(minMaxHeap.size() >= k) {
+ if (minMaxHeap.size() >= k) {
minMaxDist = minMaxHeap.peek();
}
}
@@ -413,15 +398,15 @@ public class VAFile<V extends NumberVector<?>> extends AbstractRefiningIndex<V>
Collections.sort(candidates);
// refinement step
- DoubleDistanceKNNHeap result = new DoubleDistanceKNNHeap(k);
+ DoubleDistanceKNNHeap result = (DoubleDistanceKNNHeap) DBIDUtil.newHeap(DoubleDistance.FACTORY, k);
// log.fine("candidates size " + candidates.size());
// retrieve accurate distances
- for(DoubleObjPair<DBID> va : candidates) {
+ for (DoubleObjPair<DBID> va : candidates) {
// Stop when we are sure to have all elements
- if(result.size() >= k) {
+ if (result.size() >= k) {
double kDist = result.doubleKNNDistance();
- if(va.first > kDist) {
+ if (va.first > kDist) {
break;
}
}
@@ -430,7 +415,7 @@ public class VAFile<V extends NumberVector<?>> extends AbstractRefiningIndex<V>
final double dist = refine(va.second, query).doubleValue();
result.add(dist, va.second);
}
- if(LOG.isDebuggingFinest()) {
+ if (LOG.isDebuggingFinest()) {
LOG.finest("query = (" + query + ")");
LOG.finest("database: " + vectorApprox.size() + ", candidates: " + candidates.size() + ", results: " + result.size());
}
@@ -483,7 +468,7 @@ public class VAFile<V extends NumberVector<?>> extends AbstractRefiningIndex<V>
@Override
public VAFile<V> instantiate(Relation<V> relation) {
- return new VAFile<V>(pagesize, relation, numpart);
+ return new VAFile<>(pagesize, relation, numpart);
}
@Override
@@ -512,22 +497,22 @@ public class VAFile<V extends NumberVector<?>> extends AbstractRefiningIndex<V>
@Override
protected void makeOptions(Parameterization config) {
super.makeOptions(config);
- IntParameter pagesizeP = new IntParameter(TreeIndexFactory.PAGE_SIZE_ID, 1024);
+ IntParameter pagesizeP = new IntParameter(AbstractPageFileFactory.Parameterizer.PAGE_SIZE_ID, 1024);
pagesizeP.addConstraint(new GreaterConstraint(0));
- if(config.grab(pagesizeP)) {
+ if (config.grab(pagesizeP)) {
pagesize = pagesizeP.getValue();
}
IntParameter partitionsP = new IntParameter(Factory.PARTITIONS_ID);
partitionsP.addConstraint(new GreaterConstraint(2));
- if(config.grab(partitionsP)) {
+ if (config.grab(partitionsP)) {
numpart = partitionsP.getValue();
}
}
@Override
protected Factory<?> makeInstance() {
- return new Factory<NumberVector<?>>(pagesize, numpart);
+ return new Factory<>(pagesize, numpart);
}
}
}
-} \ No newline at end of file
+}
diff --git a/src/de/lmu/ifi/dbs/elki/index/vafile/VALPNormDistance.java b/src/de/lmu/ifi/dbs/elki/index/vafile/VALPNormDistance.java
index 2d9469e7..d0b4a8e5 100644
--- a/src/de/lmu/ifi/dbs/elki/index/vafile/VALPNormDistance.java
+++ b/src/de/lmu/ifi/dbs/elki/index/vafile/VALPNormDistance.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.index.vafile;
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/vafile/package-info.java b/src/de/lmu/ifi/dbs/elki/index/vafile/package-info.java
index f38b1dca..10aae35c 100644
--- a/src/de/lmu/ifi/dbs/elki/index/vafile/package-info.java
+++ b/src/de/lmu/ifi/dbs/elki/index/vafile/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