docs: public Clustering<PrototypeModel<O>> run(Database database, Relation<O> relation) {
      if(!(t1 >= t2)) {
        throw new AbortException("T1 must be at least as large as T2.");
      }
  
      DistanceQuery<O> dq = database.getDistanceQuery(relation, getDistanceFunction());
      ModifiableDBIDs ids = DBIDUtil.newHashSet(relation.getDBIDs());
      ArrayList<Cluster<PrototypeModel<O>>> clusters = new ArrayList<>();
      final int size = relation.size();
      FiniteProgress prog = LOG.isVerbose() ? new FiniteProgress("Canopy clustering", size, LOG) : null;
  
      DBIDVar first = DBIDUtil.newVar();
      while(!ids.isEmpty()) {
        // Remove first element:
        ids.pop(first);
  
        // Start a new cluster:
        ModifiableDBIDs cids = DBIDUtil.newArray();
        cids.add(first);
  
        // Compare to remaining objects:
        for(DBIDMIter iter = ids.iter(); iter.valid(); iter.advance()) {
          double dist = dq.distance(first, iter);
          // Inclusion threshold:
          if(dist > t1) {
            continue;
          }
          cids.add(iter);
          // Removal threshold:
          if(dist <= t2) {
            iter.remove();
          }
        }
        // TODO: remember the central object using a CanopyModel?
        // Construct cluster:
        clusters.add(new Cluster<>(cids, new SimplePrototypeModel<>(relation.get(first))));
  
        if(prog != null) {
          prog.setProcessed(size - ids.size(), LOG);
        }
      }
      LOG.ensureCompleted(prog);
      return new Clustering<>("Canopy clustering", "canopy-clustering", clusters);
    }