docs: public OutlierResult run(Database database, Relation<N> nrel, Relation<? extends NumberVector> relation) {
      assert (RelationUtil.dimensionality(relation) == 1) : "TrimmedMean can only process one-dimensional data sets.";
      final NeighborSetPredicate npred = getNeighborSetPredicateFactory().instantiate(database, nrel);
  
      WritableDoubleDataStore errors = DataStoreUtil.makeDoubleStorage(relation.getDBIDs(), DataStoreFactory.HINT_TEMP);
      WritableDoubleDataStore scores = DataStoreUtil.makeDoubleStorage(relation.getDBIDs(), DataStoreFactory.HINT_STATIC);
  
      FiniteProgress progress = LOG.isVerbose() ? new FiniteProgress("Computing trimmed means", relation.size(), LOG) : null;
      for(DBIDIter iditer = relation.iterDBIDs(); iditer.valid(); iditer.advance()) {
        DBIDs neighbors = npred.getNeighborDBIDs(iditer);
        int num = 0;
        double[] values = new double[neighbors.size()];
        // calculate trimmedMean
        for(DBIDIter iter = neighbors.iter(); iter.valid(); iter.advance()) {
          values[num] = relation.get(iter).doubleValue(0);
          num++;
        }
  
        // calculate local trimmed Mean and error term
        final double tm;
        if(num > 0) {
          int left = (int) Math.floor(p * (num - 1));
          int right = (int) Math.floor((1 - p) * (num - 1));
          Arrays.sort(values, 0, num);
          Mean mean = new Mean();
          for(int i = left; i <= right; i++) {
            mean.put(values[i]);
          }
          tm = mean.getMean();
        }
        else {
          tm = relation.get(iditer).doubleValue(0);
        }
        // Error: deviation from trimmed mean
        errors.putDouble(iditer, relation.get(iditer).doubleValue(0) - tm);
  
        LOG.incrementProcessed(progress);
      }
      LOG.ensureCompleted(progress);
  
      if(LOG.isVerbose()) {
        LOG.verbose("Computing median error.");
      }
      double median_dev_from_median;
      {
        // calculate the median error
        double[] ei = new double[relation.size()];
        {
          int i = 0;
          for(DBIDIter iditer = relation.iterDBIDs(); iditer.valid(); iditer.advance()) {
            ei[i] = errors.doubleValue(iditer);
            i++;
          }
        }
        double median_i = QuickSelect.median(ei);
        // Update to deviation from median
        for(int i = 0; i < ei.length; i++) {
          ei[i] = Math.abs(ei[i] - median_i);
        }
        // Again, extract median
        median_dev_from_median = QuickSelect.median(ei);
      }
  
      if(LOG.isVerbose()) {
        LOG.verbose("Normalizing scores.");
      }
      // calculate score
      DoubleMinMax minmax = new DoubleMinMax();
      for(DBIDIter iditer = relation.iterDBIDs(); iditer.valid(); iditer.advance()) {
        double score = Math.abs(errors.doubleValue(iditer)) * 0.6745 / median_dev_from_median;
        scores.putDouble(iditer, score);
        minmax.put(score);
      }
      //
      DoubleRelation scoreResult = new MaterializedDoubleRelation("TrimmedMean", "Trimmed Mean Score", scores, relation.getDBIDs());
      OutlierScoreMeta scoreMeta = new BasicOutlierScoreMeta(minmax.getMin(), minmax.getMax(), 0.0, Double.POSITIVE_INFINITY, 0);
      OutlierResult or = new OutlierResult(scoreMeta, scoreResult);
      or.addChildResult(npred);
      return or;
    }