diff options
Diffstat (limited to 'src/de/lmu/ifi/dbs/elki/algorithm/outlier/lof/FlexibleLOF.java')
-rw-r--r-- | src/de/lmu/ifi/dbs/elki/algorithm/outlier/lof/FlexibleLOF.java | 271 |
1 files changed, 116 insertions, 155 deletions
diff --git a/src/de/lmu/ifi/dbs/elki/algorithm/outlier/lof/FlexibleLOF.java b/src/de/lmu/ifi/dbs/elki/algorithm/outlier/lof/FlexibleLOF.java index 2508b6b0..372bf68c 100644 --- a/src/de/lmu/ifi/dbs/elki/algorithm/outlier/lof/FlexibleLOF.java +++ b/src/de/lmu/ifi/dbs/elki/algorithm/outlier/lof/FlexibleLOF.java @@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.algorithm.outlier.lof; This file is part of ELKI: Environment for Developing KDD-Applications Supported by Index-Structures - Copyright (C) 2013 + Copyright (C) 2014 Ludwig-Maximilians-Universität München Lehr- und Forschungseinheit für Datenbanksysteme ELKI Development Team @@ -38,20 +38,16 @@ import de.lmu.ifi.dbs.elki.database.datastore.WritableDoubleDataStore; 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.DistanceDBIDListIter; -import de.lmu.ifi.dbs.elki.database.ids.distance.DoubleDistanceDBIDListIter; -import de.lmu.ifi.dbs.elki.database.ids.distance.DoubleDistanceKNNList; -import de.lmu.ifi.dbs.elki.database.ids.distance.KNNList; +import de.lmu.ifi.dbs.elki.database.ids.DoubleDBIDListIter; +import de.lmu.ifi.dbs.elki.database.ids.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; import de.lmu.ifi.dbs.elki.database.query.knn.PreprocessorKNNQuery; 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.DoubleRelation; +import de.lmu.ifi.dbs.elki.database.relation.MaterializedDoubleRelation; 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.preprocessed.knn.MaterializeKNNPreprocessor; 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; @@ -59,6 +55,7 @@ import de.lmu.ifi.dbs.elki.math.DoubleMinMax; import de.lmu.ifi.dbs.elki.result.outlier.OutlierResult; import de.lmu.ifi.dbs.elki.result.outlier.OutlierScoreMeta; import de.lmu.ifi.dbs.elki.result.outlier.QuotientOutlierScoreMeta; +import de.lmu.ifi.dbs.elki.utilities.DatabaseUtil; import de.lmu.ifi.dbs.elki.utilities.documentation.Description; import de.lmu.ifi.dbs.elki.utilities.documentation.Reference; import de.lmu.ifi.dbs.elki.utilities.documentation.Title; @@ -113,12 +110,14 @@ import de.lmu.ifi.dbs.elki.utilities.pairs.Pair; * @apiviz.has KNNQuery * * @param <O> the type of DatabaseObjects handled by this Algorithm - * @param <D> Distance type */ @Title("LOF: Local Outlier Factor") @Description("Algorithm to compute density-based local outlier factors in a database based on the neighborhood size parameter 'k'") -@Reference(authors = "M. M. Breunig, H.-P. Kriegel, R. Ng, and J. Sander", title = "LOF: Identifying Density-Based Local Outliers", booktitle = "Proc. 2nd ACM SIGMOD Int. Conf. on Management of Data (SIGMOD '00), Dallas, TX, 2000", url = "http://dx.doi.org/10.1145/342009.335388") -public class FlexibleLOF<O, D extends NumberDistance<D, ?>> extends AbstractAlgorithm<OutlierResult> implements OutlierAlgorithm { +@Reference(authors = "M. M. Breunig, H.-P. Kriegel, R. Ng, J. Sander", // +title = "LOF: Identifying Density-Based Local Outliers", // +booktitle = "Proc. 2nd ACM SIGMOD Int. Conf. on Management of Data (SIGMOD '00), Dallas, TX, 2000", // +url = "http://dx.doi.org/10.1145/342009.335388") +public class FlexibleLOF<O> extends AbstractAlgorithm<OutlierResult> implements OutlierAlgorithm { /** * The logger for this class. */ @@ -137,20 +136,12 @@ public class FlexibleLOF<O, D extends NumberDistance<D, ?>> extends AbstractAlgo /** * Neighborhood distance function. */ - protected DistanceFunction<? super O, D> referenceDistanceFunction; + protected DistanceFunction<? super O> referenceDistanceFunction; /** * Reachability distance function. */ - protected DistanceFunction<? super O, D> reachabilityDistanceFunction; - - /** - * Include object itself in kNN neighborhood. - * - * In the official LOF publication, the point itself is not considered to be - * part of its k nearest neighbors. - */ - private static boolean objectIsInKNN = false; + protected DistanceFunction<? super O> reachabilityDistanceFunction; /** * Constructor. @@ -160,10 +151,10 @@ public class FlexibleLOF<O, D extends NumberDistance<D, ?>> extends AbstractAlgo * @param neighborhoodDistanceFunction the neighborhood distance function * @param reachabilityDistanceFunction the reachability distance function */ - public FlexibleLOF(int krefer, int kreach, DistanceFunction<? super O, D> neighborhoodDistanceFunction, DistanceFunction<? super O, D> reachabilityDistanceFunction) { + public FlexibleLOF(int krefer, int kreach, DistanceFunction<? super O> neighborhoodDistanceFunction, DistanceFunction<? super O> reachabilityDistanceFunction) { super(); - this.krefer = krefer + (objectIsInKNN ? 0 : 1); - this.kreach = kreach + (objectIsInKNN ? 0 : 1); + this.krefer = krefer + 1; + this.kreach = kreach + 1; this.referenceDistanceFunction = neighborhoodDistanceFunction; this.reachabilityDistanceFunction = reachabilityDistanceFunction; } @@ -178,9 +169,9 @@ public class FlexibleLOF<O, D extends NumberDistance<D, ?>> extends AbstractAlgo */ public OutlierResult run(Database database, Relation<O> relation) { StepProgress stepprog = LOG.isVerbose() ? new StepProgress("LOF", 3) : null; - Pair<KNNQuery<O, D>, KNNQuery<O, D>> pair = getKNNQueries(database, relation, stepprog); - KNNQuery<O, D> kNNRefer = pair.getFirst(); - KNNQuery<O, D> kNNReach = pair.getSecond(); + Pair<KNNQuery<O>, KNNQuery<O>> pair = getKNNQueries(database, relation, stepprog); + KNNQuery<O> kNNRefer = pair.getFirst(); + KNNQuery<O> kNNReach = pair.getSecond(); return doRunInTime(relation.getDBIDs(), kNNRefer, kNNReach, stepprog).getResult(); } @@ -191,30 +182,29 @@ public class FlexibleLOF<O, D extends NumberDistance<D, ?>> extends AbstractAlgo * @param stepprog the progress logger * @return the kNN queries for the algorithm */ - private Pair<KNNQuery<O, D>, KNNQuery<O, D>> getKNNQueries(Database database, Relation<O> relation, StepProgress stepprog) { + private Pair<KNNQuery<O>, KNNQuery<O>> getKNNQueries(Database database, Relation<O> relation, StepProgress stepprog) { // "HEAVY" flag for knnReach since it is used more than once - KNNQuery<O, D> knnReach = QueryUtil.getKNNQuery(relation, reachabilityDistanceFunction, kreach, DatabaseQuery.HINT_HEAVY_USE, DatabaseQuery.HINT_OPTIMIZED_ONLY, DatabaseQuery.HINT_NO_CACHE); + KNNQuery<O> knnReach = QueryUtil.getKNNQuery(relation, reachabilityDistanceFunction, kreach, DatabaseQuery.HINT_HEAVY_USE, DatabaseQuery.HINT_OPTIMIZED_ONLY, DatabaseQuery.HINT_NO_CACHE); // No optimized kNN query - use a preprocessor! - if (!(knnReach instanceof PreprocessorKNNQuery)) { - if (stepprog != null) { - if (referenceDistanceFunction.equals(reachabilityDistanceFunction)) { + if(!(knnReach instanceof PreprocessorKNNQuery)) { + if(stepprog != null) { + if(referenceDistanceFunction.equals(reachabilityDistanceFunction)) { stepprog.beginStep(1, "Materializing neighborhoods w.r.t. reference neighborhood distance function.", LOG); - } else { + } + else { stepprog.beginStep(1, "Not materializing neighborhoods w.r.t. reference neighborhood distance function, but materializing neighborhoods w.r.t. reachability distance function.", LOG); } } int kpreproc = (referenceDistanceFunction.equals(reachabilityDistanceFunction)) ? Math.max(kreach, krefer) : kreach; - MaterializeKNNPreprocessor<O, D> preproc = new MaterializeKNNPreprocessor<>(relation, reachabilityDistanceFunction, kpreproc); - database.addIndex(preproc); - DistanceQuery<O, D> rdq = database.getDistanceQuery(relation, reachabilityDistanceFunction); - knnReach = preproc.getKNNQuery(rdq, kreach); + knnReach = DatabaseUtil.precomputedKNNQuery(database, relation, reachabilityDistanceFunction, kpreproc); } // knnReach is only used once - KNNQuery<O, D> knnRefer; - if (referenceDistanceFunction == reachabilityDistanceFunction || referenceDistanceFunction.equals(reachabilityDistanceFunction)) { + KNNQuery<O> knnRefer; + if(referenceDistanceFunction == reachabilityDistanceFunction || referenceDistanceFunction.equals(reachabilityDistanceFunction)) { knnRefer = knnReach; - } else { + } + else { // do not materialize the first neighborhood, since it is used only once knnRefer = QueryUtil.getKNNQuery(relation, referenceDistanceFunction, krefer); } @@ -234,149 +224,118 @@ public class FlexibleLOF<O, D extends NumberDistance<D, ?>> extends AbstractAlgo * @param stepprog Progress logger * @return LOF result */ - protected LOFResult<O, D> doRunInTime(DBIDs ids, KNNQuery<O, D> kNNRefer, KNNQuery<O, D> kNNReach, StepProgress stepprog) { + protected LOFResult<O> doRunInTime(DBIDs ids, KNNQuery<O> kNNRefer, KNNQuery<O> kNNReach, StepProgress stepprog) { // Assert we got something - if (kNNRefer == null) { + if(kNNRefer == null) { throw new AbortException("No kNN queries supported by database for reference neighborhood distance function."); } - if (kNNReach == null) { + if(kNNReach == null) { throw new AbortException("No kNN queries supported by database for reachability distance function."); } // Compute LRDs - if (stepprog != null) { - stepprog.beginStep(2, "Computing LRDs.", LOG); - } - WritableDoubleDataStore lrds = computeLRDs(ids, kNNReach); + LOG.beginStep(stepprog, 2, "Computing LRDs."); + WritableDoubleDataStore lrds = DataStoreUtil.makeDoubleStorage(ids, DataStoreFactory.HINT_HOT | DataStoreFactory.HINT_TEMP); + computeLRDs(kNNReach, ids, lrds); // compute LOF_SCORE of each db object - if (stepprog != null) { - stepprog.beginStep(3, "Computing LOFs.", LOG); - } - Pair<WritableDoubleDataStore, DoubleMinMax> lofsAndMax = computeLOFs(ids, lrds, kNNRefer); - WritableDoubleDataStore lofs = lofsAndMax.getFirst(); + LOG.beginStep(stepprog, 3, "Computing LOFs."); + WritableDoubleDataStore lofs = DataStoreUtil.makeDoubleStorage(ids, DataStoreFactory.HINT_STATIC); // track the maximum value for normalization. - DoubleMinMax lofminmax = lofsAndMax.getSecond(); + DoubleMinMax lofminmax = new DoubleMinMax(); + computeLOFs(kNNRefer, ids, lrds, lofs, lofminmax); - if (stepprog != null) { - stepprog.setCompleted(LOG); - } + LOG.setCompleted(stepprog); // Build result representation. - Relation<Double> scoreResult = new MaterializedRelation<>("Local Outlier Factor", "lof-outlier", TypeUtil.DOUBLE, lofs, ids); + DoubleRelation scoreResult = new MaterializedDoubleRelation("Local Outlier Factor", "lof-outlier", lofs, ids); OutlierScoreMeta scoreMeta = new QuotientOutlierScoreMeta(lofminmax.getMin(), lofminmax.getMax(), 0.0, Double.POSITIVE_INFINITY, 1.0); OutlierResult result = new OutlierResult(scoreMeta, scoreResult); - return new LOFResult<>(result, kNNRefer, kNNReach, lrds, lofs); } /** * Computes the local reachability density (LRD) of the specified objects. * - * @param ids the ids of the objects - * @param knnReach the precomputed neighborhood of the objects w.r.t. the + * @param knnq the precomputed neighborhood of the objects w.r.t. the * reachability distance - * @return the LRDs of the objects + * @param ids the ids of the objects + * @param lrds Reachability storage */ - protected WritableDoubleDataStore computeLRDs(DBIDs ids, KNNQuery<O, D> knnReach) { - WritableDoubleDataStore lrds = DataStoreUtil.makeDoubleStorage(ids, DataStoreFactory.HINT_HOT | DataStoreFactory.HINT_TEMP); + protected void computeLRDs(KNNQuery<O> knnq, DBIDs ids, WritableDoubleDataStore lrds) { FiniteProgress lrdsProgress = LOG.isVerbose() ? new FiniteProgress("LRD", ids.size(), LOG) : null; - for (DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) { - final KNNList<D> neighbors = knnReach.getKNNForDBID(iter, kreach); + for(DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) { + final KNNList neighbors = knnq.getKNNForDBID(iter, kreach); double sum = 0.0; int count = 0; - if (neighbors instanceof DoubleDistanceKNNList) { - // Fast version for double distances - for (DoubleDistanceDBIDListIter neighbor = ((DoubleDistanceKNNList) neighbors).iter(); neighbor.valid(); neighbor.advance()) { - if (objectIsInKNN || !DBIDUtil.equal(neighbor, iter)) { - KNNList<D> neighborsNeighbors = knnReach.getKNNForDBID(neighbor, kreach); - final double nkdist; - if (neighborsNeighbors instanceof DoubleDistanceKNNList) { - nkdist = ((DoubleDistanceKNNList) neighborsNeighbors).doubleKNNDistance(); - } else { - nkdist = neighborsNeighbors.getKNNDistance().doubleValue(); - } - sum += Math.max(neighbor.doubleDistance(), nkdist); - count++; - } - } - } else { - for (DistanceDBIDListIter<D> neighbor = neighbors.iter(); neighbor.valid(); neighbor.advance()) { - if (objectIsInKNN || !DBIDUtil.equal(neighbor, iter)) { - KNNList<D> neighborsNeighbors = knnReach.getKNNForDBID(neighbor, kreach); - sum += Math.max(neighbor.getDistance().doubleValue(), neighborsNeighbors.getKNNDistance().doubleValue()); - count++; - } + for(DoubleDBIDListIter neighbor = neighbors.iter(); neighbor.valid(); neighbor.advance()) { + if(DBIDUtil.equal(neighbor, iter)) { + continue; } + KNNList neighborsNeighbors = knnq.getKNNForDBID(neighbor, kreach); + sum += Math.max(neighbor.doubleValue(), neighborsNeighbors.getKNNDistance()); + count++; } // Avoid division by 0 final double lrd = (sum > 0) ? (count / sum) : Double.POSITIVE_INFINITY; lrds.putDouble(iter, lrd); - if (lrdsProgress != null) { - lrdsProgress.incrementProcessed(LOG); - } - } - if (lrdsProgress != null) { - lrdsProgress.ensureCompleted(LOG); + LOG.incrementProcessed(lrdsProgress); } - return lrds; + LOG.ensureCompleted(lrdsProgress); } /** * Computes the Local outlier factor (LOF) of the specified objects. * - * @param ids the ids of the objects - * @param lrds the LRDs of the objects - * @param knnRefer the precomputed neighborhood of the objects w.r.t. the + * @param knnq the precomputed neighborhood of the objects w.r.t. the * reference distance - * @return the LOFs of the objects and the maximum LOF + * @param ids IDs to process + * @param lrds Local reachability distances + * @param lofs Local outlier factor storage + * @param lofminmax Score minimum/maximum tracker */ - protected Pair<WritableDoubleDataStore, DoubleMinMax> computeLOFs(DBIDs ids, DoubleDataStore lrds, KNNQuery<O, D> knnRefer) { - WritableDoubleDataStore lofs = DataStoreUtil.makeDoubleStorage(ids, DataStoreFactory.HINT_STATIC); - // track the maximum value for normalization. - DoubleMinMax lofminmax = new DoubleMinMax(); - + protected void computeLOFs(KNNQuery<O> knnq, DBIDs ids, DoubleDataStore lrds, WritableDoubleDataStore lofs, DoubleMinMax lofminmax) { FiniteProgress progressLOFs = LOG.isVerbose() ? new FiniteProgress("LOF_SCORE for objects", ids.size(), LOG) : null; - for (DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) { - final double lrdp = lrds.doubleValue(iter); + for(DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) { final double lof; - if (lrdp > 0 && !Double.isInfinite(lrdp)) { - final KNNList<D> neighbors = knnRefer.getKNNForDBID(iter, krefer); - double sum = 0.0; + final double lrdp = lrds.doubleValue(iter); + final KNNList neighbors = knnq.getKNNForDBID(iter, krefer); + if(!Double.isInfinite(lrdp)) { + double sum = 0.; int count = 0; - for (DBIDIter neighbor = neighbors.iter(); neighbor.valid(); neighbor.advance()) { + for(DBIDIter neighbor = neighbors.iter(); neighbor.valid(); neighbor.advance()) { // skip the point itself - if (objectIsInKNN || !DBIDUtil.equal(neighbor, iter)) { - sum += lrds.doubleValue(neighbor); - count++; + if(DBIDUtil.equal(neighbor, iter)) { + continue; + } + final double val = lrds.doubleValue(neighbor); + sum += val; + count++; + if(Double.isInfinite(val)) { + break; } } - lof = sum / (count * lrdp); - } else { + lof = sum / (lrdp * count); + } + else { lof = 1.0; } lofs.putDouble(iter, lof); // update minimum and maximum - if (!Double.isInfinite(lof)) { - lofminmax.put(lof); - } + lofminmax.put(lof); - if (progressLOFs != null) { - progressLOFs.incrementProcessed(LOG); - } + LOG.incrementProcessed(progressLOFs); } - if (progressLOFs != null) { - progressLOFs.ensureCompleted(LOG); - } - return new Pair<>(lofs, lofminmax); + LOG.ensureCompleted(progressLOFs); } @Override public TypeInformation[] getInputTypeRestriction() { final TypeInformation type; - if (reachabilityDistanceFunction.equals(referenceDistanceFunction)) { + if(reachabilityDistanceFunction.equals(referenceDistanceFunction)) { type = reachabilityDistanceFunction.getInputTypeRestriction(); - } else { + } + else { type = new CombinedTypeInformation(referenceDistanceFunction.getInputTypeRestriction(), reachabilityDistanceFunction.getInputTypeRestriction()); } return TypeUtil.array(type); @@ -393,7 +352,7 @@ public class FlexibleLOF<O, D extends NumberDistance<D, ?>> extends AbstractAlgo * * @author Elke Achtert */ - public static class LOFResult<O, D extends NumberDistance<D, ?>> { + public static class LOFResult<O> { /** * The result of the run of the {@link FlexibleLOF} algorithm. */ @@ -402,22 +361,22 @@ public class FlexibleLOF<O, D extends NumberDistance<D, ?>> extends AbstractAlgo /** * The kNN query w.r.t. the reference neighborhood distance. */ - private final KNNQuery<O, D> kNNRefer; + private final KNNQuery<O> kNNRefer; /** * The kNN query w.r.t. the reachability distance. */ - private final KNNQuery<O, D> kNNReach; + private final KNNQuery<O> kNNReach; /** * The RkNN query w.r.t. the reference neighborhood distance. */ - private RKNNQuery<O, D> rkNNRefer; + private RKNNQuery<O> rkNNRefer; /** * The rkNN query w.r.t. the reachability distance. */ - private RKNNQuery<O, D> rkNNReach; + private RKNNQuery<O> rkNNReach; /** * The LRD values of the objects. @@ -439,7 +398,7 @@ public class FlexibleLOF<O, D extends NumberDistance<D, ?>> extends AbstractAlgo * @param lrds the LRD values of the objects * @param lofs the LOF values of the objects */ - public LOFResult(OutlierResult result, KNNQuery<O, D> kNNRefer, KNNQuery<O, D> kNNReach, WritableDoubleDataStore lrds, WritableDoubleDataStore lofs) { + public LOFResult(OutlierResult result, KNNQuery<O> kNNRefer, KNNQuery<O> kNNReach, WritableDoubleDataStore lrds, WritableDoubleDataStore lofs) { this.result = result; this.kNNRefer = kNNRefer; this.kNNReach = kNNReach; @@ -452,7 +411,7 @@ public class FlexibleLOF<O, D extends NumberDistance<D, ?>> extends AbstractAlgo * * @return the kNN query w.r.t. the reference neighborhood distance */ - public KNNQuery<O, D> getKNNRefer() { + public KNNQuery<O> getKNNRefer() { return kNNRefer; } @@ -461,7 +420,7 @@ public class FlexibleLOF<O, D extends NumberDistance<D, ?>> extends AbstractAlgo * * @return the kNN query w.r.t. the reachability distance */ - public KNNQuery<O, D> getKNNReach() { + public KNNQuery<O> getKNNReach() { return kNNReach; } @@ -497,7 +456,7 @@ public class FlexibleLOF<O, D extends NumberDistance<D, ?>> extends AbstractAlgo * * @param rkNNRefer the query to set */ - public void setRkNNRefer(RKNNQuery<O, D> rkNNRefer) { + public void setRkNNRefer(RKNNQuery<O> rkNNRefer) { this.rkNNRefer = rkNNRefer; } @@ -506,7 +465,7 @@ public class FlexibleLOF<O, D extends NumberDistance<D, ?>> extends AbstractAlgo * * @return the RkNN query w.r.t. the reference neighborhood distance */ - public RKNNQuery<O, D> getRkNNRefer() { + public RKNNQuery<O> getRkNNRefer() { return rkNNRefer; } @@ -515,7 +474,7 @@ public class FlexibleLOF<O, D extends NumberDistance<D, ?>> extends AbstractAlgo * * @return the RkNN query w.r.t. the reachability distance */ - public RKNNQuery<O, D> getRkNNReach() { + public RKNNQuery<O> getRkNNReach() { return rkNNReach; } @@ -524,7 +483,7 @@ public class FlexibleLOF<O, D extends NumberDistance<D, ?>> extends AbstractAlgo * * @param rkNNReach the query to set */ - public void setRkNNReach(RKNNQuery<O, D> rkNNReach) { + public void setRkNNReach(RKNNQuery<O> rkNNReach) { this.rkNNReach = rkNNReach; } } @@ -536,7 +495,7 @@ public class FlexibleLOF<O, D extends NumberDistance<D, ?>> extends AbstractAlgo * * @apiviz.exclude */ - public static class Parameterizer<O, D extends NumberDistance<D, ?>> extends AbstractDistanceBasedAlgorithm.Parameterizer<O, D> { + public static class Parameterizer<O> extends AbstractDistanceBasedAlgorithm.Parameterizer<O> { /** * The distance function to determine the reachability distance between * database objects. @@ -545,16 +504,16 @@ public class FlexibleLOF<O, D extends NumberDistance<D, ?>> extends AbstractAlgo /** * Parameter to specify the number of nearest neighbors of an object to be - * considered for computing its LOF_SCORE, must be an integer greater than - * 1. + * considered for computing its LOF score, must be an integer greater or + * equal to 1. */ - public static final OptionID KREF_ID = new OptionID("lof.krefer", "The number of nearest neighbors of an object to be considered for computing its LOF_SCORE."); + public static final OptionID KREF_ID = new OptionID("lof.krefer", "The number of nearest neighbors of an object to be considered for computing its LOF score."); /** * Parameter to specify the number of nearest neighbors of an object to be * considered for computing its reachability distance. */ - public static final OptionID KREACH_ID = new OptionID("lof.kreach", "The number of nearest neighbors of an object to be considered for computing its LOF_SCORE."); + public static final OptionID KREACH_ID = new OptionID("lof.kreach", "The number of nearest neighbors of an object to be considered for computing its LOF score."); /** * The reference set size to use. @@ -569,43 +528,45 @@ public class FlexibleLOF<O, D extends NumberDistance<D, ?>> extends AbstractAlgo /** * Neighborhood distance function. */ - protected DistanceFunction<O, D> neighborhoodDistanceFunction = null; + protected DistanceFunction<O> neighborhoodDistanceFunction = null; /** * Reachability distance function. */ - protected DistanceFunction<O, D> reachabilityDistanceFunction = null; + protected DistanceFunction<O> reachabilityDistanceFunction = null; @Override protected void makeOptions(Parameterization config) { super.makeOptions(config); final IntParameter pK = new IntParameter(KREF_ID); - pK.addConstraint(CommonConstraints.GREATER_THAN_ONE_INT); - if (config.grab(pK)) { + pK.addConstraint(CommonConstraints.GREATER_EQUAL_ONE_INT); + if(config.grab(pK)) { krefer = pK.intValue(); } final IntParameter pK2 = new IntParameter(KREACH_ID); pK2.setOptional(true); - pK2.addConstraint(CommonConstraints.GREATER_THAN_ONE_INT); - if (config.grab(pK2)) { + pK2.addConstraint(CommonConstraints.GREATER_EQUAL_ONE_INT); + if(config.grab(pK2)) { kreach = pK2.intValue(); - } else { + } + else { kreach = krefer; } - final ObjectParameter<DistanceFunction<O, D>> reachDistP = new ObjectParameter<>(REACHABILITY_DISTANCE_FUNCTION_ID, DistanceFunction.class); + final ObjectParameter<DistanceFunction<O>> reachDistP = new ObjectParameter<>(REACHABILITY_DISTANCE_FUNCTION_ID, DistanceFunction.class); reachDistP.setOptional(true); - if (config.grab(reachDistP)) { + if(config.grab(reachDistP)) { reachabilityDistanceFunction = reachDistP.instantiateClass(config); - } else { + } + else { reachabilityDistanceFunction = distanceFunction; } } @Override - protected FlexibleLOF<O, D> makeInstance() { + protected FlexibleLOF<O> makeInstance() { return new FlexibleLOF<>(kreach, krefer, distanceFunction, reachabilityDistanceFunction); } } |