B
    `P                 @   sD  d Z ddlmZ ddlmZ ddlmZ ddlZddlmZ	 ddl
mZ ddlmZ dd	lmZ dd
lmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ dgZG dd dejZe eed"ddZ!d#ddZ"d$ddZ#e	j$ddd%ddZ%e	j&dfd d!Z'dS )&zThe Gamma distribution class.    )absolute_import)division)print_functionN)v2)softplus)distribution)kullback_leibler)assert_util)batched_rejection_sampler)distribution_util)
dtype_util)implementation_selection)prefer_static)reparameterization)samplers)tensor_util)tensorshape_utilGammac                   s   e Zd ZdZd/ fdd	Zedd Zedd	 Ze	d
d Z
e	dd Zd0ddZdd Zdd Zdd Zedd1ddZd2ddZdd Zdd Zd d! Zd"d# Zd$d% Zed&d'd( Zd)d* Zd+d, Zd-d. Z  ZS )3r   ab	  Gamma distribution.

  The Gamma distribution is defined over positive real numbers using
  parameters `concentration` (aka "alpha") and `rate` (aka "beta").

  #### Mathematical Details

  The probability density function (pdf) is,

  ```none
  pdf(x; alpha, beta, x > 0) = x**(alpha - 1) exp(-x beta) / Z
  Z = Gamma(alpha) beta**(-alpha)
  ```

  where:

  * `concentration = alpha`, `alpha > 0`,
  * `rate = beta`, `beta > 0`,
  * `Z` is the normalizing constant, and,
  * `Gamma` is the [gamma function](
    https://en.wikipedia.org/wiki/Gamma_function).

  The cumulative density function (cdf) is,

  ```none
  cdf(x; alpha, beta, x > 0) = GammaInc(alpha, beta x) / Gamma(alpha)
  ```

  where `GammaInc` is the [lower incomplete Gamma function](
  https://en.wikipedia.org/wiki/Incomplete_gamma_function).

  The parameters can be intuited via their relationship to mean and stddev,

  ```none
  concentration = alpha = (mean / stddev)**2
  rate = beta = mean / stddev**2 = concentration / mean
  ```

  Distribution parameters are automatically broadcast in all functions; see
  examples for details.

  Warning: The samples of this distribution are always non-negative. However,
  the samples that are smaller than `np.finfo(dtype).tiny` are rounded
  to this value, so it appears more often than it should.
  This should only be noticeable when the `concentration` is very small, or the
  `rate` is very large. See note in `tf.random.gamma` docstring.

  Samples of this distribution are reparameterized (pathwise differentiable).
  The derivatives are computed using the approach described in the paper

  [Michael Figurnov, Shakir Mohamed, Andriy Mnih.
  Implicit Reparameterization Gradients, 2018](https://arxiv.org/abs/1805.08498)

  #### Examples

  ```python
  import tensorflow_probability as tfp; tfp = tfp.experimental.substrates.numpy
  tfd = tfp.distributions

  dist = tfd.Gamma(concentration=3.0, rate=2.0)
  dist2 = tfd.Gamma(concentration=[3.0, 4.0], rate=[2.0, 3.0])
  ```

  Compute the gradients of samples w.r.t. the parameters:

  ```python
  concentration = tf.constant(3.0)
  rate = tf.constant(2.0)
  dist = tfd.Gamma(concentration, rate)
  samples = dist.sample(5)  # Shape [5]
  loss = tf.reduce_mean(tf.square(samples))  # Arbitrary loss function
  # Unbiased stochastic gradients of the loss function
  grads = tf.gradients(loss, [concentration, rate])
  ```

  FTc          	      sz   t t }t|\}tj||gtjd}tj||dd| _	tj||dd| _
tt| j|||tj||d W dQ R X dS )a  Construct Gamma with `concentration` and `rate` parameters.

    The parameters `concentration` and `rate` must be shaped in a way that
    supports broadcasting (e.g. `concentration + rate` is a valid operation).

    Args:
      concentration: Floating point tensor, the concentration params of the
        distribution(s). Must contain only positive values.
      rate: Floating point tensor, the inverse scale params of the
        distribution(s). Must contain only positive values.
      validate_args: Python `bool`, default `False`. When `True` distribution
        parameters are checked for validity despite possibly degrading runtime
        performance. When `False` invalid inputs may silently render incorrect
        outputs.
      allow_nan_stats: Python `bool`, default `True`. When `True`, statistics
        (e.g., mean, mode, variance) use the value "`NaN`" to indicate the
        result is undefined. When `False`, an exception is raised if one or
        more of the statistic's batch members are undefined.
      name: Python `str` name prefixed to Ops created by this class.

    Raises:
      TypeError: if `concentration` and `rate` are different dtypes.
    )
dtype_hintconcentration)dtypenamerate)r   validate_argsallow_nan_statsZreparameterization_type
parametersr   N)dictlocalstf
name_scoper   common_dtypefloat32r   Zconvert_nonref_to_tensor_concentration_ratesuperr   __init__r   ZFULLY_REPARAMETERIZED)selfr   r   r   r   r   r   r   )	__class__ g/home/dcms/DCMS/lib/python3.7/site-packages/tensorflow_probability/python/distributions/_numpy/gamma.pyr%   z   s    

zGamma.__init__c             C   s    t tdtj| tjdgd S )N)r   r   )r      )r   zipr   convert_to_tensorint32)sample_shaper(   r(   r)   _param_shapes   s    zGamma._param_shapesc             C   s   t dddS )Nr   )r   r   )r   )clsr(   r(   r)   _params_event_ndims   s    zGamma._params_event_ndimsc             C   s   | j S )zConcentration parameter.)r"   )r&   r(   r(   r)   r      s    zGamma.concentrationc             C   s   | j S )zRate parameter.)r#   )r&   r(   r(   r)   r      s    z
Gamma.rateNc             C   s4   t t |d kr| jn|t |d kr,| jn|S )N)r   broadcast_shapeshaper   r   )r&   r   r   r(   r(   r)   _batch_shape_tensor   s    zGamma._batch_shape_tensorc             C   s   t | jj| jjS )N)r   Zbroadcast_static_shaper   r3   r   )r&   r(   r(   r)   _batch_shape   s    zGamma._batch_shapec             C   s   t jg t jdS )N)r   )r   constantr-   )r&   r(   r(   r)   _event_shape_tensor   s    zGamma._event_shape_tensorc             C   s
   t g S )N)r   ZTensorShape)r&   r(   r(   r)   _event_shape   s    zGamma._event_shapezMNote: See `tf.random.gamma` docstring for sampling details and
      caveats.c             C   sB   t j|dd}tt|gt| j| jt| j| j|dd S )Ngamma)salt)r3   r   r   seedr   )r   sanitize_seedrandom_gammar   r,   r   r   r   )r&   nr;   r(   r(   r)   	_sample_n   s
    
zGamma._sample_nc             C   sn   t |d kr| jn|}t |d kr*| jn|}t j|d |||  }t j||t j|  }|| S )Ng      ?)r   r,   r   r   mathZxlogylgammalog)r&   xr   r   Zlog_unnormalized_probZlog_normalizationr(   r(   r)   	_log_prob   s    
zGamma._log_probc             C   s   t j| j| j| S )N)r   r@   Zigammar   r   )r&   rC   r(   r(   r)   _cdf   s    z
Gamma._cdfc             C   s>   t | j}|t j| j t j| d| t j|  S )Ng      ?)r   r,   r   r@   rB   r   rA   digamma)r&   r   r(   r(   r)   _entropy   s    zGamma._entropyc             C   s   | j | j S )N)r   r   )r&   r(   r(   r)   _mean   s    zGamma._meanc             C   s   | j t| j S )N)r   r   Zsquarer   )r&   r(   r(   r)   	_variance   s    zGamma._variancec             C   s   t | j| j S )N)r   sqrtr   r   )r&   r(   r(   r)   _stddev   s    zGamma._stddevzThe mode of a gamma distribution is `(shape - 1) / rate` when
      `shape > 1`, and `NaN` otherwise. If `self.allow_nan_stats` is `False`,
      an exception will be raised rather than returning `NaN`.c          	   C   s   t | j}t | j}|d | }| jr0g }ntjt g | j|ddg}t 	|" t 
|dk|t| jtjS Q R X d S )Ng      ?z-Mode not defined when any concentration <= 1.)message)r   r,   r   r   r   r	   Zassert_lessZonesr   Zcontrol_dependencieswherer   as_numpy_dtypenpnan)r&   r   r   mode
assertionsr(   r(   r)   _mode   s    
zGamma._modec             C   s   t j| jdS )N)r   )softplus_bijectorZSoftplusr   )r&   r(   r(   r)   _default_event_space_bijector	  s    z#Gamma._default_event_space_bijectorc             C   s&   g }| j s|S |tj|dd |S )NzSample must be non-negative.)rL   )r   appendr	   Zassert_non_negative)r&   rC   rR   r(   r(   r)   _sample_control_dependencies  s    z"Gamma._sample_control_dependenciesc             C   s^   | j s
g S g }|t| jkr4|tj| jdd |t| jkrZ|tj| jdd |S )Nz*Argument `concentration` must be positive.)rL   z!Argument `rate` must be positive.)r   r   Zis_refr   rV   r	   Zassert_positiver   )r&   Zis_initrR   r(   r(   r)   _parameter_control_dependencies  s    

z%Gamma._parameter_control_dependencies)FTr   )NN)N)NN)__name__
__module____qualname____doc__r%   staticmethodr/   classmethodr1   propertyr   r   r4   r5   r7   r8   r   ZAppendDocstringr?   rD   rE   rG   rH   rI   rK   rS   rU   rW   rX   __classcell__r(   r(   )r'   r)   r   ,   s4   L  )

	c          	   C   s   t |p
d t | j}t | j}t |j}t |j}|| t j| t j| t j| |t j|  |t j|  ||| d   S Q R X dS )aq  Calculate the batched KL divergence KL(g0 || g1) with g0 and g1 Gamma.

  Args:
    g0: Instance of a `Gamma` distribution object.
    g1: Instance of a `Gamma` distribution object.
    name: Python `str` name to use for created operations.
      Default value: `None` (i.e., `'kl_gamma_gamma'`).

  Returns:
    kl_gamma_gamma: `Tensor`. The batchwise KL(g0 || g1).
  Zkl_gamma_gammag      ?N)	r   r   r,   r   r   r@   rF   rA   rB   )Zg0Zg1r   Zg0_concentrationZg0_rateZg1_concentrationZg1_rater(   r(   r)   _kl_gamma_gamma#  s    Lra   c       
      C   s   t j| tt |t |gdd}|dkt j|B }t |t	|j
d|}|dkt j|B }t |t	|j
d|}t jj|||||j
d}	t ||B t	|j
tj|	S )z0Sample using *fast* `tf.random.stateless_gamma`.r   )axisg        g      Y@)r3   r;   alphabetar   )r   concatr   r2   r3   r@   is_nanrM   r   rN   r   randomZstateless_gammarO   rP   )
r3   r   r   r;   Ztotal_shapeZbad_concentrationZclipped_concentrationZbad_rateZclipped_ratesamplesr(   r(   r)   _random_gamma_cpuB  s$    ri   c             C   s6   t j| tt |t |gdd} t| |||dS )z9Sample using XLA-friendly python-based rejection sampler.r   )rb   )r.   rc   rd   r;   )r   re   r   r2   r3   random_gamma_rejection)r3   r   r   r;   r(   r(   r)   _random_gamma_noncpu\  s    rk   F)Z	autographc                s:   t   tjtjddtj fdd}|||S )a  Sample a gamma, CPU specialized to stateless_gamma.

  Args:
    shape: Sample shape.
    concentration: Concentration of gamma distribution.
    rate: Rate parameter of gamma distribution.
    seed: int or Tensor seed.

  Returns:
    samples: Samples from gamma distributions.
  r3   )r   r   c                s:   t jdttd}| d fdd}|fS )Nr9   )fn_nameZ
default_fnZcpu_fn)r3   r   r   r;   c                s   t jj d  d }d   }t jj| | t t d}t jj| | t t d}t j	rtj	r j	j	kr||gS t jj
t 	 t 	d\}}t t jj||ddt 	 }t t jj||ddt 	}||gS )z7The gradient of the gamma samples w.r.t alpha and beta.r   )rc   sample)rb   )s0s1T)rb   Zkeepdims)r   Zraw_opsZRandomGammaGradr@   Z
reduce_sumrangesizer   Zis_fully_definedr3   ZBroadcastGradientArgsZreshape)Zdy_Zpartial_alphaZpartial_betaZgrad_aZgrad_brarb)r   r   rh   r3   r(   r)   grad  s(    z*random_gamma.<locals>.sample.<locals>.grad)r   Zimplementation_selectingrk   ri   )r   r   Zsampler_implru   )r;   r3   )r   r   rh   r)   rm     s    zrandom_gamma.<locals>.sample)r   r<   r   r,   r-   Zcustom_gradient)r3   r   r   r;   rm   r(   )r;   r3   r)   r=   k  s    
&r=   c       
         s   t j|dd\ tj||gtjd fdd}tt|t|}t	||}||}t
|dk|tj}	||	 S )a4  Samples from the gamma distribution.

  The sampling algorithm is rejection sampling [1], and pathwise gradients with
  respect to alpha are computed via implicit differentiation [2].

  Args:
    sample_shape: The output sample shape. Must broadcast with both
      `alpha` and `beta`.
    alpha: Floating point tensor, the alpha params of the
      distribution(s). Must contain only positive values. Must broadcast with
      `beta`.
    beta: Floating point tensor, the inverse scale params of the
      distribution(s). Must contain only positive values. Must broadcast with
      `alpha`.
    internal_dtype: dtype to use for internal computations.
    seed: (optional) The random seed.

  Returns:
    Differentiable samples from the gamma distribution.

  #### References

  [1] George Marsaglia and Wai Wan Tsang. A simple method for generating Gamma
      variables. ACM Transactions on Mathematical Software, 2000.

  [2] Michael Figurnov, Shakir Mohamed, and Andriy Mnih. Implicit
      Reparameterization Gradients. Neural Information Processing Systems, 2018.
  r=   )r:   )r   c          
      s  t | }| dk}t ||d}t |dk |d |}t jdd}|| |t    fdd}tj|dd	 }| }t jdd}t |dk t jt	j
d
|| |}	||	 }t ||tj}t |}
t |
d	ktt|
jj|
}
|
S )zGamma rejection sampler.g        g      Y@g      ?gUUUUUU?)r   c       	         s   t | \ } fdd}| \}}|| }|| | }t j|d}tj||d d| tj|   k }||fS )zGenerate and test samples.c                 s     fdd} t | d S )zGenerate positive v.c                s,   t j| d}d |  }||f|dkfS )N)r   r;      g        )r   normal)r;   rC   v)cinternal_dtyper.   r(   r)   _inner  s    zrandom_gamma_rejection.<locals>.rejection_sample.<locals>.generate_and_test_samples.<locals>.generate_positive_v.<locals>._innerr   )brsbatched_las_vegas_algorithm)r{   )ry   rz   r.   v_seedr(   r)   generate_positive_v  s    zprandom_gamma_rejection.<locals>.rejection_sample.<locals>.generate_and_test_samples.<locals>.generate_positive_v)r   r;   g       @rv   )r   
split_seeduniformr   r@   rB   )	r;   Zu_seedr   rC   rx   Zx2Zv3uZgood_sample_mask)ry   drz   r.   )r~   r)   generate_and_test_samples  s    
	,zSrandom_gamma_rejection.<locals>.rejection_sample.<locals>.generate_and_test_samples)r;   r   )r   r;   )r   castrM   r6   rJ   r|   r}   r@   powr   r   rO   rP   Zfinfor   rN   r   Ztiny)rc   Z
cast_alphaZgood_params_maskZ
safe_alphaZmodified_safe_alphaZ	one_thirdr   rh   ZoneZalpha_lt_one_fixZoutput_type_samples)alpha_fix_seedgenerate_and_test_samples_seedrz   output_dtyper.   )ry   r   r)   rejection_sample  s8    &
z0random_gamma_rejection.<locals>.rejection_sampleg        )r   r   r   r    r   r!   r   r2   r3   Zbroadcast_torM   rO   rP   )
r.   rc   rd   rz   r;   r   Zbroadcast_alpha_shapeZbroadcast_alphaZalpha_samplesZcorrected_betar(   )r   r   rz   r   r.   r)   rj     s    Srj   )N)N)N)N)(r\   
__future__r   r   r   numpyrO   Z;tensorflow_probability.python.internal.backend.numpy.compatr   r   Z.tensorflow_probability.python.bijectors._numpyr   rT   Z2tensorflow_probability.python.distributions._numpyr   r   Z-tensorflow_probability.python.internal._numpyr	   r
   r|   r   r   r   r   Z&tensorflow_probability.python.internalr   r   r   r   __all__Distributionr   Z
RegisterKLra   ri   rk   functionr=   float64rj   r(   r(   r(   r)   <module>   s8    x
"


9