B
    `?                 @   s   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gZdZG dd dejZeeedddZdS )z!The Dirichlet distribution class.    )absolute_import)division)print_functionN)v2)softmax_centered)distribution)kullback_leibler)assert_util)distribution_util)
dtype_util)reparameterization)samplers)tensor_util)tensorshape_util	DirichletzNote: `value` must be a non-negative tensor with
dtype `self.dtype` and be in the `(self.event_shape() - 1)`-simplex, i.e.,
`tf.reduce_sum(value, -1) = 1`. It must have a shape compatible with
`self.batch_shape() + self.event_shape()`.c                   s   e Zd ZdZd* fdd	Zedd Zedd	 Zd
d Z	dd Z
dd Zdd Zd+ddZeedd Zee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 ),r   a:  Dirichlet distribution.

  The Dirichlet distribution is defined over the
  [`(k-1)`-simplex](https://en.wikipedia.org/wiki/Simplex) using a positive,
  length-`k` vector `concentration` (`k > 1`). The Dirichlet is identically the
  Beta distribution when `k = 2`.

  #### Mathematical Details

  The Dirichlet is a distribution over the open `(k-1)`-simplex, i.e.,

  ```none
  S^{k-1} = { (x_0, ..., x_{k-1}) in R^k : sum_j x_j = 1 and all_j x_j > 0 }.
  ```

  The probability density function (pdf) is,

  ```none
  pdf(x; alpha) = prod_j x_j**(alpha_j - 1) / Z
  Z = prod_j Gamma(alpha_j) / Gamma(sum_j alpha_j)
  ```

  where:

  * `x in S^{k-1}`, i.e., the `(k-1)`-simplex,
  * `concentration = alpha = [alpha_0, ..., alpha_{k-1}]`, `alpha_j > 0`,
  * `Z` is the normalization constant aka the [multivariate beta function](
    https://en.wikipedia.org/wiki/Beta_function#Multivariate_beta_function),
    and,
  * `Gamma` is the [gamma function](
    https://en.wikipedia.org/wiki/Gamma_function).

  The `concentration` represents mean total counts of class occurrence, i.e.,

  ```none
  concentration = alpha = mean * total_concentration
  ```

  where `mean` in `S^{k-1}` and `total_concentration` is a positive real number
  representing a mean total count.

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

  Warning: Some components of the samples can be zero due to finite precision.
  This happens more often when some of the concentrations are very small.
  Make sure to round the samples to `np.finfo(dtype).tiny` before computing the
  density.

  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

  # Create a single trivariate Dirichlet, with the 3rd class being three times
  # more frequent than the first. I.e., batch_shape=[], event_shape=[3].
  alpha = [1., 2, 3]
  dist = tfd.Dirichlet(alpha)

  dist.sample([4, 5])  # shape: [4, 5, 3]

  # x has one sample, one batch, three classes:
  x = [.2, .3, .5]   # shape: [3]
  dist.prob(x)       # shape: []

  # x has two samples from one batch:
  x = [[.1, .4, .5],
       [.2, .3, .5]]
  dist.prob(x)         # shape: [2]

  # alpha will be broadcast to shape [5, 7, 3] to match x.
  x = [[...]]   # shape: [5, 7, 3]
  dist.prob(x)  # shape: [5, 7]
  ```

  ```python
  # Create batch_shape=[2], event_shape=[3]:
  alpha = [[1., 2, 3],
           [4, 5, 6]]   # shape: [2, 3]
  dist = tfd.Dirichlet(alpha)

  dist.sample([4, 5])  # shape: [4, 5, 2, 3]

  x = [.2, .3, .5]
  # x will be broadcast as [[.2, .3, .5],
  #                         [.2, .3, .5]],
  # thus matching batch_shape [2, 3].
  dist.prob(x)         # shape: [2]
  ```

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

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

  FTc          	      sj   t t }t|L}tj|gtjd}tj||dd| _	t
