Builds the cluster hierarchy.

@param clustering Clustering we process
@param clusters the sorted list of clusters
@param dimensionality the dimensionality of the data
@param database the database containing the data objects
776057
private void buildHierarchy(Relation<V> database, Clustering<SubspaceModel> clustering, List<Cluster<SubspaceModel>> clusters, int dimensionality) {
    StringBuilder msg = LOG.isDebugging() ? new StringBuilder() : null;
    final int db_dim = RelationUtil.dimensionality(database);
    Hierarchy<Cluster<SubspaceModel>> hier = clustering.getClusterHierarchy();

    for(int i = 0; i < clusters.size() - 1; i++) {
      Cluster<SubspaceModel> c_i = clusters.get(i);
      final Subspace s_i = c_i.getModel().getSubspace();
      int subspaceDim_i = dimensionality - s_i.dimensionality();
      NumberVector ci_centroid = ProjectedCentroid.make(s_i.getDimensions(), database, c_i.getIDs());
      long[] pv1 = s_i.getDimensions();

      for(int j = i + 1; j < clusters.size(); j++) {
        Cluster<SubspaceModel> c_j = clusters.get(j);
        final Subspace s_j = c_j.getModel().getSubspace();
        int subspaceDim_j = dimensionality - s_j.dimensionality();

        if(subspaceDim_i < subspaceDim_j) {
          if(msg != null) {
            msg.append("\n l_i=").append(subspaceDim_i).append(" pv_i=[").append(BitsUtil.toStringLow(s_i.getDimensions(), db_dim)).append(']') //
                .append("\n l_j=").append(subspaceDim_j).append(" pv_j=[").append(BitsUtil.toStringLow(s_j.getDimensions(), db_dim)).append(']');
          }

          // noise level reached
          if(s_j.dimensionality() == 0) {
            // no parents exists -> parent is noise
            if(hier.numParents(c_i) == 0) {
              clustering.addChildCluster(c_j, c_i);
              if(msg != null) {
                msg.append("\n [").append(BitsUtil.toStringLow(s_j.getDimensions(), db_dim)) //
                    .append("] is parent of [").append(BitsUtil.toStringLow(s_i.getDimensions(), db_dim)).append(']');
              }
            }
          }
          else {
            NumberVector cj_centroid = ProjectedCentroid.make(c_j.getModel().getDimensions(), database, c_j.getIDs());
            long[] pv2 = s_j.getDimensions();
            long[] commonPreferenceVector = BitsUtil.andCMin(pv1, pv2);
            int subspaceDim = subspaceDimensionality(ci_centroid, cj_centroid, pv1, pv2, commonPreferenceVector);

            double d = weightedDistance(ci_centroid, cj_centroid, commonPreferenceVector);
            if(msg != null) {
              msg.append("\n dist = ").append(subspaceDim);
            }

            if(subspaceDim == subspaceDim_j) {
              if(msg != null) {
                msg.append("\n d = ").append(d);
              }
              if(d <= 2 * epsilon) {
                // no parent exists or c_j is not a parent of the already
                // existing parents
                if(hier.numParents(c_i) == 0 || !isParent(database, c_j, hier.iterParents(c_i), db_dim)) {
                  clustering.addChildCluster(c_j, c_i);
                  if(msg != null) {
                    msg.append("\n [").append(BitsUtil.toStringLow(s_j.getDimensions(), db_dim)) //
                        .append("] is parent of [") //
                        .append(BitsUtil.toStringLow(s_i.getDimensions(), db_dim)).append(']');
                  }
                }
              }
              else {
                throw new RuntimeException("Should never happen: d = " + d);
              }
            }
          }
        }
      }
    }
    if(msg != null) {
      LOG.debug(msg.toString());
    }
  }
134611
public void setCacheClusters(java.util.Collection<CacheCluster> cacheClusters) {
        if (cacheClusters == null) {
            this.cacheClusters = null;
            return;
        }

        this.cacheClusters = new com.amazonaws.internal.SdkInternalList<CacheCluster>(cacheClusters);
    }
