docs: public OutlierResult run(Relation<O> relation) {
      final int k1 = k + 1; // Query size
      final double perplexity = k / 3.;
      KNNQuery<O> knnq = relation.getKNNQuery(getDistanceFunction(), k1);
      final double logPerp = perplexity > 1. ? FastMath.log(perplexity) : .1;
  
      double[] p = new double[k + 10];
      ModifiableDoubleDBIDList dists = DBIDUtil.newDistanceDBIDList(k + 10);
      DoubleDBIDListIter di = dists.iter();
      FiniteProgress prog = LOG.isVerbose() ? new FiniteProgress("ISOS scores", relation.size(), LOG) : null;
      WritableDoubleDataStore scores = DataStoreUtil.makeDoubleStorage(relation.getDBIDs(), DataStoreFactory.HINT_HOT | DataStoreFactory.HINT_DB, 1.);
      for(DBIDIter it = relation.iterDBIDs(); it.valid(); it.advance()) {
        KNNList knns = knnq.getKNNForDBID(it, k1);
        if(p.length < knns.size() + 1) {
          p = new double[knns.size() + 10];
        }
        final DoubleDBIDListIter ki = knns.iter();
        try {
          double id = estimateID(it, ki, p);
          adjustDistances(it, ki, knns.getKNNDistance(), id, dists);
          // We now continue with the modified distances below.
          // Compute affinities
          SOS.computePi(it, di, p, perplexity, logPerp);
          // Normalization factor:
          double s = SOS.sumOfProbabilities(it, di, p);
          if(s > 0.) {
            nominateNeighbors(it, di, p, 1. / s, scores);
          }
        }
        catch(ArithmeticException e) {
          // ID estimation failed, supposedly constant values because of too many
          // duplicate points, or too small k. Fall back to KNNSOS.
          // Note: this looks almost identical to the above, but uses ki instead
          // of the adjusted distances di!
          // Compute affinities
          SOS.computePi(it, ki, p, perplexity, logPerp);
          // Normalization factor:
          double s = SOS.sumOfProbabilities(it, ki, p);
          if(s > 0.) {
            nominateNeighbors(it, ki, p, 1. / s, scores);
          }
        }
        LOG.incrementProcessed(prog);
      }
      LOG.ensureCompleted(prog);
      DoubleMinMax minmax = transformScores(scores, relation.getDBIDs(), logPerp, phi);
      DoubleRelation scoreres = new MaterializedDoubleRelation("Intrinsic Stoachastic Outlier Selection", "isos-outlier", scores, relation.getDBIDs());
      OutlierScoreMeta meta = new ProbabilisticOutlierScore(minmax.getMin(), minmax.getMax(), 0.);
      return new OutlierResult(meta, scoreres);
    }