docs: private Clustering<SubspaceModel> computeClusters(Relation<V> database, DiSHClusterOrder clusterOrder) {
      final int dimensionality = RelationUtil.dimensionality(database);
  
      // extract clusters
      Object2ObjectOpenCustomHashMap<long[], List<ArrayModifiableDBIDs>> clustersMap = extractClusters(database, clusterOrder);
      logClusterSizes("Step 1: extract clusters", dimensionality, clustersMap);
  
      // check if there are clusters < minpts
      checkClusters(database, clustersMap);
      logClusterSizes("Step 2: check clusters", dimensionality, clustersMap);
  
      // sort the clusters
      List<Cluster<SubspaceModel>> clusters = sortClusters(database, clustersMap);
      if(LOG.isVerbose()) {
        StringBuilder msg = new StringBuilder("Step 3: sort clusters");
        for(Cluster<SubspaceModel> c : clusters) {
          msg.append('\n').append(BitsUtil.toStringLow(c.getModel().getSubspace().getDimensions(), dimensionality)).append(" ids ").append(c.size());
        }
        LOG.verbose(msg.toString());
      }
  
      // build the hierarchy
      Clustering<SubspaceModel> clustering = new Clustering<>("DiSH clustering", "dish-clustering");
      buildHierarchy(database, clustering, clusters, dimensionality);
      if(LOG.isVerbose()) {
        StringBuilder msg = new StringBuilder("Step 4: build hierarchy");
        for(Cluster<SubspaceModel> c : clusters) {
          msg.append('\n').append(BitsUtil.toStringLow(c.getModel().getSubspace().getDimensions(), dimensionality)).append(" ids ").append(c.size());
          for(It<Cluster<SubspaceModel>> iter = clustering.getClusterHierarchy().iterParents(c); iter.valid(); iter.advance()) {
            msg.append("\n   parent ").append(iter.get());
          }
          for(It<Cluster<SubspaceModel>> iter = clustering.getClusterHierarchy().iterChildren(c); iter.valid(); iter.advance()) {
            msg.append("\n   child ").append(iter.get());
          }
        }
        LOG.verbose(msg.toString());
      }
  
      // build result
      for(Cluster<SubspaceModel> c : clusters) {
        if(clustering.getClusterHierarchy().numParents(c) == 0) {
          clustering.addToplevelCluster(c);
        }
      }
      return clustering;
    }