122375
void mergeClusters_(int cluster_1, int cluster2) {
		// dbg_check_cluster_(cluster_1);
		// dbg_check_cluster_(cluster2);
		int eventQnode = getClusterEventQNode(cluster2);
		if (eventQnode != -1) {
			m_event_q.deleteNode(eventQnode, -1);
			setClusterEventQNode_(cluster2, -1);
		}

		int firstEdge1 = getClusterFirstEdge(cluster_1);
		int firstEdge2 = getClusterFirstEdge(cluster2);

		if (firstEdge2 != -1) {// scope
			int edge2 = firstEdge2;
			int lastEdge = firstEdge2;
			boolean bForceContinue = false;
			// Delete edges that connect cluster_1 and cluster2.
			do {
				// dbg_check_edge_(edge2);
				bForceContinue = false;
				// assert(!StridedIndexTypeCollection.isValidElement(getEdgeSweepNode(edge2)));
				int end = getEdgeEnd(edge2, cluster2);
				int nextEdge2 = getNextEdgeEx(edge2, end);
				if (getEdgeCluster(edge2, (end + 1) & 1) == cluster_1) { // Snapping
																			// clusters
																			// that
																			// are
																			// connected
																			// with
																			// an
																			// edge
																			// Delete
																			// the
																			// edge.
					disconnectEdge_(edge2);
					int edgeOrigins2 = getEdgeOriginVertices(edge2);
					m_edge_vertices.deleteList(edgeOrigins2);
					deleteEdge_(edge2);
					if (edge2 == nextEdge2) {// deleted last edge connecting to
												// the cluster2 (all connections
												// are degenerate)
						firstEdge2 = -1;
						break;
					}
					if (firstEdge2 == edge2) {
						firstEdge2 = getClusterFirstEdge(cluster2);
						lastEdge = nextEdge2;
						bForceContinue = true;
					}
				} else {
					assert (edge2 != getClusterFirstEdge(cluster_1));
				}
				edge2 = nextEdge2;
			} while (edge2 != lastEdge || bForceContinue);

			if (firstEdge2 != -1) {
				// set the cluster to the edge ends
				do {
					int end = getEdgeEnd(edge2, cluster2);
					int nextEdge2 = getNextEdgeEx(edge2, end);
					assert (edge2 != getClusterFirstEdge(cluster_1));
					setEdgeCluster_(edge2, end, cluster_1);
					edge2 = nextEdge2;
				} while (edge2 != lastEdge);

				firstEdge1 = getClusterFirstEdge(cluster_1);
				if (firstEdge1 != -1) {
					int next1 = getNextEdge(firstEdge1, cluster_1);
					int next2 = getNextEdge(firstEdge2, cluster_1);
					if (next1 == firstEdge1) {
						setClusterFirstEdge_(cluster_1, firstEdge2);
						addEdgeToClusterImpl_(firstEdge1, cluster_1);
						setClusterFirstEdge_(cluster_1, firstEdge1);
					} else if (next2 == firstEdge2) {
						addEdgeToClusterImpl_(firstEdge2, cluster_1);
					}

					setNextEdge_(firstEdge2, cluster_1, next1);
					setPrevEdge_(next1, cluster_1, firstEdge2);
					setNextEdge_(firstEdge1, cluster_1, next2);
					setPrevEdge_(next2, cluster_1, firstEdge1);
				} else {
					setClusterFirstEdge_(cluster_1, firstEdge2);
				}
			}
		}

		int vertices1 = getClusterVertices(cluster_1);
		int vertices2 = getClusterVertices(cluster2);
		// Update cluster info on vertices.
		for (int vh = m_cluster_vertices.getFirst(vertices2); vh != -1; vh = m_cluster_vertices
				.getNext(vh)) {
			int v = m_cluster_vertices.getElement(vh);
			m_shape.setUserIndex(v, m_vertex_cluster_index, cluster_1);
		}
		m_cluster_vertices.concatenateLists(vertices1, vertices2);
		deleteCluster_(cluster2);
		// dbg_check_cluster_(cluster_1);
	}
1317073
public void setClusterInfoList(java.util.Collection<ClusterInfo> clusterInfoList) {
        if (clusterInfoList == null) {
            this.clusterInfoList = null;
            return;
        }

        this.clusterInfoList = new java.util.ArrayList<ClusterInfo>(clusterInfoList);
    }