t| j| j	j||tj||d W dQ R X dS )a  Initialize a batch of Dirichlet distributions.

    Args:
      concentration: Positive floating-point `Tensor` indicating mean number
        of class occurrences; aka "alpha". Implies `self.dtype`, and
        `self.batch_shape`, `self.event_shape`, i.e., if
        `concentration.shape = [N1, N2, ..., Nm, k]` then
        `batch_shape = [N1, N2, ..., Nm]` and
        `event_shape = [k]`.
      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.
    )Z
dtype_hintconcentration)dtypename)r   validate_argsallow_nan_statsZreparameterization_type
parametersr   N)dictlocalstf
name_scoper   Zcommon_dtypefloat32r   Zconvert_nonref_to_tensor_concentrationsuperr   __init__r   r   ZFULLY_REPARAMETERIZED)selfr   r   r   r   r   r   )	__class__ k/home/dcms/DCMS/lib/python3.7/site-packages/tensorflow_probability/python/distributions/_numpy/dirichlet.pyr      s    

zDirichlet.__init__c             C   s
   t ddS )N   )r   )r   )clsr!   r!   r"   _params_event_ndims   s    zDirichlet._params_event_ndimsc             C   s   | j S )z=Concentration parameter; expected counts for that coordinate.)r   )r   r!   r!   r"   r      s    zDirichlet.concentrationc             C   s   t | j}t |d d S )N)r   convert_to_tensorr   shape)r   r   r!   r!   r"   _batch_shape_tensor   s    zDirichlet._batch_shape_tensorc             C   s   | j jd d S )Nr&   )r   r(   )r   r!   r!   r"   _batch_shape   s    zDirichlet._batch_shapec             C   s   t | j}t |dd  S )Nr&   )r   r'   r   r(   )r   r   r!   r!   r"   _event_shape_tensor   s    zDirichlet._event_shape_tensorc             C   s   t j| jjdd  ddS )Nr&   r#   )rank)r   Z	with_rankr   r(   )r   r!   r!   r"   _event_shape   s    zDirichlet._event_shapeNc             C   s,   t j|g| j| j|d}|tj|ddd S )N)r(   alphar   seedr&   T)axiskeepdims)r   gammar   r   r   
reduce_sum)r   nr/   Zgamma_sampler!   r!   r"   	_sample_n   s    zDirichlet._sample_nc             C   s4   t | j}t jt j|d |ddt j| S )Ng      ?r&   )r0   )r   r'   r   r3   mathZxlogylbeta)r   xr   r!   r!   r"   	_log_prob   s    zDirichlet._log_probc             C   s   t | |S )N)r   expr9   )r   r8   r!   r!   r"   _prob   s    zDirichlet._probc             C   sp   t | j}t t |d | j}t j|dd}t j||| t j	|  t j|d t j	| dd S )Nr&   )r0   g      ?)
r   r'   r   castr(   r   r3   r6   r7   digamma)r   r   ktotal_concentrationr!   r!   r"   _entropy   s    zDirichlet._entropyc             C   s$   t | j}t j|ddd}|| S )Nr&   T)r0   r1   )r   r'   r   r3   )r   r   r?   r!   r!   r"   _mean   s    zDirichlet._meanc          
   C   sz   t | j}t j|ddd}|| }t jd| }|| }|||  }t jt |dt j	f  |dt j	d d f |S )Nr&   T)r0   r1   g      ?.)
r   r'   r   r3   r6   rsqrtZlinalgZset_diagmatmulnewaxis)r   r   r?   meanscaler8   Zvariancer!   r!   r"   _covariance   s    &zDirichlet._covariancec             C   sH   t | j}t j|ddd}|| }t jd| }|| }|||  S )Nr&   T)r0   r1   g      ?)r   r'   r   r3   r6   rB   )r   r   r?   rE   rF   r8   r!   r!   r"   	_variance  s    zDirichlet._variancezNote: The mode is undefined when any `concentration <= 1`. If
      `self.allow_nan_stats` is `True`, `NaN` is used for undefined modes. If
      `self.allow_nan_stats` is `False` an exception is raised when one or more
      modes are undefined.c          	   C   s   t | j}t t |d | j}t j|dd}|d |dt jf |  }| jr~t 	t j
