docstr: Diffusion propagator on a given set of real points.
  if the array r_points is non writeable, then intermediate
  results are cached for faster recalculation
docstr_tok: ["Diffusion","propagator","on","a","given","set","of","real","points",".","if","the","array","r_points","is","non","writeable",",","then","intermediate","results","are","cached","for","faster","recalculation"]
code: def pdf(self, r_points):
      """Diffusion propagator on a given set of real points.
      if the array r_points is non writeable, then intermediate
      results are cached for faster recalculation
      """
      if not r_points.flags.writeable:
          psi = self.model.cache_get(
              "shore_matrix_pdf", key=hash(r_points.data)
          )
      else:
          psi = None
      if psi is None:
          psi = shore_matrix_pdf(self.radial_order, self.zeta, r_points)
          if not r_points.flags.writeable:
              self.model.cache_set(
                  "shore_matrix_pdf", hash(r_points.data), psi
              )
  
      eap = np.dot(psi, self._shore_coef)
  
      return np.clip(eap, 0, eap.max())
  
imports: from warnings import warn
  from math import factorial
  import numpy
  from scipy.special import genlaguerre, gamma, hyp2f1
  from dipy.reconst.cache import Cache
  from dipy.reconst.multi_voxel import multi_voxel_fit
  from dipy.reconst.shm import real_sh_descoteaux_from_index
  from dipy.core.geometry import cart2sphere
  from dipy.utils.optpkg import optional_package
label_desc: Use image node_id 3 for calling the ShoreFit obj's underlying member method code with example usage: obj.pdf(r_points) and returns: np