1317771
void get_cluster_features(final Context ctx,
                              final List<Integer> cluster4,
                              final List<Integer> cluster6,
                              final List<Integer> cluster,
                              List<Integer> features)
    {
        if (!use_cluster)
        {
            return;
        }

        PUSH(features, CLUSTER(cluster, ctx.S0));
        PUSH(features, CLUSTER4(cluster4, ctx.S0));
        PUSH(features, CLUSTER6(cluster6, ctx.S0));
        PUSH(features, CLUSTER(cluster, ctx.S1));
        PUSH(features, CLUSTER(cluster, ctx.S2));
        PUSH(features, CLUSTER(cluster, ctx.N0));
        PUSH(features, CLUSTER4(cluster4, ctx.N0));
        PUSH(features, CLUSTER6(cluster6, ctx.N0));
        PUSH(features, CLUSTER(cluster, ctx.N1));
        PUSH(features, CLUSTER(cluster, ctx.N2));
        PUSH(features, CLUSTER(cluster, ctx.S0L));
        PUSH(features, CLUSTER(cluster, ctx.S0R));
        PUSH(features, CLUSTER(cluster, ctx.S0L2));
        PUSH(features, CLUSTER(cluster, ctx.S0R2));
        PUSH(features, CLUSTER(cluster, ctx.S0LL));
        PUSH(features, CLUSTER(cluster, ctx.S0RR));
        PUSH(features, CLUSTER(cluster, ctx.S1L));
        PUSH(features, CLUSTER(cluster, ctx.S1R));
        PUSH(features, CLUSTER(cluster, ctx.S1L2));
        PUSH(features, CLUSTER(cluster, ctx.S1R2));
        PUSH(features, CLUSTER(cluster, ctx.S1LL));
        PUSH(features, CLUSTER(cluster, ctx.S1RR));
    }
1266120
public void setDBClusterOptionGroupMemberships(java.util.Collection<DBClusterOptionGroupStatus> dBClusterOptionGroupMemberships) {
        if (dBClusterOptionGroupMemberships == null) {
            this.dBClusterOptionGroupMemberships = null;
            return;
        }

        this.dBClusterOptionGroupMemberships = new java.util.ArrayList<DBClusterOptionGroupStatus>(dBClusterOptionGroupMemberships);
    }
581380
public void listClusters() {
    System.out.println("\nListing Clusters");
    // [START bigtable_get_clusters]
    try {
      List<Cluster> clusters = adminClient.listClusters(instanceId);
      for (Cluster cluster : clusters) {
        System.out.println(cluster.getId());
      }
    } catch (NotFoundException e) {
      System.err.println("Failed to list clusters from a non-existent instance: " + e.getMessage());
    }
    // [END bigtable_get_clusters]
  }
1194574
public List<Cluster> cluster(final Collection<Point2D> points) {
    	final List<Cluster> clusters = new ArrayList<Cluster>();
        final Map<Point2D, PointStatus> visited = new HashMap<Point2D, DBScan.PointStatus>();

        KDTree<Point2D> tree = new KDTree<Point2D>(2);
        
        // Populate the kdTree
        for (final Point2D point : points) {
        	double[] key = {point.x, point.y};
        	tree.insert(key, point);
        }
                
        for (final Point2D point : points) {
            if (visited.get(point) != null) {
                continue;
            }
            final List<Point2D> neighbors = getNeighbors(point, tree);
            if (neighbors.size() >= minPoints) {
                // DBSCAN does not care about center points
                final Cluster cluster = new Cluster(clusters.size());
                clusters.add(expandCluster(cluster, point, neighbors, tree, visited));
            } else {
                visited.put(point, PointStatus.NOISE);
            }
        }

        for (Cluster cluster : clusters) {
        	cluster.calculateCentroid();
        }
        
        return clusters;
    }
1065575
public void setDBClusterMembers(java.util.Collection<DBClusterMember> dBClusterMembers) {
        if (dBClusterMembers == null) {
            this.dBClusterMembers = null;
            return;
        }

        this.dBClusterMembers = new java.util.ArrayList<DBClusterMember>(dBClusterMembers);
    }
