B
    `9                 @   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 ZG dd dejZeeedddZG dd dejZeeedddZdS )zThe Blockwise distribution.    )absolute_import)division)print_functionN)v2)distribution)joint_distribution_sequential)kullback_leibler)assert_util)
dtype_util)prefer_static)reparameterization)tensorshape_utilc             C   s&   yt | }W n tk
r    dS X dS )NFT)iter	TypeError)x_ r   k/home/dcms/DCMS/lib/python3.7/site-packages/tensorflow_probability/python/distributions/_numpy/blockwise.py_is_iterable#   s
    r   c                   sb   e Zd ZdZ fddZdd Zdd Zdd	 Zd
d ZdddZ	dd Z
dd Zdd Z  ZS )_CastzDUtility distribution to cast inputs/outputs of another distribution.c          	      sb   t t }dt|}t|4}|| _|| _t	t
| j||j|j|j||d W d Q R X d S )NzCastTo{})dtypevalidate_argsallow_nan_statsreparameterization_type
parametersname)dictlocalsformatr
   r   tf
name_scope_distribution_dtypesuperr   __init__r   r   r   )selfr   r   r   r   )	__class__r   r   r$   .   s    

z_Cast.__init__c             C   s   | j jS )N)r!   batch_shape)r%   r   r   r   _batch_shape<   s    z_Cast._batch_shapec             C   s
   | j  S )N)r!   batch_shape_tensor)r%   r   r   r   _batch_shape_tensor?   s    z_Cast._batch_shape_tensorc             C   s   | j jS )N)r!   event_shape)r%   r   r   r   _event_shapeB   s    z_Cast._event_shapec             C   s
   | j  S )N)r!   event_shape_tensor)r%   r   r   r   _event_shape_tensorE   s    z_Cast._event_shape_tensorNc                s    t j fdd j||S )Nc                s   t |  jS )N)r   castr"   )r   )r%   r   r   <lambda>I       z!_Cast._sample_n.<locals>.<lambda>)r   nestmap_structurer!   sample)r%   nseedr   )r%   r   	_sample_nH   s    z_Cast._sample_nc             C   s,   t jt j|| jj}t | j|| jS )N)r   r2   r3   r/   r!   r   log_probr"   )r%   r   r   r   r   	_log_probL   s    z_Cast._log_probc             C   s
   | j  S )N)r!   entropy)r%   r   r   r   _entropyP   s    z_Cast._entropyc                s   t j fdd j S )Nc                s   t |  jS )N)r   r/   r"   )r   )r%   r   r   r0   T   r1   z_Cast._mean.<locals>.<lambda>)r   r2   r3   r!   mean)r%   r   )r%   r   _meanS   s    z_Cast._mean)N)__name__
__module____qualname____doc__r$   r(   r*   r,   r.   r7   r9   r;   r=   __classcell__r   r   )r&   r   r   +   s   
r   c             C   s   | j j|j |dS )N)r   )r!   kl_divergence)Zd0d1r   r   r   r   _kl_blockwise_castX   s    rE   c                   s   e Zd ZdZd$ fdd	Zedd Zdd	 Zd
d Zdd Z	dd Z
dd Zdd Zd%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 )&	Blockwiseac  Blockwise distribution.

  This distribution converts a distribution or list of distributions into a
  vector-variate distribution by doing a sequence of reshapes and concatenating
  the results. This is particularly useful for converting `JointDistribution`
  instances to vector-variate for downstream uses which can only handle
  single-`Tensor` distributions.

  #### Examples

  Flattening a sequence of distrbutions:

  ```python
  tfd = tfp.distributions

  d = tfd.Blockwise(
      [
          tfd.Independent(
              tfd.Normal(
                  loc=tf.zeros(4, dtype=tf.float64),
                  scale=1),
              reinterpreted_batch_ndims=1),
          tfd.MultivariateNormalTriL(
              scale_tril=tf.eye(2, dtype=tf.float32)),
      ],
      dtype_override=tf.float32,
  )
  x = d.sample([2, 1])
  y = d.log_prob(x)
  x.shape  # ==> (2, 1, 4 + 2)
  x.dtype  # ==> tf.float32
  y.shape  # ==> (2, 1)
  y.dtype  # ==> tf.float32

  d.mean()  # ==> np.zeros((4 + 2,))
  ```

  Flattening a joint distribution:

  ```python
  tfd = tfp.distributions

  Root = tfd.JointDistributionCoroutine.Root  # Convenient alias.
  def model():
    e = yield Root(tfd.Independent(tfd.Exponential(rate=[100, 120]), 1))
    g = yield tfd.Gamma(concentration=e[..., 0], rate=e[..., 1])
    n = yield Root(tfd.Normal(loc=0, scale=2.))
    yield tfd.Normal(loc=n, scale=g)

  joint = tfd.JointDistributionCoroutine(model)
  d = tfd.Blockwise(joint)

  x = d.sample([2, 1])
  y = d.log_prob(x)
  x.shape  # ==> (2, 1, 2 + 1 + 1 + 1)
  x.dtype  # ==> tf.float32
  y.shape  # ==> (2, 1)
  y.dtype  # ==> tf.float32
  ```

  NFc       	   	      s4  t t }t|}|| _ dk	r<tj fdd|}t|rVt	t
|| _n|| _| j | _| jj| _ dk	r }nZtdd tj| jjD }t|dkrtj}n(t|dkr| }ntd| jjttj| jj}t|dkr| ntj}tt| j||||||d	 W dQ R X dS )
aV  Construct the `Blockwise` distribution.

    Args:
      distributions: Python `list` of `tfp.distributions.Distribution`
        instances. All distribution instances must have the same `batch_shape`
        and all must have `event_ndims==1`, i.e., be vector-variate
        distributions.
      dtype_override: samples of `distributions` will be cast to this `dtype`.
        If unspecified, all `distributions` must have the same `dtype`.
        Default value: `None` (i.e., do not cast).
      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.
    Nc                s
   t |  S )N)r   )d)dtype_overrider   r   r0      r1   z$Blockwise.__init__.<locals>.<lambda>c             s   s    | ]}|d k	rt |V  qd S )N)r
   Z
base_dtype).0r   r   r   r   	<genexpr>   s   z%Blockwise.__init__.<locals>.<genexpr>r      z.Distributions must have same dtype; found: {}.)r   r   r   r   r   r   )r   r   r   r    _distributionsr2   r3   r   r   ZJointDistributionSequentiallistr!   r)   _cached_batch_shape_tensorr'   _cached_batch_shapesetflattenr   lenfloat32popr   r   r   r   ZNOT_REPARAMETERIZEDr#   rF   r$   )	r%   distributionsrH   r   r   r   r   r   r   )r&   )rH   r   r$      sF    



zBlockwise.__init__c             C   s   | j S )N)rL   )r%   r   r   r   rU      s    zBlockwise.distributionsc             C   s    t tjtj| jtd S )N)		functoolsreducer   Z
merge_withr   r2   rQ   rO   TensorShape)r%   r   r   r   r(      s    zBlockwise._batch_shapec             C   s   t j| jd S )Nr   )r   r2   rQ   rN   )r%   r   r   r   r*      s    zBlockwise._batch_shape_tensorc             C   sR   t jtj| jj}tdd t j|D r:t 	d gS t 	t
t j|gS )Nc             s   s   | ]}|d kV  qd S )Nr   )rI   rr   r   r   rJ      s    z)Blockwise._event_shape.<locals>.<genexpr>)r   r2   r3   r   num_elementsr!   r+   anyrQ   rX   sum)r%   event_sizesr   r   r   r,      s
    

zBlockwise._event_shapec             C   s`   t jtj| jj}tdd t j|D rHt jdd || j	 }t 
t j|t j S )Nc             s   s   | ]}|d kV  qd S )Nr   )rI   sr   r   r   rJ      s    z0Blockwise._event_shape_tensor.<locals>.<genexpr>c             S   s   | d krt |S | S )N)r   reduce_prod)Zstatic_sizeshape_tensorr   r   r   r0     s    z/Blockwise._event_shape_tensor.<locals>.<lambda>)r   r2   r3   r   rZ   r!   r+   r[   rQ   r-   Z
reduce_sumZnewaxis)r%   r]   r   r   r   r.      s    

