docs: @Override
    public Clustering<M> run(Database database, Relation<V> relation) {
      MutableProgress prog = LOG.isVerbose() ? new MutableProgress("X-means number of clusters", k_max, LOG) : null;
  
      // Run initial k-means to find at least k_min clusters
      innerKMeans.setK(k_min);
      LOG.statistics(new StringStatistic(KEY + ".initialization", initializer.toString()));
      splitInitializer.setInitialMeans(initializer.chooseInitialMeans(database, relation, k_min, getDistanceFunction()));
      Clustering<M> clustering = innerKMeans.run(database, relation);
  
      if(prog != null) {
        prog.setProcessed(k_min, LOG);
      }
  
      ArrayList<Cluster<M>> clusters = new ArrayList<>(clustering.getAllClusters());
      while(clusters.size() <= k_max) {
        // Improve-Structure:
        ArrayList<Cluster<M>> nextClusters = new ArrayList<>();
        for(Cluster<M> cluster : clusters) {
          // Try to split this cluster:
          List<Cluster<M>> childClusterList = splitCluster(cluster, database, relation);
          nextClusters.addAll(childClusterList);
          if(childClusterList.size() > 1) {
            k += childClusterList.size() - 1;
            if(prog != null) {
              if(k >= k_max) {
                prog.setTotal(k + 1);
              }
              prog.setProcessed(k, LOG);
            }
          }
        }
        if(clusters.size() == nextClusters.size()) {
          break;
        }
        // Improve-Params:
        splitInitializer.setInitialClusters(nextClusters);
        innerKMeans.setK(nextClusters.size());
        clustering = innerKMeans.run(database, relation);
        clusters.clear();
        clusters.addAll(clustering.getAllClusters());
      }
  
      // Ensure that the progress bar finished.
      if(prog != null) {
        prog.setTotal(k);
        prog.setProcessed(k, LOG);
      }
      return new Clustering<>("X-Means Result", "X-Means", clusters);
    }