341741
public OutlierResult run(Database database, Relation<O> relation) {
    StepProgress stepprog = LOG.isVerbose() ? new StepProgress("CBLOF", 3) : null;
    DBIDs ids = relation.getDBIDs();

    LOG.beginStep(stepprog, 1, "Computing clustering.");
    Clustering<MeanModel> clustering = clusteringAlgorithm.run(database);

    LOG.beginStep(stepprog, 2, "Computing boundary between large and small clusters.");
    List<? extends Cluster<MeanModel>> clusters = clustering.getAllClusters();
    Collections.sort(clusters, new Comparator<Cluster<MeanModel>>() {
      @Override
      public int compare(Cluster<MeanModel> o1, Cluster<MeanModel> o2) {
        // Sort in descending order by size
        return Integer.compare(o2.size(), o1.size());
      }
    });
    int clusterBoundary = getClusterBoundary(relation, clusters);

    List<? extends Cluster<MeanModel>> largeClusters = clusters.subList(0, clusterBoundary + 1);
    List<? extends Cluster<MeanModel>> smallClusters = clusters.subList(clusterBoundary + 1, clusters.size());

    LOG.beginStep(stepprog, 3, "Computing Cluster-Based Local Outlier Factors (CBLOF).");
    WritableDoubleDataStore cblofs = DataStoreUtil.makeDoubleStorage(ids, DataStoreFactory.HINT_HOT | DataStoreFactory.HINT_DB);
    DoubleMinMax cblofMinMax = new DoubleMinMax();
    computeCBLOFs(relation, distance, cblofs, cblofMinMax, largeClusters, smallClusters);

    LOG.setCompleted(stepprog);

    DoubleRelation scoreResult = new MaterializedDoubleRelation("Cluster-Based Local Outlier Factor", "cblof-outlier", cblofs, ids);
    OutlierScoreMeta scoreMeta = new QuotientOutlierScoreMeta(cblofMinMax.getMin(), cblofMinMax.getMax(), 0.0, Double.POSITIVE_INFINITY, 1.0);
    return new OutlierResult(scoreMeta, scoreResult);
  }
