def _log_cdf(self, x): loc, scale, low, high = self._loc_scale_low_high() std_low, std_high = self._standardized_low_and_high( low=low, high=high, loc=loc, scale=scale) return (_log_sub_exp( special_math.log_ndtr( (x - loc) / scale), special_math.log_ndtr(std_low)) - self._log_normalizer(std_low=std_low, std_high=std_high))
def _mean(self): loc, scale, low, high = self._loc_scale_low_high() std_low, std_high = self._standardized_low_and_high( loc=loc, scale=scale, low=low, high=high) lse, sign = _log_sub_exp(_normal_log_pdf(std_low), _normal_log_pdf(std_high), return_sign=True) return loc + scale * sign * tf.math.exp( lse - self._log_normalizer(std_low=std_low, std_high=std_high))
def _normal_cdf_log_difference(x, y): """Computes log(ndtr(x) - ndtr(y)) assuming that x >= y.""" # When x >= y >= 0, we will return log(ndtr(-y) - ndtr(-x)) # because ndtr does not have a good precision for large positive x, y. is_y_positive = y >= 0 x_hat = tf.where(is_y_positive, -y, x) y_hat = tf.where(is_y_positive, -x, y) return _log_sub_exp(special_math.log_ndtr(x_hat), special_math.log_ndtr(y_hat))
def _log_normalizer(self, loc=None, scale=None, low=None, high=None, std_low=None, std_high=None): if std_low is None or std_high is None: std_low, std_high = self._standardized_low_and_high( loc=loc, scale=scale, low=low, high=high) return _log_sub_exp( special_math.log_ndtr(std_high), special_math.log_ndtr(std_low))
def _log_normalizer(self, loc=None, scale=None, low=None, high=None, std_low=None, std_high=None): if std_low is None or std_high is None: std_low, std_high = self._standardized_low_and_high(loc=loc, scale=scale, low=low, high=high) return _log_sub_exp(_log_cauchy_cdf(std_high), _log_cauchy_cdf(std_low))
def _variance(self): loc, scale, low, high = self._loc_scale_low_high() std_low, std_high = self._standardized_low_and_high( loc=loc, scale=scale, low=low, high=high) log_normalizer = self._log_normalizer(std_low=std_low, std_high=std_high) var = ( tf.square(scale) * (1. + (std_low * _normal_pdf(std_low) - std_high * _normal_pdf(std_high)) / tf.exp(log_normalizer) - tf.exp(2. * ( _log_sub_exp( # ignore sign because result gets squared _normal_log_pdf(std_low), _normal_log_pdf(std_high)) - log_normalizer)))) return var