docs: public OutlierResult run(Relation<V> relation) {
      final int dim = RelationUtil.dimensionality(relation);
      final int size = relation.size();
      ArrayList<ArrayList<DBIDs>> ranges = buildRanges(relation);
  
      ArrayList<int[]> Rk;
      // Build a list of all subspaces
      FiniteProgress prog = LOG.isVerbose() ? new FiniteProgress("Subspace size", k, LOG) : null;
      // R1 initial one-dimensional subspaces.
      Rk = new ArrayList<>();
      // Set of all dim*phi ranges
      ArrayList<IntIntPair> q = new ArrayList<>();
      for(int i = 0; i < dim; i++) {
        for(int j = 0; j < phi; j++) {
          q.add(new IntIntPair(i, j));
          Rk.add(new int[] { i, j });
        }
      }
      LOG.incrementProcessed(prog);
  
      // build Ri
      for(int i = 2; i <= k; i++) {
        ArrayList<int[]> Rnew = new ArrayList<>();
  
        for(int j = 0; j < Rk.size(); j++) {
          int[] c = Rk.get(j);
          for(IntIntPair pair : q) {
            boolean invalid = false;
            for(int t = 0; t < c.length; t += 2) {
              if(c[t] == pair.first) {
                invalid = true;
                break;
              }
            }
            if(!invalid) {
              int[] neu = Arrays.copyOf(c, c.length + 2);
              neu[c.length] = pair.first;
              neu[c.length + 1] = pair.second;
              Rnew.add(neu);
            }
          }
        }
        Rk = Rnew;
        LOG.incrementProcessed(prog);
      }
      if(prog != null) {
        prog.setProcessed(k, LOG);
      }
      LOG.ensureCompleted(prog);
  
      WritableDoubleDataStore sparsity = DataStoreUtil.makeDoubleStorage(relation.getDBIDs(), DataStoreFactory.HINT_HOT | DataStoreFactory.HINT_STATIC);
      // calculate the sparsity coefficient
      for(int[] sub : Rk) {
        DBIDs ids = computeSubspace(sub, ranges);
        final double sparsityC = sparsity(ids.size(), size, k, phi);
  
        if(sparsityC < 0) {
          for(DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) {
            double prev = sparsity.doubleValue(iter);
            if(Double.isNaN(prev) || sparsityC < prev) {
              sparsity.putDouble(iter, sparsityC);
            }
          }
        }
      }
      DoubleMinMax minmax = new DoubleMinMax();
      for(DBIDIter iditer = relation.iterDBIDs(); iditer.valid(); iditer.advance()) {
        double val = sparsity.doubleValue(iditer);
        if(Double.isNaN(val)) {
          sparsity.putDouble(iditer, 0.0);
          val = 0.0;
        }
        minmax.put(val);
      }
      DoubleRelation scoreResult = new MaterializedDoubleRelation("AggarwalYuNaive", "aggarwal-yu-outlier", sparsity, relation.getDBIDs());
      OutlierScoreMeta meta = new InvertedOutlierScoreMeta(minmax.getMin(), minmax.getMax(), Double.NEGATIVE_INFINITY, 0.0);
      return new OutlierResult(meta, scoreResult);
    }