477409
public double evaluateClustering(Database db, Relation<O> rel, Clustering<?> cl) {
    final DistanceQuery<O> dq = rel.getDistanceQuery(distanceFunction);

    List<? extends Cluster<?>> clusters = cl.getAllClusters();
    final int numc = clusters.size();

    // DBCV needs a "dimensionality".
    @SuppressWarnings("unchecked")
    final Relation<? extends SpatialComparable> vrel = (Relation<? extends SpatialComparable>) rel;
    final int dim = RelationUtil.dimensionality(vrel);

    // precompute all core distances
    ArrayDBIDs[] cids = new ArrayDBIDs[numc];
    double[][] coreDists = new double[numc][];
    for(int c = 0; c < numc; c++) {
      Cluster<?> cluster = clusters.get(c);
      // Singletons are considered as Noise, because they have no sparseness
      if(cluster.isNoise() || cluster.size() < 2) {
        coreDists[c] = null;
        continue;
      }
      // Store for use below:
      ArrayDBIDs ids = cids[c] = DBIDUtil.ensureArray(cluster.getIDs());
      double[] clusterCoreDists = coreDists[c] = new double[ids.size()];
      for(DBIDArrayIter it = ids.iter(), it2 = ids.iter(); it.valid(); it.advance()) {
        double currentCoreDist = 0;
        int neighbors = 0;
        for(it2.seek(0); it2.valid(); it2.advance()) {
          if(DBIDUtil.equal(it, it2)) {
            continue;
          }
          double dist = dq.distance(it, it2);
          // Unfortunately, the DBCV definition has a division by zero.
          // We ignore such objects.
          if(dist > 0) {
            currentCoreDist += MathUtil.powi(1. / dist, dim);
            ++neighbors;
          }
        }
        // Average, and undo power.
        clusterCoreDists[it.getOffset()] = FastMath.pow(currentCoreDist / neighbors, -1. / dim);
      }
    }

    // compute density sparseness of all clusters
    int[][] clusterDegrees = new int[numc][];
    double[] clusterDscMax = new double[numc];
    // describes if a cluster contains any internal edges
    boolean[] internalEdges = new boolean[numc];
    for(int c = 0; c < numc; c++) {
      Cluster<?> cluster = clusters.get(c);
      if(cluster.isNoise() || cluster.size() < 2) {
        clusterDegrees[c] = null;
        clusterDscMax[c] = Double.NaN;
        continue;
      }
      double[] clusterCoreDists = coreDists[c];
      ArrayDBIDs ids = cids[c];
      double dscMax = 0; // Density Sparseness of the Cluster
      double[][] distances = new double[cluster.size()][cluster.size()];

      // create mutability distance matrix for Minimum Spanning Tree
      for(DBIDArrayIter it = ids.iter(), it2 = ids.iter(); it.valid(); it.advance()) {
        double currentCoreDist = clusterCoreDists[it.getOffset()];
        for(it2.seek(it.getOffset() + 1); it2.valid(); it2.advance()) {
          double mutualReachDist = MathUtil.max(currentCoreDist, clusterCoreDists[it2.getOffset()], dq.distance(it, it2));
          distances[it.getOffset()][it2.getOffset()] = mutualReachDist;
          distances[it2.getOffset()][it.getOffset()] = mutualReachDist;
        }
      }

      // generate Minimum Spanning Tree
      int[] nodes = PrimsMinimumSpanningTree.processDense(distances);

      // get degree of all nodes in the spanning tree
      int[] degree = new int[cluster.size()];
      for(int i = 0; i < nodes.length; i++) {
        degree[nodes[i]]++;
      }
      // check if cluster contains any internal edges
      for(int i = 0, e = nodes.length - 1; i < e; i += 2) {
        if(degree[nodes[i]] > 1 && degree[nodes[i + 1]] > 1) {
          internalEdges[c] = true;
        }
      }

      clusterDegrees[c] = degree;

      // find maximum sparseness in the Minimum Spanning Tree
      for(int i = 0, e = nodes.length - 1; i < e; i += 2) {
        final int n1 = nodes[i], n2 = nodes[i + 1];
        // We only consider edges where both vertices are internal nodes.
        // If a cluster has no internal nodes we consider all edges.
        if(distances[n1][n2] > dscMax && (!internalEdges[c] || (degree[n1] > 1 && degree[n2] > 1))) {
          dscMax = distances[n1][n2];
        }
      }
      clusterDscMax[c] = dscMax;
    }

    // compute density separation of all clusters
    double dbcv = 0;
    for(int c = 0; c < numc; c++) {
      Cluster<?> cluster = clusters.get(c);
      if(cluster.isNoise() || cluster.size() < 2) {
        continue;
      }
      double currentDscMax = clusterDscMax[c];
      double[] clusterCoreDists = coreDists[c];
      int[] currentDegree = clusterDegrees[c];

      // minimal Density Separation of the Cluster
      double dspcMin = Double.POSITIVE_INFINITY;
      for(DBIDArrayIter it = cids[c].iter(); it.valid(); it.advance()) {
        // We again ignore external nodes, if the cluster has any internal
        // nodes.
        if(currentDegree[it.getOffset()] < 2 && internalEdges[c]) {
          continue;
        }
        double currentCoreDist = clusterCoreDists[it.getOffset()];
        for(int oc = 0; oc < numc; oc++) {
          Cluster<?> ocluster = clusters.get(oc);
          if(ocluster.isNoise() || ocluster.size() < 2 || cluster == ocluster) {
            continue;
          }
          int[] oDegree = clusterDegrees[oc];
          double[] oclusterCoreDists = coreDists[oc];
          for(DBIDArrayIter it2 = cids[oc].iter(); it2.valid(); it2.advance()) {
            if(oDegree[it2.getOffset()] < 2 && internalEdges[oc]) {
              continue;
            }
            double mutualReachDist = MathUtil.max(currentCoreDist, oclusterCoreDists[it2.getOffset()], dq.distance(it, it2));
            dspcMin = mutualReachDist < dspcMin ? mutualReachDist : dspcMin;
          }
        }
      }

      // compute DBCV
      double vc = (dspcMin - currentDscMax) / MathUtil.max(dspcMin, currentDscMax);
      double weight = cluster.size() / (double) rel.size();
      dbcv += weight * vc;
    }

    EvaluationResult ev = EvaluationResult.findOrCreate(db.getHierarchy(), cl, "Internal Clustering Evaluation", "internal evaluation");
    MeasurementGroup g = ev.findOrCreateGroup("Distance-based Evaluation");
    g.addMeasure("Density Based Clustering Validation", dbcv, 0., Double.POSITIVE_INFINITY, 0., true);
    db.getHierarchy().resultChanged(ev);
    return dbcv;
  }
689215
public void setDBClusterMembers(java.util.Collection<DBClusterMember> dBClusterMembers) {
        if (dBClusterMembers == null) {
            this.dBClusterMembers = null;
            return;
        }

        this.dBClusterMembers = new com.amazonaws.internal.SdkInternalList<DBClusterMember>(dBClusterMembers);
    }
34173
public void setClusterArns(java.util.Collection<String> clusterArns) {
        if (clusterArns == null) {
            this.clusterArns = null;
            return;
        }

        this.clusterArns = new com.amazonaws.internal.SdkInternalList<String>(clusterArns);
    }
