code: def rescaled_distance_mtx(p, q):
      r
  
      # TODO: check that models are actually the same!
      p_locs = p.particle_locations if isinstance(p, qinfer.ParticleDistribution) else p
      q_locs = q.particle_locations if isinstance(q, qinfer.ParticleDistribution) else q
      Q = p.model.Q if isinstance(p, qinfer.smc.SMCUpdater) else 1
  
      # Because the modelparam axis is last in each of the three cases, we're
      # good as far as broadcasting goes.
      delta = np.sqrt(Q) * (
          p_locs[:, np.newaxis, :] -
          q_locs[np.newaxis, :, :]
      )
  
      return np.sqrt(np.sum(delta**2, axis=-1))
docs: r"""
      Given two particle updaters for the same model, returns a matrix
      :math:`\matr{d}` with elements
  
      .. math::
          \matr{d}_{i,j} = \left\Vert \sqrt{\matr{Q}} \cdot
              (\vec{x}_{p, i} - \vec{x}_{q, j}) \right\Vert_2,
  
      where :math:`\matr{Q}` is the scale matrix of the model,
      :math:`\vec{x}_{p,i}` is the :math:`i`th particle of ``p``, and where
      :math:`\vec{x}_{q,i}` is the :math:`i`th particle of ``q`.
  
      :param qinfer.smc.SMCUpdater p: SMC updater for the distribution
          :math:`p(\vec{x})`.
      :param qinfer.smc.SMCUpdater q: SMC updater for the distribution
          :math:`q(\vec{x})`.
  
      Either or both of ``p`` or ``q`` can simply be the locations array for
      an :ref:`SMCUpdater`.