docs: public PointerDensityHierarchyRepresentationResult run(Database db, Relation<O> relation) {
      final DistanceQuery<O> distQ = db.getDistanceQuery(relation, getDistanceFunction());
      final KNNQuery<O> knnQ = db.getKNNQuery(distQ, minPts);
      // We need array addressing later.
      final ArrayDBIDs ids = DBIDUtil.ensureArray(relation.getDBIDs());
  
      // Compute the core distances
      // minPts + 1: ignore query point.
      final WritableDoubleDataStore coredists = computeCoreDists(ids, knnQ, minPts);
  
      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);
  
      FiniteProgress progress = LOG.isVerbose() ? new FiniteProgress("Running HDBSCAN*-SLINK", ids.size(), LOG) : null;
      // has to be an array for monotonicity reasons!
      ModifiableDBIDs processedIDs = DBIDUtil.newArray(ids.size());
  
      for(DBIDIter id = ids.iter(); id.valid(); id.advance()) {
        // Steps 1,3,4 are exactly as in SLINK
        step1(id, pi, lambda);
        // Step 2 is modified to use a different distance
        step2(id, processedIDs, distQ, coredists, m);
        step3(id, pi, lambda, processedIDs, m);
        step4(id, pi, lambda, processedIDs);
  
        processedIDs.add(id);
  
        LOG.incrementProcessed(progress);
      }
      LOG.ensureCompleted(progress);
  
      return new PointerDensityHierarchyRepresentationResult(ids, pi, lambda, distQ.getDistanceFunction().isSquared(), coredists);
    }