class_docstr: Continuous Bernoulli distribution.
  
  This distribution is parameterized by `probs`, a (batch of) parameters
  taking values in `(0, 1)`. Note that, unlike in the Bernoulli case, `probs`
  does not correspond to a probability, but the same name is used due to the
  similarity with the Bernoulli.
  
  #### Mathematical Details
  
  The continuous Bernoulli is a distribution over the interval `[0, 1]`,
  parameterized by `probs` in `(0, 1)`.
  
  The probability density function (pdf) is,
  
  ```none
  pdf(x; probs) = probs**x * (1 - probs)**(1 - x) * C(probs)
  C(probs) = (2 * atanh(1 - 2 * probs) / (1 - 2 * probs) if probs != 0.5
              else 2.)
  ```
  
  While the normalizing constant `C(probs)` is a continuous function of `probs`
  (even at `probs = 0.5`), computing it at values close to 0.5 can result in
  numerical instabilities due to 0/0 errors. A Taylor approximation of
  `C(probs)` is thus used for values of `probs`
  in a small interval around 0.5.
  
  NOTE: Unlike the Bernoulli, numerical instabilities can happen for `probs`
  very close to 0 or 1. Current implementation allows any value in `(0, 1)`,
  but this could be changed to `(1e-6, 1-1e-6)` to avoid these issues.
  
  #### References
  
  [1] Loaiza-Ganem G and Cunningham JP. The continuous Bernoulli: fixing a
      pervasive error in variational autoencoders. NeurIPS2019.
      https://arxiv.org/abs/1907.06845
code: def _log_cdf(self, x):
      # The CDF is (p**x * (1 - p)**(1 - x) + p - 1) / (2 * p - 1).
      # We do this computation in logit space to be more numerically stable.
      # p**x * (1- p)**(1 - x) becomes
      # 1 / (1 + exp(-logits))**x *
      # exp(-logits * (1 - x)) / (1 + exp(-logits)) ** (1 - x) =
      # exp(-logits * (1 - x)) / (1 + exp(-logits))
      # p - 1 becomes -exp(-logits) / (1 + exp(-logits))
      # Thus the whole numerator is
      # (exp(-logits * (1 - x)) - exp(-logits)) / (1 + exp(-logits))
      # The denominator is (1 - exp(-logits)) / (1 + exp(-logits))
      # Putting it all together, this gives:
      # (exp(-logits * (1 - x)) - exp(-logits)) / (1 - exp(-logits)) =
      # (exp(logits * x) - 1) / (exp(logits) - 1)
      logits = self._logits_parameter_no_checks()
  
      # For logits < 0, we can directly use the expression.
      safe_logits = tf.where(logits < 0.0, logits, -1.0)
      result_negative_logits = generic.log1mexp(
          tf.math.multiply_no_nan(safe_logits, x)
      ) - generic.log1mexp(safe_logits)
      # For logits > 0, to avoid infs with large arguments we rewrite the
      # expression. Let z = log(exp(logits) - 1)
      # log_cdf = log((exp(logits * x) - 1) / (exp(logits) - 1))
      #         = log(exp(logits * x) - 1) - log(exp(logits) - 1)
      #         = log(exp(logits * x) - 1) - log(exp(z))
      #         = log(exp(logits * x - z) - exp(-z))
      # Because logits > 0, logits * x - z > -z, so we can pull it out to get
      #         = log(exp(logits * x - z) * (1 - exp(-logits * x)))
      #         = logits * x - z + tf.math.log(1 - exp(-logits * x))
      dtype = dtype_util.as_numpy_dtype(x.dtype)
      eps = np.finfo(dtype).eps
      # log(exp(logits) - 1)
      safe_logits = tf.where(logits > 0.0, logits, 1.0)
      z = tf.where(
          safe_logits > -np.log(eps),
          safe_logits,
          tf.math.log(tf.math.expm1(safe_logits)),
      )
      result_positive_logits = (
          tf.math.multiply_no_nan(safe_logits, x)
          - z
          + generic.log1mexp(-tf.math.multiply_no_nan(safe_logits, x))
      )
  
      result = tf.where(
          logits < 0.0,
          result_negative_logits,
          tf.where(
              logits > 0.0, result_positive_logits, tf.math.log(x)
          ),
      )
  
      # Finally, handle the case where `logits` and `p` are on the boundary,
      # as the above expressions can result in ratio of `infs` in that case as
      # well.
      result = tf.where(
          tf.math.equal(logits, np.inf), dtype(-np.inf), result
      )
      result = tf.where(
          (tf.math.equal(logits, -np.inf) & tf.math.not_equal(x, 0.0))
          | (tf.math.equal(logits, np.inf) & tf.math.equal(x, 1.0)),
          tf.zeros_like(logits),
          result,
      )
  
      result = tf.where(
          x < 0.0,
          dtype(-np.inf),
          tf.where(x > 1.0, tf.zeros_like(x), result),
      )
  
      return result
  
imports: import numpy
  import tensorflow.compat.v2
  from tensorflow_probability.python.bijectors import sigmoid
  from tensorflow_probability.python.distributions import distribution
  from tensorflow_probability.python.distributions import kullback_leibler
  from tensorflow_probability.python.internal import assert_util
  from tensorflow_probability.python.internal import dtype_util
  from tensorflow_probability.python.internal import parameter_properties
  from tensorflow_probability.python.internal import prefer_static
  from tensorflow_probability.python.internal import reparameterization
  from tensorflow_probability.python.internal import samplers
  from tensorflow_probability.python.internal import tensor_util
  from tensorflow_probability.python.math import generic
label_desc: Use image node_id 10 for calling the ContinuousBernoulli obj's underlying member method code with example usage: obj._log_cdf(x) and returns: result