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 G dd dejZeeedddZdS )z#The Independent distribution class.    )absolute_import)division)print_functionN)v2)distribution)kullback_leibler)assert_util)prefer_static)tensor_util)tensorshape_utilc                   s   e Zd ZdZd, fdd	Zedd Zedd	 Zd-d
dZ fddZ	dd Z
dd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zd d! Zd"d# Zd$d% Zd&d' Zd(d) Zd*d+ Z  ZS ).Independenta&	  Independent distribution from batch of distributions.

  This distribution is useful for regarding a collection of independent,
  non-identical distributions as a single random variable. For example, the
  `Independent` distribution composed of a collection of `Bernoulli`
  distributions might define a distribution over an image (where each
  `Bernoulli` is a distribution over each pixel).

  More precisely, a collection of `B` (independent) `E`-variate random variables
  (rv) `{X_1, ..., X_B}`, can be regarded as a `[B, E]`-variate random variable
  `(X_1, ..., X_B)` with probability
  `p(x_1, ..., x_B) = p_1(x_1) * ... * p_B(x_B)` where `p_b(X_b)` is the
  probability of the `b`-th rv. More generally `B, E` can be arbitrary shapes.

  Similarly, the `Independent` distribution specifies a distribution over `[B,
  E]`-shaped events. It operates by reinterpreting the rightmost batch dims as
  part of the event dimensions. The `reinterpreted_batch_ndims` parameter
  controls the number of batch dims which are absorbed as event dims;
  `reinterpreted_batch_ndims <= len(batch_shape)`.  For example, the `log_prob`
  function entails a `reduce_sum` over the rightmost `reinterpreted_batch_ndims`
  after calling the base distribution's `log_prob`.  In other words, since the
  batch dimension(s) index independent distributions, the resultant multivariate
  will have independent components.

  #### Mathematical Details

  The probability function is,

  ```none
  prob(x; reinterpreted_batch_ndims) = tf.reduce_prod(
      dist.prob(x),
      axis=-1-range(reinterpreted_batch_ndims))
  ```

  #### Examples

  ```python
  tfd = tfp.distributions

  # Make independent distribution from a 2-batch Normal.
  ind = tfd.Independent(
      distribution=tfd.Normal(loc=[-1., 1], scale=[0.1, 0.5]),
      reinterpreted_batch_ndims=1)

  # All batch dims have been 'absorbed' into event dims.
  ind.batch_shape  # ==> []
  ind.event_shape  # ==> [2]

  # Make independent distribution from a 2-batch bivariate Normal.
  ind = tfd.Independent(
      distribution=tfd.MultivariateNormalDiag(
          loc=[[-1., 1], [1, -1]],
          scale_identity_multiplier=[1., 0.5]),
      reinterpreted_batch_ndims=1)

  # All batch dims have been 'absorbed' into event dims.
  ind.batch_shape  # ==> []
  ind.event_shape  # ==> [2, 2]
  ```

  NFc          	      s   t t }t|pd|j }|| _|dkrxt|j}|dk	rjt	d|d | _
tj| j
tjdd| _qd| _d| _
n6tj|tjdd| _t| j}|dkrdnt|| _
tt| j| jj| jj|| jj||d W dQ R X dS )aU  Construct an `Independent` distribution.

    Args:
      distribution: The base distribution instance to transform. Typically an
        instance of `Distribution`.
      reinterpreted_batch_ndims: Scalar, integer number of rightmost batch dims
        which will be regarded as event dims. When `None` all but the first
        batch axis (batch axis 0) will be transferred to event dimensions
        (analogous to `tf.layers.flatten`).
      validate_args: Python `bool`.  Whether to validate input with asserts.
        If `validate_args` is `False`, and the inputs are invalid,
        correct behavior is not guaranteed.
      name: The name for ops managed by the distribution.
        Default value: `Independent + distribution.name`.

    Raises:
      ValueError: if `reinterpreted_batch_ndims` exceeds
        `distribution.batch_ndims`
    r   Nr      reinterpreted_batch_ndims)Z
dtype_hintname)dtypereparameterization_typevalidate_argsallow_nan_stats
parametersr   )dictlocalstfZ
name_scoper   _distributionr   rankbatch_shapemax!_static_reinterpreted_batch_ndimsconvert_to_tensorint32_reinterpreted_batch_ndimsr
   Zconvert_nonref_to_tensorZget_static_valueintsuperr   __init__r   r   r   )selfr   r   r   r   r   batch_ndimsZ
static_val)	__class__ m/home/dcms/DCMS/lib/python3.7/site-packages/tensorflow_probability/python/distributions/_numpy/independent.pyr"   `   s4    


zIndependent.__init__c             C   s   | j S )N)r   )r#   r&   r&   r'   r      s    zIndependent.distributionc             C   s   | j S )N)r   )r#   r&   r&   r'   r      s    z%Independent.reinterpreted_batch_ndimsc             C   sN   | j d k	r| j S | jd k	r&t| jS |d kr8| j }tdt|d S )Nr   r   )r   r   r   r   r   batch_shape_tensormaximumsize)r#   Zdistribution_batch_shape_tensorr&   r&   r'   _get_reinterpreted_batch_ndims   s    


z*Independent._get_reinterpreted_batch_ndimsc                s   t | tk	rtt| |S | jd kr.tdt|tjrBt	|n|f}t
|krZ|t
f }|td ft| j  }| j| j| | jdS )NzBCannot slice Independent with non-static reinterpreted_batch_ndims)r   r   )typer   r!   __getitem__r   NotImplementedError
isinstancecollectionsSequencetupleEllipsisslicer    copyr   )r#   Zslices)r%   r&   r'   r-      s    

