docs: private ArrayDBIDs updateKNNsAndRkNNs(DBIDs ids) {
      ArrayModifiableDBIDs rkNN_ids = DBIDUtil.newArray();
      DBIDs oldids = DBIDUtil.difference(relation.getDBIDs(), ids);
      for(DBIDIter id = oldids.iter(); id.valid(); id.advance()) {
        KNNList oldkNNs = storage.get(id);
        double knnDist = oldkNNs.getKNNDistance();
        // look for new kNNs
        KNNHeap heap = null;
        for(DBIDIter newid = ids.iter(); newid.valid(); newid.advance()) {
          double dist = distanceQuery.distance(id, newid);
          if(dist <= knnDist) {
            // New id changes the kNNs of oldid.
            heap = heap != null ? heap : DBIDUtil.newHeap(oldkNNs);
            heap.insert(dist, newid);
          }
        }
        // kNNs for oldid have changed:
        if(heap != null) {
          KNNList newkNNs = heap.toKNNList();
          storage.put(id, newkNNs);
  
          // get the difference
          ModifiableDoubleDBIDList added = DBIDUtil.newDistanceDBIDList(),
              removed = DBIDUtil.newDistanceDBIDList();
          DoubleDBIDListIter olditer = oldkNNs.iter(), newiter = newkNNs.iter();
          while(olditer.valid() && newiter.valid()) {
            if(DBIDUtil.equal(olditer, newiter)) {
              olditer.advance();
              newiter.advance();
              continue;
            }
            double newd = newiter.doubleValue(), oldd = olditer.doubleValue();
            if(newd < oldd || (newd == oldd && !oldkNNs.contains(newiter))) {
              added.add(newiter.doubleValue(), newiter);
              newiter.advance();
            }
            else if(oldd < newd || (oldd == newd && !newkNNs.contains(olditer))) {
              removed.add(olditer.doubleValue(), olditer);
              olditer.advance();
            }
            else {
              throw new IllegalStateException("Unexpected third case, needs debug!");
            }
          }
          for(; olditer.valid(); olditer.advance()) {
            removed.add(olditer.doubleValue(), olditer);
          }
          for(; newiter.valid(); newiter.advance()) {
            added.add(newiter.doubleValue(), newiter);
          }
          // add new RkNN
          for(DoubleDBIDListIter newnn = added.iter(); newnn.valid(); newnn.advance()) {
            materialized_RkNN.get(newnn).add(DBIDUtil.newPair(newnn.doubleValue(), id));
          }
          // remove old RkNN
          for(DoubleDBIDListIter oldnn = removed.iter(); oldnn.valid(); oldnn.advance()) {
            materialized_RkNN.get(oldnn).remove(DBIDUtil.newPair(oldnn.doubleValue(), id));
          }
  
          rkNN_ids.add(id);
        }
      }
      return rkNN_ids;
    }