1316793
public Clustering<SubspaceModel> run(Relation<? extends NumberVector> relation) {
    final int dimensionality = RelationUtil.dimensionality(relation);
    StepProgress step = new StepProgress(2);

    // 1. Identification of subspaces that contain clusters
    step.beginStep(1, "Identification of subspaces that contain clusters", LOG);
    ArrayList<List<CLIQUESubspace>> dimensionToDenseSubspaces = new ArrayList<>(dimensionality);
    List<CLIQUESubspace> denseSubspaces = findOneDimensionalDenseSubspaces(relation);
    dimensionToDenseSubspaces.add(denseSubspaces);
    if(LOG.isVerbose()) {
      LOG.verbose("1-dimensional dense subspaces: " + denseSubspaces.size());
    }
    if(LOG.isDebugging()) {
      for(CLIQUESubspace s : denseSubspaces) {
        LOG.debug(s.toString());
      }
    }

    for(int k = 2; k <= dimensionality && !denseSubspaces.isEmpty(); k++) {
      denseSubspaces = findDenseSubspaces(relation, denseSubspaces);
      assert (dimensionToDenseSubspaces.size() == k - 1);
      dimensionToDenseSubspaces.add(denseSubspaces);
      if(LOG.isVerbose()) {
        LOG.verbose(k + "-dimensional dense subspaces: " + denseSubspaces.size());
      }
      if(LOG.isDebugging()) {
        for(CLIQUESubspace s : denseSubspaces) {
          LOG.debug(s.toString());
        }
      }
    }

    // 2. Identification of clusters
    step.beginStep(2, "Identification of clusters", LOG);
    // build result
    Clustering<SubspaceModel> result = new Clustering<>("CLIQUE clustering", "clique-clustering");
    for(int dim = 0; dim < dimensionToDenseSubspaces.size(); dim++) {
      List<CLIQUESubspace> subspaces = dimensionToDenseSubspaces.get(dim);
      List<Pair<Subspace, ModifiableDBIDs>> modelsAndClusters = determineClusters(subspaces);

      if(LOG.isVerbose()) {
        LOG.verbose((dim + 1) + "-dimensional clusters: " + modelsAndClusters.size());
      }

      for(Pair<Subspace, ModifiableDBIDs> modelAndCluster : modelsAndClusters) {
        Cluster<SubspaceModel> newCluster = new Cluster<>(modelAndCluster.second);
        newCluster.setModel(new SubspaceModel(modelAndCluster.first, Centroid.make(relation, modelAndCluster.second).getArrayRef()));
        result.addToplevelCluster(newCluster);
      }
    }

    return result;
  }
812834
public void setDBClusterBacktracks(java.util.Collection<DBClusterBacktrack> dBClusterBacktracks) {
        if (dBClusterBacktracks == null) {
            this.dBClusterBacktracks = null;
            return;
        }

        this.dBClusterBacktracks = new com.amazonaws.internal.SdkInternalList<DBClusterBacktrack>(dBClusterBacktracks);
    }
132817
public void setDBClusterSnapshots(java.util.Collection<DBClusterSnapshot> dBClusterSnapshots) {
        if (dBClusterSnapshots == null) {
            this.dBClusterSnapshots = null;
            return;
        }

        this.dBClusterSnapshots = new java.util.ArrayList<DBClusterSnapshot>(dBClusterSnapshots);
    }
178294
private void logClusterSizes(String m, int dimensionality, Object2ObjectOpenCustomHashMap<long[], List<ArrayModifiableDBIDs>> clustersMap) {
    if(LOG.isVerbose()) {
      final StringBuilder msg = new StringBuilder(1000).append(m).append('\n');
      for(ObjectIterator<Object2ObjectMap.Entry<long[], List<ArrayModifiableDBIDs>>> iter = clustersMap.object2ObjectEntrySet().fastIterator(); iter.hasNext();) {
        Object2ObjectMap.Entry<long[], List<ArrayModifiableDBIDs>> entry = iter.next();
        msg.append(BitsUtil.toStringLow(entry.getKey(), dimensionality)).append(" sizes:");
        for(ArrayModifiableDBIDs c : entry.getValue()) {
          msg.append(' ').append(c.size());
        }
        msg.append('\n');
      }
      LOG.verbose(msg.toString());
    }
  }