docs: public OutlierResult run(Database database, Relation<O> relation) {
      final DBIDs ids = relation.getDBIDs();
      DistanceQuery<O> distFunc = database.getDistanceQuery(relation, getDistanceFunction());
      // Get k nearest neighbor and range query on the relation.
      KNNQuery<O> knnq = database.getKNNQuery(distFunc, k, DatabaseQuery.HINT_HEAVY_USE);
      RangeQuery<O> rnnQuery = database.getRangeQuery(distFunc, DatabaseQuery.HINT_HEAVY_USE);
  
      StepProgress stepProg = LOG.isVerbose() ? new StepProgress("DWOF", 2) : null;
      // DWOF output score storage.
      WritableDoubleDataStore dwofs = DataStoreUtil.makeDoubleStorage(ids, DataStoreFactory.HINT_DB | DataStoreFactory.HINT_HOT, 0.);
      if(stepProg != null) {
        stepProg.beginStep(1, "Initializing objects' Radii", LOG);
      }
      WritableDoubleDataStore radii = DataStoreUtil.makeDoubleStorage(ids, DataStoreFactory.HINT_TEMP | DataStoreFactory.HINT_HOT, 0.);
      // Find an initial radius for each object:
      initializeRadii(ids, knnq, distFunc, radii);
      WritableIntegerDataStore oldSizes = DataStoreUtil.makeIntegerStorage(ids, DataStoreFactory.HINT_HOT, 1);
      WritableIntegerDataStore newSizes = DataStoreUtil.makeIntegerStorage(ids, DataStoreFactory.HINT_HOT, 1);
      int countUnmerged = relation.size();
      if(stepProg != null) {
        stepProg.beginStep(2, "Clustering-Evaluating Cycles.", LOG);
      }
      IndefiniteProgress clusEvalProgress = LOG.isVerbose() ? new IndefiniteProgress("Evaluating DWOFs", LOG) : null;
      while(countUnmerged > 0) {
        LOG.incrementProcessed(clusEvalProgress);
        // Increase radii
        for(DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) {
          radii.putDouble(iter, radii.doubleValue(iter) * delta);
        }
        // stores the clustering label for each object
        WritableDataStore<ModifiableDBIDs> labels = DataStoreUtil.makeStorage(ids, DataStoreFactory.HINT_TEMP, ModifiableDBIDs.class);
        // Cluster objects based on the current radius
        clusterData(ids, rnnQuery, radii, labels);
        // simple reference swap
        WritableIntegerDataStore temp = newSizes;
        newSizes = oldSizes;
        oldSizes = temp;
  
        // Update the cluster size count for each object.
        countUnmerged = updateSizes(ids, labels, newSizes);
        labels.destroy();
        // Update DWOF scores.
        for(DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) {
          double newScore = (newSizes.intValue(iter) > 0) ? ((double) (oldSizes.intValue(iter) - 1) / (double) newSizes.intValue(iter)) : 0.0;
          dwofs.putDouble(iter, dwofs.doubleValue(iter) + newScore);
        }
      }
      LOG.setCompleted(clusEvalProgress);
      LOG.setCompleted(stepProg);
      // Build result representation.
      DoubleMinMax minmax = new DoubleMinMax();
      for(DBIDIter iter = relation.iterDBIDs(); iter.valid(); iter.advance()) {
        minmax.put(dwofs.doubleValue(iter));
      }
      OutlierScoreMeta meta = new InvertedOutlierScoreMeta(minmax.getMin(), minmax.getMax(), 0.0, Double.POSITIVE_INFINITY);
      DoubleRelation rel = new MaterializedDoubleRelation("Dynamic-Window Outlier Factors", "dwof-outlier", dwofs, ids);
      return new OutlierResult(meta, rel);
    }