B
    `AC                 @   s   d 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dlmZ ddlmZ dgZdZG dd dejZdd Zdd Zdd Z dS )z#The Multinomial distribution class.    )absolute_import)division)print_function)v2)_numpy)binomial)categorical)distribution)assert_util)distribution_util)
dtype_util)prefer_static)reparameterization)samplers)tensor_util)tensorshape_utilMultinomiala  For each batch of counts, `value = [n_0, ...
,n_{k-1}]`, `P[value]` is the probability that after sampling `self.total_count`
draws from this Multinomial distribution, the number of draws falling in class
`j` is `n_j`. Since this definition is [exchangeable](
https://en.wikipedia.org/wiki/Exchangeable_random_variables); different
sequences have the same counts so the probability includes a combinatorial
coefficient.

Note: `value` must be a non-negative tensor with dtype `self.dtype`, have no
fractional components, and such that
`tf.reduce_sum(value, -1) = self.total_count`. Its shape must be broadcastable
with `self.probs` and `self.total_count`.c                   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
dd Zdd Zdd Zdd Zd0ddZeedd Zdd Zdd Zdd  Zd1d!d"Zd#d$ Zd2d%d&Zd'd( Zd)d* Zd+d, Zd-d. Z  ZS )3r   a4
  Multinomial distribution.

  This Multinomial distribution is parameterized by `probs`, a (batch of)
  length-`K` `prob` (probability) vectors (`K > 1`) such that
  `tf.reduce_sum(probs, -1) = 1`, and a `total_count` number of trials, i.e.,
  the number of trials per draw from the Multinomial. It is defined over a
  (batch of) length-`K` vector `counts` such that
  `tf.reduce_sum(counts, -1) = total_count`. The Multinomial is identically the
  Binomial distribution when `K = 2`.

  #### Mathematical Details

  The Multinomial is a distribution over `K`-class counts, i.e., a length-`K`
  vector of non-negative integer `counts = n = [n_0, ..., n_{K-1}]`.

  The probability mass function (pmf) is,

  ```none
  pmf(n; pi, N) = prod_j (pi_j)**n_j / Z
  Z = (prod_j n_j!) / N!
  ```

  where:
  * `probs = pi = [pi_0, ..., pi_{K-1}]`, `pi_j > 0`, `sum_j pi_j = 1`,
  * `total_count = N`, `N` a positive integer,
  * `Z` is the normalization constant, and,
  * `N!` denotes `N` factorial.

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

  #### Pitfalls

  The number of classes, `K`, must not exceed:

  - the largest integer representable by `self.dtype`, i.e.,
    `2**(mantissa_bits+1)` (IEE754),
  - the maximum `Tensor` index, i.e., `2**31-1`.

  In other words,

  ```python
  K <= min(2**31-1, {
    tf.float16: 2**11,
    tf.float32: 2**24,
    tf.float64: 2**53 }[param.dtype])
  ```

  Note: This condition is validated only when `self.validate_args = True`.

  #### Examples

  Create a 3-class distribution, with the 3rd class is most likely to be drawn,
  using logits.

  ```python
  logits = [-50., -43, 0]
  dist = Multinomial(total_count=4., logits=logits)
  ```

  Create a 3-class distribution, with the 3rd class is most likely to be drawn.

  ```python
  p = [.2, .3, .5]
  dist = Multinomial(total_count=4., probs=p)
  ```

  The distribution functions can be evaluated on counts.

  ```python
  # counts same shape as p.
  counts = [1., 0, 3]
  dist.prob(counts)  # Shape []

  # p will be broadcast to [[.2, .3, .5], [.2, .3, .5]] to match counts.
  counts = [[1., 2, 1], [2, 2, 0]]
  dist.prob(counts)  # Shape [2]

  # p will be broadcast to shape [5, 7, 3] to match counts.
  counts = [[...]]  # Shape [5, 7, 3]
  dist.prob(counts)  # Shape [5, 7]
  ```

  Create a 2-batch of 3-class distributions.

  ```python
  p = [[.1, .2, .7], [.3, .3, .4]]  # Shape [2, 3]
  dist = Multinomial(total_count=[4., 5], probs=p)

  counts = [[2., 1, 1], [3, 1, 1]]
  dist.prob(counts)  # Shape [2]

  dist.sample(5) # Shape [5, 2, 3]
  ```
  NFTc       	   	      s   t t }|dk|dkkr"tdt|p}tj|||gtjd}tj	|d|d| _
tj	||dd| _tj	||dd| _tt| j|tj||||d	 W dQ R X dS )
a  Initialize a batch of Multinomial distributions.

    Args:
      total_count: Non-negative floating point tensor with shape broadcastable
        to `[N1,..., Nm]` with `m >= 0`. Defines this as a batch of
        `N1 x ... x Nm` different Multinomial distributions. Its components
        should be equal to integer values.
      logits: Floating point tensor representing unnormalized log-probabilities
        of a positive event with shape broadcastable to
        `[N1,..., Nm, K]` `m >= 0`, and the same dtype as `total_count`. Defines
        this as a batch of `N1 x ... x Nm` different `K` class Multinomial
        distributions. Only one of `logits` or `probs` should be passed in.
      probs: Positive floating point tensor with shape broadcastable to
        `[N1,..., Nm, K]` `m >= 0` and same dtype as `total_count`. Defines
        this as a batch of `N1 x ... x Nm` different `K` class Multinomial
        distributions. `probs`'s components in the last portion of its shape
        should sum to `1`. Only one of `logits` or `probs` should be passed in.
      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.
    Nz(Must pass probs or logits, but not both.)Z
dtype_hinttotal_count)namedtypeprobs)r   r   logits)r   Zreparameterization_typevalidate_argsallow_nan_stats
parametersr   )dictlocals
ValueErrortf
name_scoper   Zcommon_dtypefloat32r   Zconvert_nonref_to_tensor_total_count_probs_logitssuperr   __init__r   ZNOT_REPARAMETERIZED)	selfr   r   r   r   r   r   r   r   )	__class__ m/home/dcms/DCMS/lib/python3.7/site-packages/tensorflow_probability/python/distributions/_numpy/multinomial.pyr%      s&    "


zMultinomial.__init__c             C   s   t ddddS )Nr      )r   r   r   )r   )clsr(   r(   r)   _params_event_ndims   s    zMultinomial._params_event_ndimsc             C   s   | j S )z,Number of trials used to construct a sample.)r!   )r&   r(   r(   r)   r      s    zMultinomial.total_countc             C   s   | j S )zInput argument `logits`.)r#   )r&   r(   r(   r)   r      s    zMultinomial.logitsc             C   s   | j S )zInput argument `probs`.)r"   )r&   r(   r(   r)   r      s    zMultinomial.probsc             C   s4   t t | jd kr| jn| jd d t | jS )N)r   Zbroadcast_dynamic_shapeshaper#   r"   r   )r&   r(   r(   r)   _batch_shape_tensor   s    "zMultinomial._batch_shape_tensorc             C   s,   t | jd kr| jn| jjd d | jjS )Nr-   )r   Zbroadcast_static_shaper#   r"   r.   r   )r&   r(   r(   r)   _batch_shape   s    zMultinomial._batch_shapec             C   s$   t | jd kr| jn| jdd  S )Nr-   )r   r.   r#   r"   )r&   r(   r(   r)   _event_shape_tensor   s    zMultinomial._event_shape_tensorc             C   s*   t j| jd kr| jn| jjdd  ddS )Nr-   r*   )Zrank)r   Z	with_rankr#   r"   r.   )r&   r(   r(   r)   _event_shape   s    zMultinomial._event_shapec             C   sV   t j| jt jd}|  }t j|jd }|d krBt |d }t||||| j	|S )N)r   r-   )
r   castr   int32_probs_parameter_no_checkscompatZdimension_valuer.   (_sample_multinomial_as_iterated_binomialr   )r&   nseedZn_drawsr   kr(   r(   r)   	_sample_n   s    zMultinomial._sample_nc             C   sT   | j d krtj| jntj| j }tjtj||dd}t	| j
|}|| S )Nr-   )axis)r#   r   mathlogr"   Zlog_softmax
reduce_sumZmultiply_no_nantfp_mathZlog_combinationsr   )r&   countsZlog_pZlog_unnorm_probZneg_log_normalizerr(   r(   r)   	_log_prob   s
    &zMultinomial._log_probc             C   s&   |   }t| j}|dtjf | S )N.)r5   r   convert_to_tensorr   newaxis)r&   pr:   r(   r(   r)   _mean
  s    zMultinomial._meanc          	   C   sp   |   }t| j}tj|dtjtjf  |dd d tjf |dtjd d f   |dtjf | d|  S )N.g      ?)r5   r   rC   r   ZlinalgZset_diagrD   )r&   rE   r:   r(   r(   r)   _covariance  s    (zMultinomial._covariancec             C   s.   |   }t| j}|dtjf | d|  S )N.g      ?)r5   r   rC   r   rD   )r&   rE   r:   r(   r(   r)   	_variance  s    zMultinomial._variancec          	   C   s"   |  |p
d
 |  S Q R X dS )zDLogits vec computed from non-`None` input arg (`probs` or `logits`).logits_parameterN)_name_and_control_scope_logits_parameter_no_checks)r&   r   r(   r(   r)   rI     s    zMultinomial.logits_parameterc             C   s$   | j d krtj| jS t| j S )N)r#   r   r=   r>   r"   identity)r&   r(   r(   r)   rK   !  s    
z'Multinomial._logits_parameter_no_checksc          	   C   s"   |  |p
d
 |  S Q R X dS )zCProbs vec computed from non-`None` input arg (`probs` or `logits`).probs_parameterN)rJ   r5   )r&   r   r(   r(   r)   rM   &  s    zMultinomial.probs_parameterc             C   s$   | j d krt| jS tj| j S )N)r#   r   rL   r"   r=   softmax)r&   r(   r(   r)   r5   +  s    
z&Multinomial._probs_parameter_no_checksc             C   s   d S )Nr(   )r&   r(   r(   r)   _default_event_space_bijector0  s    z)Multinomial._default_event_space_bijectorc             C   sD   g }| j s|S |t| |tj| jtj	|dddd |S )zBCheck counts for proper shape, values, then return tensor version.r-   )r<   z%counts must sum to `self.total_count`)message)
r   extendr   assert_nonnegative_integer_formappendr
   Zassert_equalr   r   r?   )r&   rA   
assertionsr(   r(   r)   _sample_control_dependencies3  s    
z(Multinomial._sample_control_dependenciesc             C   sF   t || j| j| j}| js |S |t| jkrB|t	
| j |S )N)categorical_libZ*maybe_assert_categorical_param_correctnessr   r"   r#   r   Zis_refr   rQ   r   rR   )r&   Zis_initrT   r(   r(   r)   _parameter_control_dependencies?  s    
z+Multinomial._parameter_control_dependencies)NNFTr   )N)N)N)__name__
__module____qualname____doc__r%   classmethodr,   propertyr   r   r   r/   r0   r1   r2   r;   r   ZAppendDocstring_multinomial_sample_noterB   rF   rG   rH   rI   rK   rM   r5   rO   rU   rW   __classcell__r(   r(   )r'   r)   r   8   s4   _    1
	


c             C   s   t j|}t| |||||S )a  Sample a multinomial.

  The batch shape is given by broadcasting num_trials with
  remove_last_dimension(logits).

  Args:
    num_samples: Python int or singleton integer Tensor: number of multinomial
      samples to draw.
    num_classes: Python int or singleton integer Tensor: number of classes.
    logits: Floating Tensor with last dimension `num_classes`, of (unnormalized)
      logit probabilities per class.
    num_trials: Tensor of number of categorical trials each multinomial consists
      of.  num_trials[..., tf.newaxis] must broadcast with logits.
    dtype: dtype at which to emit samples.
    seed: Random seed.

  Returns:
    samples: Tensor of given dtype and shape [num_samples] + batch_shape +
      [num_classes].
  )r   r=   rN   r7   )num_samplesnum_classesr   
num_trialsr   r9   r   r(   r(   r)   draw_sampleJ  s    rc   c          	      s   t d tj|t dd fdd}t |j}|t d 7 }t|| }t 	d}t d }t j
 |jd}	t jfd	d
|||||	fd\}
}}
}	|	d t j| d}	t |	 }t|ddS Q R X dS )aO  Sample a multinomial by drawing one binomial sample per class.

  The batch shape is given by broadcasting num_trials with
  remove_last_dimension(probs).

  The loop over binomial samples is a `tf.while_loop`, thus supporting a dynamic
  number of classes.

  Args:
    num_samples: Singleton integer Tensor: number of multinomial samples to
      draw.
    num_classes: Singleton integer Tensor: number of classes.
    probs: Floating Tensor with last dimension `num_classes`, of normalized
      probabilities per class.
    num_trials: Tensor of number of categorical trials each multinomial consists
      of.  num_trials[..., tf.newaxis] must broadcast with probs.
    dtype: dtype at which to emit samples.
    seed: Random seed.

  Returns:
    samples: Tensor of given dtype and shape [num_samples] + batch_shape +
      [num_classes].
  rc   Zmultinomial_draw_sample)r8   Zsaltc       	         s~   t j| dd}t |d|  dd}t j| dd}tj||d}|j|d}|| t j| d}| d || || |fS )	z/Sample the counts for one class using binomial.r-   )r<   g      ?r   r*   )r   r   )r9   )r   )r   ZgatherZclip_by_valuer   ZBinomialsamplewriter3   )	irb   consumed_probaccumZ
probs_hereZbinomial_probsZ	seed_hereZbinomrd   )r   r   seedsr(   r)   fn  s    z4_sample_multinomial_as_iterated_binomial.<locals>.fn).r   r   )sizeZelement_shapec                s   t |  d S )Nr*   )r   Zless)indexZ_0Z_1Z_2)ra   r(   r)   <lambda>      z:_sample_multinomial_as_iterated_binomial.<locals>.<lambda>)ZcondbodyZ	loop_varsr*   )r   r-   N)r   r   r   Z
split_seedrC   r3   r   Z
zeros_like_replicate_along_leftZconstantZTensorArrayr.   Z
while_loopre   Zstop_gradientstackr   Zmove_dimension)r`   ra   r   rb   r   r9   rj   rf   rg   rh   _Znum_trials_leftresultsr(   )r   ra   r   ri   r)   r7   d  s&    



r7   c             C   s0   t j|gt | gdd}t| tjdf |S )aI  Replicates `tensor` `count` times along a new leading axis.

  In other words, returns a Tensor of shape '[count] + tensor.shape`, with
  `count` copies of `tensor`.

  Args:
    tensor: Tensor to replicate.
    count: A scalar integer Tensor giving the number of times to replicate.

  Returns:
    result: Replicated Tensor.
  r   )r<   .)r   concatr.   r   Zbroadcast_torD   )ZtensorcountZdesired_shaper(   r(   r)   rp     s    rp   N)!r[   
__future__r   r   r   Z;tensorflow_probability.python.internal.backend.numpy.compatr   r   Z"tensorflow_probability.python.mathr   r@   Z2tensorflow_probability.python.distributions._numpyr   r   rV   r	   Z-tensorflow_probability.python.internal._numpyr
   r   r   r   Z&tensorflow_probability.python.internalr   r   r   r   __all__r^   Distributionr   rc   r7   rp   r(   r(   r(   r)   <module>   s0     E