zBlockwise._event_shape_tensorc                sl    fdd}t dd tj jjD r@tj|| jj}ntj|| j }tjtj|ddS )Nc                sx   t |  j} t t|}|dkr*| S tjt| d tt| t|  dggdd}t 	| t|t j
S )NrK   )axis)r   r/   r   get_static_valuepsrank_from_shapeconcatshapesizereshapeint32)partr+   static_rank	new_shape)r%   r   r   _reshape_part  s    ,z:Blockwise._flatten_and_concat_event.<locals>._reshape_partc             s   s   | ]}t |V  qd S )N)r   is_fully_defined)rI   r^   r   r   r   rJ     s   z6Blockwise._flatten_and_concat_event.<locals>.<genexpr>ra   )rb   )	allr   r2   rQ   r!   r+   r3   r-   rf   )r%   r   rn   r   )r%   r   _flatten_and_concat_event	  s    

z#Blockwise._flatten_and_concat_eventc             C   s   | j  }dd tj|D }tj|tj||dd}dd }tdd tj| j jD r|tj	||| j j
| j j}ntj	||| j j
| j  }|S )	Nc             S   s   g | ]}t d t |qS )rK   )rd   maximumr_   )rI   r^   r   r   r   
<listcomp>#  s   z6Blockwise._split_and_reshape_event.<locals>.<listcomp>ra   )rb   c             S   s^   t | |} t t|}|dkr(| S tjt| d d |gdd}t | t|t jS )NrK   ra   )rb   )	r   r/   rc   rd   re   rf   rg   ri   rj   )rk   r   r+   rl   rm   r   r   r   rn   (  s     z9Blockwise._split_and_reshape_event.<locals>._reshape_partc             s   s   | ]}t |V  qd S )N)r   ro   )rI   r^   r   r   r   rJ   1  s   z5Blockwise._split_and_reshape_event.<locals>.<genexpr>)r!   r-   r   r2   rQ   Zpack_sequence_assplitrp   r+   r3   r   )r%   r   Zevent_tensorssplitsrn   r   r   r   _split_and_reshape_event   s    
z"Blockwise._split_and_reshape_eventc             C   s   |  | jj||dS )N)r6   )rq   r!   r4   )r%   r5   r6   r   r   r   r7   :  s    zBlockwise._sample_nc             C   s   | j | |S )N)r!   r8   rv   )r%   r   r   r   r   r9   >  s    zBlockwise._log_probc             C   s
   | j  S )N)r!   r:   )r%   r   r   r   r;   A  s    zBlockwise._entropyc             C   s   | j | |S )N)r!   Zprobrv   )r%   r   r   r   r   _probD  s    zBlockwise._probc             C   s   |  | j S )N)rq   r!   r<   )r%   r   r   r   r=   G  s    zBlockwise._meanc             C   s
   | j  S )N)r!   Z*_experimental_default_event_space_bijector)r%   r   r   r   _default_event_space_bijectorJ  s    z'Blockwise._default_event_space_bijectorc                s  g }d |rTt j| j}tdd |D rT|dd  |d d krTtd || jsf|rbtg S | jr| j}tdd t j|D st j	dd	 || j
}t j|}| fd
dt|dd  |d d D  | fddt|dd  |d d D  |S )Nz.Distributions must have the same `batch_shape`c             s   s   | ]}t |V  qd S )N)r   ro   )rI   br   r   r   rJ   T  s    z<Blockwise._parameter_control_dependencies.<locals>.<genexpr>rK   ra   z{}; found: {}.c             s   s   | ]}t |V  qd S )N)r   ro   )rI   r^   r   r   r   rJ   _  s   c             S   s   t | r| S |S )N)r   ro   )Zstatic_shaper`   r   r   r   r0   b  s    z;Blockwise._parameter_control_dependencies.<locals>.<lambda>c             3   s(   | ] \}}t j||d  dV  qdS )z{}.)messageN)r	   assert_equalr   )rI   b1b2)rz   r   r   rJ   g  s   c             3   s4   | ],\}}t jt|t|d  dV  qdS )z{}.)rz   N)r	   r{   r   rh   r   )rI   r|   r}   )rz   r   r   rJ   m  s   )r   r2   rQ   rO   rp   
ValueErrorr   r   AssertionErrorr3   rN   extendzip)r%   Zis_init
assertionsZbatch_shapesr   )rz   r   _parameter_control_dependenciesM  s4    

 
 z)Blockwise._parameter_control_dependenciesc             C   sR   g }d}t |jd k	r2t |jdkrNt|n| jrN|tj|d|d |S )Nz'Input must have at least one dimension.r   rK   )rz   )r   Zrankrg   r~   r   appendr	   Zassert_rank_at_least)r%   r   r   rz   r   r   r   _sample_control_dependenciesu  s    
z&Blockwise._sample_control_dependencies)NFFrF   )N)r>   r?   r@   rA   r$   propertyrU   r(   r*   r,   r.   rq   rv   r7   r9   r;   rw   r=   rx   r   r   rB   r   r   )r&   r   rF   ]   s(   =   E
(rF   c             C   s   | j j|j |dS )a  Calculate the batched KL divergence KL(b0 || b1) with b0 and b1 Blockwise distributions.

  Args:
    b0: instance of a Blockwise distribution object.
    b1: instance of a Blockwise distribution object.
    name: (optional) Name to use for created operations. Default is
      "kl_blockwise_blockwise".

  Returns:
    kl_blockwise_blockwise: `Tensor`. The batchwise KL(b0 || b1).
  )r   )r!   rC   )Zb0r|   r   r   r   r   _kl_blockwise_blockwise  s    r   )N)N)rA   
__future__r   r   r   rV   Z;tensorflow_probability.python.internal.backend.numpy.compatr   r   Z2tensorflow_probability.python.distributions._numpyr   Zdistribution_libr   r   Z-tensorflow_probability.python.internal._numpyr	   r
   r   rd   Z&tensorflow_probability.python.internalr   r   r   Distributionr   Z
RegisterKLrE   rF   r   r   r   r   r   <module>   s,   -
  %
