docstr: Verifies samples are consistent with the PDF using importance sampling.
  
  In particular, we verify an estimate the surface area of the n-dimensional
  hypersphere, and the surface areas of the spherical caps demarcated by
  a handful of survival rates.
  
  Args:
    pspherical: A `PowerSpherical` distribution instance.
    rtol: Relative difference tolerable.
docstr_tok: ["Verifies","samples","are","consistent","with","the","PDF","using","importance","sampling",".","In","particular",",","we","verify","an","estimate","the","surface","area","of","the","n-dimensional","hypersphere",",","and","the","surface","areas","of","the","spherical","caps","demarcated","by","a","handful","of","survival","rates",".","Args",":","pspherical",":","A","`","PowerSpherical","`","distribution","instance",".","rtol",":","Relative","difference","tolerable","."]
code: def VerifySampleAndPdfConsistency(self, pspherical, rtol=0.075):
      """Verifies samples are consistent with the PDF using importance sampling.
  
      In particular, we verify an estimate the surface area of the n-dimensional
      hypersphere, and the surface areas of the spherical caps demarcated by
      a handful of survival rates.
  
      Args:
        pspherical: A `PowerSpherical` distribution instance.
        rtol: Relative difference tolerable.
      """
      dim = tf.compat.dimension_value(pspherical.event_shape[-1])
      nsamples = int(1e5)
      samples = pspherical.sample(
          sample_shape=[nsamples], seed=test_util.test_seed()
      )
      samples = tf.debugging.check_numerics(samples, "samples")
      log_prob = pspherical.log_prob(samples)
      log_prob, samples = self.evaluate([log_prob, samples])
      # Check that the log_prob is not nan or +inf. It can be -inf since
      # if we sample a direction diametrically opposite to the mean direction,
      # we'll get an inner product of -1.
      self.assertFalse(np.any(np.isnan(log_prob)))
      self.assertFalse(np.any(np.isposinf(log_prob)))
      log_importance = -log_prob
      sphere_surface_area_estimate, importance = self.evaluate(
          [
              tf.reduce_mean(tf.math.exp(log_importance), axis=0),
              tf.exp(log_importance),
          ]
      )
      true_sphere_surface_area = (
          2
          * (np.pi) ** (dim / 2)
          * self.evaluate(tf.exp(-tf.math.lgamma(dim / 2)))
      )
      # Broadcast to correct size
      true_sphere_surface_area += np.zeros_like(
          sphere_surface_area_estimate
      )
      # Highly concentrated distributions do not get enough coverage to provide
      # a reasonable full-sphere surface area estimate. These are covered below
      # by CDF-based hypersphere cap surface area estimates.
      # Because the PowerSpherical distribution has zero mass at
      # -`mean_direction` (and points close to -`mean_direction` due to floating
      # point), we only compute this at concentration = 0, which has guaranteed
      # mass everywhere.
      self.assertAllClose(
          true_sphere_surface_area[0],
          sphere_surface_area_estimate[0],
          rtol=rtol,
      )
  
      # Assert surface area of hyperspherical cap For some CDFs in [.05,.45],
      # (h must be greater than 0 for the hypersphere cap surface area
      # calculation to hold).
      for survival_rate in 0.95, 0.9, 0.75, 0.6:
          cdf = 1 - survival_rate
          mean_dir = self.evaluate(pspherical.mean_direction)
          dotprods = np.sum(samples * mean_dir, -1)
          # Empirical estimate of the effective dot-product of the threshold that
          # selects for a given CDF level, that is the cosine of the largest
          # passable angle, or the minimum cosine for a within-CDF sample.
          dotprod_thresh = np.percentile(
              dotprods, 100 * survival_rate, axis=0, keepdims=True
          )
          # We mask this sum because it is possible for the log_prob to be -inf when
          # the mean_direction is -mean_dir.
          importance_masked = np.ma.array(
              importance, mask=dotprods <= dotprod_thresh
          )
          sphere_cap_surface_area_ests = (
              cdf
              * (importance_masked).sum(0)
              / (dotprods > dotprod_thresh).sum(0)
          )
          h = 1 - dotprod_thresh
          self.assertGreaterEqual(
              h.min(), 0
          )  # h must be >= 0 for the eqn below
          true_sphere_cap_surface_area = (
              0.5
              * true_sphere_surface_area
              * self.evaluate(
                  tf.math.betainc((dim - 1) / 2, 0.5, 2 * h - h**2)
              )
          )
          if (
              dim == 3
          ):  # For 3-d we have a simpler form we can double-check.
              self.assertAllClose(
                  2 * np.pi * h, true_sphere_cap_surface_area
              )
  
          self.assertAllClose(
              true_sphere_cap_surface_area,
              sphere_cap_surface_area_ests
              + np.zeros_like(true_sphere_cap_surface_area),
              rtol=rtol,
          )
  
imports: import numpy
  from scipy import special
  import tensorflow.compat.v2
  from tensorflow_probability.python.distributions import kullback_leibler
  from tensorflow_probability.python.distributions import power_spherical
  from tensorflow_probability.python.distributions import spherical_uniform
  from tensorflow_probability.python.distributions import von_mises_fisher
  from tensorflow_probability.python.internal import dtype_util
  from tensorflow_probability.python.internal import tensorshape_util
  from tensorflow_probability.python.internal import test_util
  from tensorflow_probability.python.stats import sample_stats
label_desc: Use image node_id 7 for calling the _PowerSphericalTest obj's underlying member method code with example usage: obj.VerifySampleAndPdfConsistency(pspherical, rtol) without return types