|dkddd|t| jtjS tjt g | j|ddg}t | t |S Q R X d S )	Nr&   )r0   g      ?.T)r0   r1   z*Mode undefined when any concentration <= 1)message)r   r'   r   r<   r(   r   r3   rD   r   whereZ
reduce_allr   Zas_numpy_dtypenpnanr	   assert_lessonesZcontrol_dependenciesidentity)r   r   r>   r?   mode
assertionsr!   r!   r"   _mode  s    
zDirichlet._modec             C   s   t j| jdS )N)r   )softmax_centered_bijectorZSoftmaxCenteredr   )r   r!   r!   r"   _default_event_space_bijector'  s    z'Dirichlet._default_event_space_bijectorc             C   sR   g }| j s|S |tj|dd |tjtjg | jdtj|dddd |S )z Checks the validity of a sample.zSamples must be non-negative.)rI   )r   r&   )r0   z&Sample last-dimension must sum to `1`.)	r   appendr	   Zassert_non_negativeZassert_nearr   rN   r   r3   )r   r8   rQ   r!   r!   r"   _sample_control_dependencies,  s    
z&Dirichlet._sample_control_dependenciesc             C   s   g }|rt | jjstdd}t| jj}|dk	rJ|dk rht|n| j	rh|
tj| jd|d d}tj| jjd }|dk	r|dk rt|n(| j	r|
tjdt| jd |d | j	s|rtg S |t| jkr|
tj| jd	d |S )
z3Checks the validity of the concentration parameter.z,Argument `concentration` must be float type.z3Argument `concentration` must have rank at least 1.Nr#   )rI   z;Argument `concentration` must have `event_size` at least 2.r&      z*Argument `concentration` must be positive.)r   Zis_floatingr   r   	TypeErrorr   r,   r(   
ValueErrorr   rU   r	   Zassert_rank_at_leastr   compatZdimension_valuerM   AssertionErrorr   Zis_refZassert_positive)r   Zis_initrQ   msgZndimsZ
event_sizer!   r!   r"   _parameter_control_dependencies9  s<    



z)Dirichlet._parameter_control_dependencies)FTr   )N)__name__
__module____qualname____doc__r   classmethodr%   propertyr   r)   r*   r+   r-   r5   r
   ZAppendDocstring_dirichlet_sample_noter9   r;   r@   rA   rG   rH   rR   rT   rV   r]   __classcell__r!   r!   )r    r"   r   0   s,   m  !
	c          	   C   s   t |p
dt t | j}t |j}t jt j|ddd}t j|| }|| }t j|| ddt j| t j| S Q R X dS )a^  Batchwise KL divergence KL(d1 || d2) with d1 and d2 Dirichlet.

  Args:
    d1: instance of a Dirichlet distribution object.
    d2: instance of a Dirichlet distribution object.
    name: Python `str` name to use for created operations.
      Default value: `None` (i.e., `'kl_dirichlet_dirichlet'`).

  Returns:
    kl_div: Batchwise KL(d1 || d2)
  Zkl_dirichlet_dirichletr&   T)r0   r1   )r0   N)r   r   r'   r   r6   r=   r3   r7   )d1Zd2r   Zconcentration1Zconcentration2Zdigamma_sum_d1Zdigamma_diffZconcentration_diffr!   r!   r"   _kl_dirichlet_dirichletc  s    5rg   )N)ra   
__future__r   r   r   numpyrK   Z;tensorflow_probability.python.internal.backend.numpy.compatr   r   Z.tensorflow_probability.python.bijectors._numpyr   rS   Z2tensorflow_probability.python.distributions._numpyr   r   Z-tensorflow_probability.python.internal._numpyr	   r
   r   Z&tensorflow_probability.python.internalr   r   r   r   __all__rd   Distributionr   Z
RegisterKLrg   r!   r!   r!   r"   <module>   s,     5
