@Override
public OutlierResult run(Database database) throws IllegalStateException {
Relation<O> relation = database.getRelation(getInputTypeRestriction()[0]);
DistanceQuery<O, D> distFunc = database.getDistanceQuery(relation, getDistanceFunction());
ModifiableDBIDs processedIDs = DBIDUtil.newHashSet(relation.size());
ModifiableDBIDs pruned = DBIDUtil.newHashSet();
// KNNS
WritableDataStore<ModifiableDBIDs> knns = DataStoreUtil.makeStorage(relation.getDBIDs(), DataStoreFactory.HINT_TEMP | DataStoreFactory.HINT_HOT, ModifiableDBIDs.class);
// RNNS
WritableDataStore<ModifiableDBIDs> rnns = DataStoreUtil.makeStorage(relation.getDBIDs(), DataStoreFactory.HINT_TEMP | DataStoreFactory.HINT_HOT, ModifiableDBIDs.class);
// density
WritableDataStore<Double> density = DataStoreUtil.makeStorage(relation.getDBIDs(), DataStoreFactory.HINT_TEMP | DataStoreFactory.HINT_HOT, Double.class);
// init knns and rnns
for(DBID id : distFunc.getRelation().iterDBIDs()) {
knns.put(id, DBIDUtil.newArray());
rnns.put(id, DBIDUtil.newArray());
}
// TODO: use kNN preprocessor?
KNNQuery<O, D> knnQuery = database.getKNNQuery(distFunc, k, DatabaseQuery.HINT_HEAVY_USE);
for(DBID id : relation.iterDBIDs()) {
// if not visited count=0
int count = rnns.get(id).size();
ModifiableDBIDs s;
if(!processedIDs.contains(id)) {
// TODO: use exactly k neighbors?
List<DistanceResultPair<D>> list = knnQuery.getKNNForDBID(id, k);
for(DistanceResultPair<D> d : list) {
knns.get(id).add(d.getDBID());
}
processedIDs.add(id);
s = knns.get(id);
density.put(id, 1 / list.get(k - 1).getDistance().doubleValue());
}
else {
s = knns.get(id);
}
for(DBID q : s) {
if(!processedIDs.contains(q)) {
// TODO: use exactly k neighbors?
List<DistanceResultPair<D>> listQ = knnQuery.getKNNForDBID(q, k);
for(DistanceResultPair<D> dq : listQ) {
knns.get(q).add(dq.getDBID());
}
density.put(q, 1 / listQ.get(k - 1).getDistance().doubleValue());
processedIDs.add(q);
}
if(knns.get(q).contains(id)) {
rnns.get(q).add(id);
rnns.get(id).add(q);
count++;
}
}
if(count >= s.size() * m) {
pruned.add(id);
}
}
// Calculate INFLO for any Object
// IF Object is pruned INFLO=1.0
DoubleMinMax inflominmax = new DoubleMinMax();
WritableDataStore<Double> inflos = DataStoreUtil.makeStorage(relation.getDBIDs(), DataStoreFactory.HINT_STATIC, Double.class);
for(DBID id : distFunc.getRelation().iterDBIDs()) {
if(!pruned.contains(id)) {
ModifiableDBIDs knn = knns.get(id);
ModifiableDBIDs rnn = rnns.get(id);
double denP = density.get(id);
knn.addAll(rnn);
double den = 0;
for(DBID q : knn) {
double denQ = density.get(q);
den = den + denQ;
}
den = den / rnn.size();
den = den / denP;
inflos.put(id, den);
// update minimum and maximum
inflominmax.put(den);