docs: public PointerHierarchyRepresentationResult run(Database database, Relation<O> relation) {
      DBIDs ids = relation.getDBIDs();
      WritableDBIDDataStore pi = DataStoreUtil.makeDBIDStorage(ids, DataStoreFactory.HINT_HOT | DataStoreFactory.HINT_STATIC);
      WritableDoubleDataStore lambda = DataStoreUtil.makeDoubleStorage(ids, DataStoreFactory.HINT_HOT | DataStoreFactory.HINT_STATIC, Double.POSITIVE_INFINITY);
      // Temporary storage for m.
      WritableDoubleDataStore m = DataStoreUtil.makeDoubleStorage(ids, DataStoreFactory.HINT_HOT | DataStoreFactory.HINT_TEMP);
  
      final Logging log = getLogger(); // To allow CLINK logger override
  
      FiniteProgress progress = log.isVerbose() ? new FiniteProgress("Running SLINK", ids.size(), log) : null;
      ArrayDBIDs aids = DBIDUtil.ensureArray(ids);
  
      // First element is trivial/special:
      DBIDArrayIter id = aids.iter(), it = aids.iter();
      // Step 1: initialize
      for(; id.valid(); id.advance()) {
        // P(n+1) = n+1:
        pi.put(id, id);
        // L(n+1) = infinity already.
      }
      // First element is finished already (start at seek(1) below!)
      log.incrementProcessed(progress);
  
      // Optimized branch
      if(getDistanceFunction() instanceof PrimitiveDistanceFunction) {
        PrimitiveDistanceFunction<? super O> distf = (PrimitiveDistanceFunction<? super O>) getDistanceFunction();
        for(id.seek(1); id.valid(); id.advance()) {
          step2primitive(id, it, id.getOffset(), relation, distf, m);
          process(id, aids, it, id.getOffset(), pi, lambda, m); // SLINK or CLINK
          log.incrementProcessed(progress);
        }
      }
      else {
        // Fallback branch
        DistanceQuery<O> distQ = database.getDistanceQuery(relation, getDistanceFunction());
        for(id.seek(1); id.valid(); id.advance()) {
          step2(id, it, id.getOffset(), distQ, m);
          process(id, aids, it, id.getOffset(), pi, lambda, m); // SLINK or CLINK
          log.incrementProcessed(progress);
        }
      }
  
      log.ensureCompleted(progress);
      // We don't need m anymore.
      m.destroy();
      m = null;
  
      return new PointerHierarchyRepresentationResult(ids, pi, lambda, getDistanceFunction().isSquared());
    }