docs: private SimilarityMatrix computeSimilarityMatrixImage(Relation<O> relation, DBIDIter iter) {
      ArrayModifiableDBIDs order = DBIDUtil.newArray(relation.size());
      for(; iter.valid(); iter.advance()) {
        order.add(iter);
      }
      if(order.size() != relation.size()) {
        throw new IllegalStateException("Iterable result doesn't match database size - incomplete ordering?");
      }
      DistanceQuery<O> dq = distanceFunction.instantiate(relation);
      final int size = order.size();
  
      // When the logging is in the outer loop, it's just 2*size (providing enough
      // resolution)
      final int ltotal = 2 * size; // size * (size + 1);
      FiniteProgress prog = LOG.isVerbose() ? new FiniteProgress("Similarity Matrix Image", ltotal, LOG) : null;
  
      // Note: we assume that we have an efficient distance cache available,
      // since we are using 2*O(n*n) distance computations.
      DoubleMinMax minmax = new DoubleMinMax();
      {
        DBIDArrayIter id1 = order.iter();
        DBIDArrayIter id2 = order.iter();
        for(; id1.valid(); id1.advance()) {
          id2.seek(id1.getOffset());
          for(; id2.valid(); id2.advance()) {
            final double dist = dq.distance(id1, id2);
            if(!Double.isNaN(dist) && !Double.isInfinite(dist) /* && dist > 0.0 */) {
              if(!skipzero || dist > 0.0) {
                minmax.put(dist);
              }
            }
          }
          LOG.incrementProcessed(prog);
        }
      }
  
      double zoom = minmax.getMax() - minmax.getMin();
      if(zoom > 0.0) {
        zoom = 1. / zoom;
      }
      LinearScaling scale = new LinearScaling(zoom, -minmax.getMin() * zoom);
      BufferedImage img = new BufferedImage(size, size, BufferedImage.TYPE_INT_RGB);
      {
        DBIDArrayIter id1 = order.iter();
        DBIDArrayIter id2 = order.iter();
        for(int x = 0; x < size && id1.valid(); x++, id1.advance()) {
          id2.seek(id1.getOffset());
          for(int y = x; y < size && id2.valid(); y++, id2.advance()) {
            double ddist = dq.distance(id1, id2);
            if(ddist > 0.0) {
              ddist = scale.getScaled(ddist);
            }
            // Apply extra scaling
            if(scaling != null) {
              ddist = scaling.getScaled(ddist);
            }
            int dist = 0xFF & (int) (255 * ddist);
            int col = 0xff000000 | (dist << 16) | (dist << 8) | dist;
            img.setRGB(x, y, col);
            img.setRGB(y, x, col);
          }
          LOG.incrementProcessed(prog);
        }
      }
      LOG.ensureCompleted(prog);
  
      return new SimilarityMatrix(img, relation, order);
    }