docs: public OutlierResult run(Relation<P> spatial, Relation<? extends NumberVector> relation) {
      DistanceQuery<P> distFunc = getDistanceFunction().instantiate(spatial);
      WritableDataStore<double[]> similarityVectors = DataStoreUtil.makeStorage(spatial.getDBIDs(), DataStoreFactory.HINT_TEMP, double[].class);
      WritableDataStore<DBIDs> neighbors = DataStoreUtil.makeStorage(spatial.getDBIDs(), DataStoreFactory.HINT_TEMP, DBIDs.class);
  
      // Make a static IDs array for matrix column indexing
      ArrayDBIDs ids = DBIDUtil.ensureArray(relation.getDBIDs());
  
      // construct the relation Matrix of the ec-graph
      double[][] E = new double[ids.size()][ids.size()];
      KNNHeap heap = DBIDUtil.newHeap(k);
      {
        int i = 0;
        for(DBIDIter id = ids.iter(); id.valid(); id.advance(), i++) {
          final double val = relation.get(id).doubleValue(0);
          assert (heap.size() == 0);
          int j = 0;
          for(DBIDIter n = ids.iter(); n.valid(); n.advance(), j++) {
            if(i == j) {
              continue;
            }
            final double e;
            final double distance = distFunc.distance(id, n);
            heap.insert(distance, n);
            if(distance == 0) {
              LOG.warning("Zero distances are not supported - skipping: " + DBIDUtil.toString(id) + " " + DBIDUtil.toString(n));
              e = 0;
            }
            else {
              double diff = Math.abs(val - relation.get(n).doubleValue(0));
              double exp = FastMath.exp(FastMath.pow(diff, alpha));
              // Implementation note: not inverting exp worked a lot better.
              // Therefore we diverge from the article here.
              e = exp / distance;
            }
            E[j][i] = e;
          }
          // Convert kNN Heap into DBID array (unordered)
          ModifiableDBIDs nids = DBIDUtil.newArray(heap.size());
          for(DBIDIter it = heap.unorderedIterator(); it.valid(); it.advance()) {
            nids.add(it);
          }
          neighbors.put(id, nids);
        }
      }
      // normalize the adjacent Matrix
      // Sum based normalization - don't use E.normalizeColumns()
      // Which normalized to Euclidean length 1.0!
      // Also do the -c multiplication in this process.
      for(int i = 0; i < E[0].length; i++) {
        double sum = 0.0;
        for(int j = 0; j < E.length; j++) {
          sum += E[j][i];
        }
        if(sum == 0) {
          sum = 1.0;
        }
        for(int j = 0; j < E.length; j++) {
          E[j][i] = -c * E[j][i] / sum;
        }
      }
      // Add identity matrix. The diagonal should still be 0s, so this is trivial.
      assert (E.length == E[0].length);
      for(int col = 0; col < E[0].length; col++) {
        assert (E[col][col] == 0.0);
        E[col][col] = 1.0;
      }
      E = timesEquals(inverse(E), 1 - c);
  
      // Split the matrix into columns
      {
        int i = 0;
        for(DBIDIter id = ids.iter(); id.valid(); id.advance(), i++) {
          // Note: matrix times ith unit vector = ith column
          double[] sim = getCol(E, i);
          similarityVectors.put(id, sim);
        }
      }
      E = null;
      // compute the relevance scores between specified Object and its neighbors
      DoubleMinMax minmax = new DoubleMinMax();
      WritableDoubleDataStore scores = DataStoreUtil.makeDoubleStorage(spatial.getDBIDs(), DataStoreFactory.HINT_STATIC);
      for(DBIDIter id = ids.iter(); id.valid(); id.advance()) {
        double gmean = 1.0;
        int cnt = 0;
        for(DBIDIter iter = neighbors.get(id).iter(); iter.valid(); iter.advance()) {
          if(DBIDUtil.equal(id, iter)) {
            continue;
          }
          double sim = angle(similarityVectors.get(id), similarityVectors.get(iter));
          gmean *= sim;
          cnt++;
        }
        final double score = FastMath.pow(gmean, 1.0 / cnt);
        minmax.put(score);
        scores.putDouble(id, score);
      }
  
      DoubleRelation scoreResult = new MaterializedDoubleRelation("randomwalkec", "RandomWalkEC", scores, relation.getDBIDs());
      OutlierScoreMeta scoreMeta = new BasicOutlierScoreMeta(minmax.getMin(), minmax.getMax(), 0.0, Double.POSITIVE_INFINITY, 0.0);
      return new OutlierResult(scoreMeta, scoreResult);
    }