zIndependent.__getitem__c             C   s0   | j  }t|| j j}|d || |  S )N)r   r(   r	   rank_from_shaper   r+   )r#   r   r$   r&   r&   r'   _batch_shape_tensor   s
    
zIndependent._batch_shape_tensorc             C   sF   | j j}| jd ks t|d kr*td S t|| j }|d | S )N)r   r   r   r   r   r   TensorShape)r#   r   dr&   r&   r'   _batch_shape   s    

zIndependent._batch_shapec             C   sf   | j j}t|s| j  }t|}| j j}t|sB| j  }tj	||| 
| d  |gddS )Nr   )axis)r   r   r   is_fully_definedr(   r	   r6   event_shapeevent_shape_tensorconcatr+   )r#   r   r$   r=   r&   r&   r'   _event_shape_tensor   s    




zIndependent._event_shape_tensorc             C   sj   | j j}| jd krtd S t|d k	rD|t|| j d  }ntd gt| j }t|| j j	S )N)
r   r   r   r   r8   r   r   r    Zconcatenater=   )r#   r   Zreinterpreted_batch_shaper&   r&   r'   _event_shape   s    

zIndependent._event_shapec             K   s   | j jf ||d|S )N)Zsample_shapeseed)r   sample)r#   nrB   kwargsr&   r&   r'   	_sample_n   s    zIndependent._sample_nc             K   s   |  tj| jj|f|S )N)_reducer   
reduce_sumr   Zlog_prob)r#   xrE   r&   r&   r'   	_log_prob   s    zIndependent._log_probc             K   s   |  tj| jj|f|S )N)rG   r   rH   r   Zlog_cdf)r#   rI   rE   r&   r&   r'   _log_cdf   s    zIndependent._log_cdfc             K   s   |  tj| jjf |S )N)rG   r   rH   r   Zentropy)r#   rE   r&   r&   r'   _entropy   s    zIndependent._entropyc             K   s   | j jf |S )N)r   Zmean)r#   rE   r&   r&   r'   _mean   s    zIndependent._meanc             K   s   | j jf |S )N)r   Zvariance)r#   rE   r&   r&   r'   	_variance  s    zIndependent._variancec             K   s   | j jf |S )N)r   stddev)r#   rE   r&   r&   r'   _stddev  s    zIndependent._stddevc             K   s   | j jf |S )N)r   mode)r#   rE   r&   r&   r'   _mode  s    zIndependent._modec             C   s
   | j  S )N)r   Z*_experimental_default_event_space_bijector)r#   r&   r&   r'   _default_event_space_bijector  s    z)Independent._default_event_space_bijectorc             C   s|   g }t | jj}|d k	rF| jd k	rF|rx| j|krxtd| j|n2| jrx| j }|	t
j| |t|dd |S )NzHreinterpreted_batch_ndims({}) cannot exceed distribution.batch_ndims({})z@reinterpreted_batch_ndims cannot exceed distribution.batch_ndims)message)r   r   r   r   r   
ValueErrorformatr   r(   appendr   Zassert_less_equalr+   r	   r6   )r#   Zis_initZ
assertionsr$   r(   r&   r&   r'   _parameter_control_dependencies  s     



z+Independent._parameter_control_dependenciesc             C   s    dt |   }||| dS )Nr   )r;   )r	   ranger+   )r#   opstatr;   r&   r&   r'   rG   $  s    zIndependent._reduce)NFN)N)__name__
__module____qualname____doc__r"   propertyr   r   r+   r-   r7   r:   r@   rA   rF   rJ   rK   rL   rM   rN   rP   rR   rS   rX   rG   __classcell__r&   r&   )r%   r'   r   !   s.   =  6

	r   kl_independentc          	   C   s.  | j }|j }t| jrt|jr| j|jkr|j|jkrt| jt|j }dd td|D }tjtj	|||d|dS t
dntdn| }| }|  }	| }
ttj|	|
ddtj||ddgH t|	| jt||j }t| dd	}tjtj	|||d|dS Q R X d
S )a  Batched KL divergence `KL(a || b)` for Independent distributions.

  We can leverage the fact that
  ```
  KL(Independent(a) || Independent(b)) = sum(KL(a || b))
  ```
  where the sum is over the `reinterpreted_batch_ndims`.

  Args:
    a: Instance of `Independent`.
    b: Instance of `Independent`.
    name: (optional) name to use for created ops. Default 'kl_independent'.

  Returns:
    Batchwise `KL(a || b)`.

  Raises:
    ValueError: If the event space for `a` and `b`, or their underlying
      distributions don't match.
  c             S   s   g | ]}| d  qS )r   r&   ).0ir&   r&   r'   
<listcomp>L  s    z#_kl_independent.<locals>.<listcomp>r   )r   )r;   zBKL between Independents with different event shapes not supported.zEvent shapes do not match.)rT   r   N)r   r   r<   r=   r   rY   r   rH   r   Zkl_divergencer.   rU   r>   Zcontrol_dependenciesr   Zassert_equalr	   r6   )abr   pqZnum_reduce_dimsZreduce_dimsZp_event_shape_tensorZq_event_shape_tensorZa_event_shape_tensorZb_event_shape_tensorr&   r&   r'   _kl_independent)  s>    


rj   )rb   )r_   
__future__r   r   r   r0   Z;tensorflow_probability.python.internal.backend.numpy.compatr   r   Z2tensorflow_probability.python.distributions._numpyr   Zdistribution_libr   Z-tensorflow_probability.python.internal._numpyr   r	   r
   r   Distributionr   Z
RegisterKLrj   r&   r&   r&   r'   <module>   s      

