ó
àÆ÷Xc           @` sª  d  Z  d d l m Z m Z m Z d d l m Z d d l m Z d d l	 Z	 d d l
 Z
 d d l Z d d l m Z d d l m Z d d l m Z 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 Z d Z d Z d Z e	 j  d ƒ Z! d e f d „  ƒ  YZ" d d „ Z$ e j% e" g ƒ d „  ƒ Z& e j' d e j( e& d e) ƒd d d ƒ e j* j+ j, e j* j+ j- e j* j+ j. e j* j/ e j* j+ j0 e j* j1 e j* j2 e j* j+ j3 e j* j+ j4 e j* j5 j6 e j* j5 j7 f Z8 e j% e8 ƒ d „  ƒ Z9 e j% e" g ƒ d „  ƒ Z: e j% e" g ƒ d „  ƒ Z; d  e j< f d! „  ƒ  YZ= e j% e" g ƒ d" „  ƒ Z> e j% e" g ƒ d# „  ƒ Z? d S($   sR  
IfElse introduces lazy evaluation in Theano (coupled with the CVM/VM
linkers). It resembles the if clause of any programming language, that
has a `then` and `else` branch, and executes either one or the other
according to the condition provided.

This op differs from the already existent `switch` op, that evaluates both
branches of the clause and afterwards picks (according to the condition)
which value to report. Note also that `switch` is an elemwise operation (so
it picks each entry of a matrix according to the condition) while `ifelse`
is a global operation with a scalar condition.
i    (   t   absolute_importt   print_functiont   division(   t   deepcopy(   t   izipN(   t
   TensorType(   t   gof(   t   Opt   Apply(   t	   iteritems(   t   xrange(   t   optdb(   t   opt(   t   find_up(   t   clones   restructedtext ens>   Razvan Pascanu James Bergstra Dumitru Erhan David Warde-Farleys    (c) 2010, Universite de Montreals    Razvan Pascanu <r.pascanu@gmail>s   theano.ifelset   IfElsec           B` sk   e  Z d  Z e e d
 d „ Z d „  Z d „  Z d „  Z d „  Z	 d „  Z
 d „  Z d „  Z d
 d	 „ Z RS(   st  
    Op that provides conditional graph evaluation if used with the CVM/VM
    linkers. Note that there exist a helpful function `ifelse` that should
    be used to instantiate the op!

    According to a scalar condition `condition` the op evaluates and then
    returns all the tensors provided on the `then` branch, otherwise it
    evaluates and returns the tensors provided on the `else` branch. The op
    supports multiple tensors on each branch, with the condition that the same
    number of tensors are on the `then` as on the `else` and there is a one
    to one correspondence between them (shape and dtype wise).

    The `then` branch is defined as the first N tensors (after the
    condition), while the `else` branch is defined as the last N tensors.

    Example usage:

        ``rval = ifelse(condition, rval_if_true1, .., rval_if_trueN,
                        rval_if_false1, rval_if_false2, .., rval_if_falseN)``

    :note:
        Other Linkers then CVM and VM are INCOMPATIBLE with this Op, and
        will ignore its lazy characteristic, computing both the True and
        False branch before picking one.

    c         C` sh   | r@ i  } x% t  | ƒ D] } | d g | | <q W| |  _ n  | |  _ | |  _ | |  _ | |  _ d  S(   Ni   (   R
   t   view_mapt   as_viewt   gput   n_outst   name(   t   selfR   R   R   R   R   t   idx(    (    s-   /tmp/pip-build-X4mzal/theano/theano/ifelse.pyt   __init__G   s    			c         C` sb   t  |  ƒ t  | ƒ k s t S|  j | j k s2 t S|  j | j k sH t S|  j | j k s^ t St S(   N(   t   typet   FalseR   R   R   t   True(   R   t   other(    (    s-   /tmp/pip-build-X4mzal/theano/theano/ifelse.pyt   __eq__T   s    c         C` s=   t  t |  ƒ ƒ t  |  j ƒ At  |  j ƒ At  |  j ƒ A} | S(   N(   t   hashR   R   R   R   (   R   t   rval(    (    s-   /tmp/pip-build-X4mzal/theano/theano/ifelse.pyt   __hash___   s    )c         C` sk   g  } |  j  d  k	 r( | j |  j  ƒ n  |  j rA | j d ƒ n  |  j rZ | j d ƒ n  d d j | ƒ S(   Nt   inplaceR   s   if{%s}t   ,(   R   t   Nonet   appendR   R   t   join(   R   t   args(    (    s-   /tmp/pip-build-X4mzal/theano/theano/ifelse.pyt   __str__f   s    		c      
   C` s×  | d |  j   } | d |  j  } g  } xD | D]< } t | t t f ƒ r] | t | ƒ 7} q/ d  g |  j  Sq/ Wg  } xD | D]< } t | t t f ƒ rª | t | ƒ 7} q| d  g |  j  Sq| Wt | ƒ t | ƒ k sÚ t ‚ t | | ƒ d k rtd g }	 |  j d  k	 r|	 j |  j ƒ n  t	 d t | ƒ d t
 d t
 d d j |	 ƒ ƒ }
 |
 | j d | | t d	 t ƒ Ž } n g  } g  } x8 | j D]- } | j t | | j  ƒ ƒ | | j } qŠWt | ƒ d k sÓt ‚ | S(
   Ni   i    t   shapeR   R   R   R   t   _t   return_list(   R   t
   isinstancet   listt   tupleR"   t   lent   AssertionErrorR   R#   R   R   R$   t   inputst   dictR   t   outputst   ndim(   R   t   nodet   inputs_shapest	   ts_shapest	   fs_shapest   new_ts_inputst   ts_shapet   new_fs_inputst   fs_shapet   name_tokenst
   new_ifelset   new_outst
   out_shapest   out(    (    s-   /tmp/pip-build-X4mzal/theano/theano/ifelse.pyt   infer_shapep   s@    	c   	      G` s˜  t  | ƒ d |  j k s< t d d |  j t  | ƒ f ƒ ‚ t j j | ƒ } |  j s× g  } xn | D]f } t | d ƒ r | j | j	 ƒ  ƒ qd t
 | t j ƒ r± | j | ƒ qd | j t j j | ƒ ƒ qd W| } n  | |  j  } | |  j } xP t | | ƒ D]? \ } } | j | j k rt d | | | j | j ƒ ‚ qqW| j d k rbt d ƒ ‚ n  t |  | g t | ƒ g  | D] } | j ƒ  ^ qƒ S(   Ni   s;   Wrong number of arguments to make_node: expected %d, got %dt   _as_TensorVariables;   IfElse requires same types for true and false return valuesi    s^   Condition given to the op has to be a scalar with 0 standing for False, anything else for True(   R-   R   R.   t   theanot   tensort   as_tensor_variableR   t   hasattrR#   RA   R*   t   VariableR   R   t	   TypeErrorR2   R   R+   (	   R   t   cR%   t   nw_argst   xt   tst   fst   tt   f(    (    s-   /tmp/pip-build-X4mzal/theano/theano/ifelse.pyt	   make_node¥   s,    		c         C` s!   |  | d | d t  d t ƒ Ž S(   Ni    i   R)   (   R0   R   (   R   R/   t   eval_points(    (    s-   /tmp/pip-build-X4mzal/theano/theano/ifelse.pyt   R_opÄ   s    c      	   C` s   | d |  j   } | d |  j  } |  j d  k	 rN |  j d } |  j d } n d  } d  } t d |  j  d |  j d |  j d | ƒ } t d |  j  d |  j d |  j d | ƒ } | d g | g  t | ƒ D]+ \ }	 }
 t j j	 |
 d	 | |	 j
 ƒ^ qÉ } | d g g  t | ƒ D]+ \ }	 } t j j	 | d	 | |	 j
 ƒ^ q| } | d } | j	 ƒ  j t j j ƒ } | g | | t d
 t ƒ Ž  | | t d
 t ƒ Ž  S(   Ni   t   _grad_tt   _grad_fR   R   R   R   i    t   dtypeR)   (   R   R   R"   R   R   R   t	   enumerateRB   RC   t
   zeros_likeRT   t   astypet   configt   floatXR0   R   (   R   t   inst   gradsRK   RL   t	   nw_name_tt	   nw_name_ft
   if_true_opt   if_false_opt   iRM   t   if_trueRN   t   if_falset	   conditiont   condition_grad(    (    s-   /tmp/pip-build-X4mzal/theano/theano/ifelse.pyt   gradÇ   s0    						<F
c         ` s²   | j  d ‰ | j  d ˆ j  ‰ | j  d ˆ j ‰ | j ‰ ‡  ‡ ‡ ‡ ‡ ‡ ‡ f d †  } t | _ g  | j  D] } ˆ | ^ qr | _  g  | j D] } ˆ | ^ q• | _ | S(   Ni    i   c          ` s  ˆ  ˆ d s d g Sˆ ˆ d }  |  d k r#g  t  ˆ j ƒ D]" } ˆ  ˆ | d s? | d ^ q? } t | ƒ d k r} | Sxœ t ˆ ˆ ƒ D]‹ \ } } d ˆ  | d <ˆ | d } ˆ j rÏ | ˆ | d <q t | ƒ t j t j f k r| j	 ƒ  ˆ | d <q t
 | ƒ ˆ | d <q Wg  SnÞ g  t  ˆ j ƒ D]) } ˆ  ˆ | d s3d | ˆ j ^ q3} t | ƒ d k rx| Sx‚ t ˆ ˆ ƒ D]q \ } } d ˆ  | d <ˆ | d } t | ƒ t j t j f k rå| j	 ƒ  ˆ | d <qˆt
 | ƒ ˆ | d <qˆWg  Sd  S(   Ni    i   (   R
   R   R-   R   R   R   t   numpyt   ndarrayt   memmapt   copyR   (   t   truthvalR   t   lsR?   RM   t   valRN   (   t   compute_mapt   condRL   R1   R   t   storage_mapRK   (    s-   /tmp/pip-build-X4mzal/theano/theano/ifelse.pyt   thunkö   s8    "	)(   R/   R   R1   R   t   lazy(   R   R3   Ro   Rm   t   no_recyclingt   implRp   t   v(    (   Rm   Rn   RL   R1   R   Ro   RK   s-   /tmp/pip-build-X4mzal/theano/theano/ifelse.pyt
   make_thunkð   s    	!(	##N(   t   __name__t
   __module__t   __doc__R   R"   R   R   R   R&   R@   RO   RQ   Re   Ru   (    (    (    s-   /tmp/pip-build-X4mzal/theano/theano/ifelse.pyR   ,   s   			
	5			)c      	   C` s©  d } t | ƒ t k r! t } n t | ƒ t k r< t } n  t | ƒ t t f k r` | g } n  t | ƒ t t f k r„ | g } n  g  } g  } x?t | | ƒ D].\ } } t | t j ƒ sÓ t j j	 | ƒ } n  t | t j ƒ sú t j j	 | ƒ } n  | j | j k r´t | j t
 ƒ rFt | j t
 ƒ rF| j j | ƒ } n: t | j t
 ƒ r€t | j t
 ƒ r€| j j | ƒ } n  | j | j k r´t d | j | j f ƒ ‚ q´n  | j | ƒ | j | ƒ q  Wt | ƒ t | ƒ k rt d t | ƒ d t | ƒ d ƒ ‚ n  t d t | ƒ d t d t d | ƒ }	 |  g t | ƒ t | ƒ }
 |	 |
 t d	 t ƒ Ž  } | d k r…| d
 S| t k r›t | ƒ St | ƒ Sd S(   s  
    This function corresponds to an if statement, returning (and evaluating)
    inputs in the ``then_branch`` if ``condition`` evaluates to True or
    inputs in the ``else_branch`` if ``condition`` evalutates to False.

    :type condition: scalar like
    :param condition:
        ``condition`` should be a tensor scalar representing the condition.
        If it evaluates to 0 it corresponds to False, anything else stands
        for True.

    :type then_branch: list of theano expressions/ theano expression
    :param then_branch:
        A single theano variable or a list of theano variables that the
        function should return as the output if ``condition`` evaluates to
        true. The number of variables should match those in the
        ``else_branch``, and there should be a one to one correspondance
        (type wise) with the tensors provided in the else branch

    :type else_branch: list of theano expressions/ theano expressions
    :param else_branch:
        A single theano variable or a list of theano variables that the
        function should return as the output if ``condition`` evaluates to
        false. The number of variables should match those in the then branch,
        and there should be a one to one correspondace (type wise) with the
        tensors provided in the then branch.

    :return:
        A list of theano variables or a single variable (depending on the
        nature of the ``then_branch`` and ``else_branch``). More exactly if
        ``then_branch`` and ``else_branch`` is a tensor, then
        the return variable will be just a single variable, otherwise a
        list. The value returns correspond either to the values in the
        ``then_branch`` or in the ``else_branch`` depending on the value of
        ``cond``.
    sÔ   The two branches should have identical types, but they are %s and %s respectively. This error could be raised if for example you provided a one element list on the `then` branch but a tensor on the `else` branch.s   The number of values on the `then` branch should have the same number of variables as the `else` branch : (variables on `then` %ds   , variables on `else` %dt   )R   R   R   R   R)   i    N(   R"   R   R+   R,   R   R*   RB   RF   RC   RD   R   t   filter_variableRG   R#   R-   t
   ValueErrorR   R   R0   R   (   Rc   t   then_brancht   else_branchR   t	   rval_typet   new_then_brancht   new_else_brancht   then_branch_elemt   else_branch_elemR<   RZ   R   (    (    s-   /tmp/pip-build-X4mzal/theano/theano/ifelse.pyt   ifelse$  s^    &						(	
c      	   C` s³   |  j  } t | t ƒ r¯ | j r¯ t |  j j ƒ d k  sr t g  |  j D]! } t	 | j
 d d ƒ d k ^ qG ƒ r¯ t d | j d t d | j d | j ƒ |  j t d	 t ƒ Ž  St S(
   Niô  R2   iÿÿÿÿi    R   R   R   R   R)   (   t   opR*   R   R   R-   t   fgrapht   apply_nodest   allR1   t   getattrR   R   R   R   R   R/   R0   R   (   R3   R„   t   o(    (    s-   /tmp/pip-build-X4mzal/theano/theano/ifelse.pyt   cond_make_inplace”  s    	
2	RŠ   t   ignore_newtreesi_   t   fast_runR    c         C` s§  t  |  j t ƒ s t St ƒ  } x! |  j D] } | j | j ƒ q) Wg  t | ƒ D]$ } | rP t  | j t	 ƒ rP | ^ qP } t
 | ƒ d k r t S| d } | j } | j d | j  } | j d | j } |  j }	 g  }
 g  } xq |  j D]f } | | j k r6| j j | ƒ } |
 j | | ƒ | j | | ƒ qê |
 j | ƒ | j | ƒ qê W|	 |
 t d t ƒ Ž  } |	 | t d t ƒ Ž  } t | j d | | d t ƒ} | S(   sÿ   This optimization lifts up certain ifelse instances.

        op(ifelse(c, x, y)) -> ifelse(c, op(x), op(y))

    if `op` is in the `acceptable_ops` list, and there is no other if as
    input to that specific `op`, and the if has no other clients !?
    i   i    R)   (   R*   R„   t   acceptable_opsR   t   setR/   t   addt   ownerR+   R   R-   R   R1   t   indexR#   R0   R   Rƒ   (   t	   main_nodet   all_inp_nodest   inpRJ   t   ifnodesR3   R„   RK   RL   t   mopt   true_inst	   false_insR   t	   true_evalt
   false_evalt   nw_outs(    (    s-   /tmp/pip-build-X4mzal/theano/theano/ifelse.pyt,   ifelse_lift_single_if_through_acceptable_ops×  s6    		$
		c         C` s7  |  j  } t | t ƒ s t S|  j d | j  } i  } xœ t | ƒ D]Ž \ } } | j rC t | j j  t ƒ rC | j j d |  j d k rC | j j  } | j j d | j  } | | j j j	 | ƒ | | d <qC qC Wt
 | ƒ d k rë t St |  j ƒ } x$ t | ƒ D] \ }	 }
 |
 | |	 <qW| | t d t ƒ Ž  S(   Ni   i    R)   (   R„   R*   R   R   R/   R   RU   R   R1   R‘   R-   R+   R	   R0   R   (   R3   R„   t   t_inst   replaceR   t   tvalt   ins_opt   ins_tt   old_inst   post   var(    (    s-   /tmp/pip-build-X4mzal/theano/theano/ifelse.pyt   cond_merge_ifs_true  s"    	(c         C` s>  |  j  } t | t ƒ s t S|  j d | j } i  } x£ t | ƒ D]• \ } } | j rC t | j j  t ƒ rC | j j d |  j d k rC | j j  } | j j d | j } | | j j j	 | ƒ | | d | j <qC qC Wt
 | ƒ d k rò t St |  j ƒ } x$ t | ƒ D] \ }	 }
 |
 | |	 <qW| | t d t ƒ Ž  S(   Ni   i    R)   (   R„   R*   R   R   R/   R   RU   R   R1   R‘   R-   R+   R	   R0   R   (   R3   R„   t   f_insRž   R   t   fvalR    R¡   R¢   R£   R¤   (    (    s-   /tmp/pip-build-X4mzal/theano/theano/ifelse.pyt   cond_merge_ifs_false  s"    	/t	   CondMergec           B` s    e  Z d  Z d „  Z d „  Z RS(   s0    Graph Optimizer that merges different cond ops c         C` s   | j  t j j ƒ  ƒ d  S(   N(   t   add_featureR   t   toolboxt   ReplaceValidate(   R   R…   (    (    s-   /tmp/pip-build-X4mzal/theano/theano/ifelse.pyt   add_requirements:  s    c         C` sy  t  | j ƒ  ƒ } g  | D] } t | j t ƒ r | ^ q } t | ƒ d k  rS t S| d } x| d D]	} | j d | j d k rh t | | ƒ rh | j d | j j	  } | j d | j j	 } | j d | j j	  }	 | j d | j j	 }
 | j d g | |	 | |
 } d } | j j
 r5| j j
 } n  d } | j j
 rV| j j
 } n  t d t | |	 ƒ d t d t d | d	 | ƒ } t d
 ƒ | | t d t ƒ Ž  } g  | D] } t | ƒ ^ q²} g  } t | j ƒ t  t f k rþ| | j g 7} n | | j 7} t | j ƒ t  t f k r9| | j g 7} n | | j 7} t  t | | ƒ ƒ } | j | d d ƒqh qh Wd  S(   Ni   i    i   t   ?R   R   R   R   t   &t   hereR)   t   reasont
   cond_merge(   R+   t   toposortR*   R„   R   R-   R   R/   R   R   R   t   printR0   R   R   R   R1   R,   t   zipt   replace_all_validate(   R   R…   t   nodelistt   st
   cond_nodest   merging_nodet   proposalt   mn_tst   mn_fst   pl_tst   pl_fst   new_inst   mn_namet   pl_nameR<   R=   RJ   t   old_outst   pairs(    (    s-   /tmp/pip-build-X4mzal/theano/theano/ifelse.pyt   apply=  sH    +
 
(   Rv   Rw   Rx   R­   RÅ   (    (    (    s-   /tmp/pip-build-X4mzal/theano/theano/ifelse.pyR©   8  s   	c      	   C` s;  |  j  } t | t ƒ s t S|  j d | j  } |  j d | j } i  } x” t t |  j ƒ ƒ D]} } | | k r` xh t | d t |  j ƒ ƒ D]G } | | | | k r | | | | k r | | k r | | | <q q Wq` q` Wt | ƒ d k r÷ t Sg  } g  } i  }	 d }
 xb t t |  j ƒ ƒ D]K } | | k r%|
 |	 | <|
 d }
 | j	 | | ƒ | j	 | | ƒ q%q%Wt d t | ƒ d | j
 d | j d | j ƒ } |  j d g | | } | | t d t ƒ Ž  } g  } xZ t t |  j ƒ ƒ D]C } | | k r| | |	 | | g 7} qð| | |	 | g 7} qðW| S(   Ni   i    R   R   R   R   R)   (   R„   R*   R   R   R/   R   R
   R-   R1   R#   R   R   R   R0   R   (   R3   R„   RK   RL   t   out_mapR   t   jdxt   nw_tst   nw_fst   inv_mapR£   R<   RÀ   R=   R   (    (    s-   /tmp/pip-build-X4mzal/theano/theano/ifelse.pyt   cond_remove_identicalj  sJ    	#

		c         C` s   t  |  j t ƒ r t St ƒ  } x! |  j D] } | j | j ƒ q) Wg  t | ƒ D]$ } | rP t  | j t ƒ rP | ^ qP } t	 | ƒ d k  r t S| d } xÿ| d D]ó} | j d | j d k r¥ t
 | | ƒ r¥ t
 | | ƒ r¥ | j d | j j  } | j d | j j } | j d | j j  }	 | j d | j j }
 | j d g | |	 | |
 } d } | j j r‚| j j } n  d } | j j r£| j j } n  t d t	 | |	 ƒ d t d t d | d	 | ƒ } | | t d
 t ƒ Ž  } g  } t | j ƒ t t f k r"| | j g 7} n | | j 7} t | j ƒ t t f k r]| | j g 7} n | | j 7} t t | | ƒ ƒ } t |  j d | ƒ} | Sq¥ Wd  S(   Ni   i    i   R®   R   R   R   R   R¯   R)   Rž   (   R*   R„   R   R   RŽ   R/   R   R   R+   R-   R   R   R   R0   R   R   R1   R,   Rµ   R   (   R’   R“   R”   RJ   R¹   Rº   R»   R¼   R½   R¾   R¿   RÀ   RÁ   RÂ   R<   R=   RÃ   RÄ   t	   main_outs(    (    s-   /tmp/pip-build-X4mzal/theano/theano/ifelse.pyt   cond_merge_random_op  sR    	$
 (@   Rx   t
   __future__R    R   R   Ri   R   t   theano.compatR   t   loggingRf   t   theano.tensorRB   R   R   t
   theano.gofR   R   t   sixR	   t	   six.movesR
   t   theano.compileR   R   t   theano.scan_module.scan_utilsR   R   t   __docformat__t   __authors__t   __copyright__t   __contact__t	   getLoggert   _loggerR   R"   Rƒ   t   local_optimizerRŠ   t   registert   in2outR   RC   t   basict   Dott   Reshapet   Shapet   SpecifyShapet   MaxAndArgmaxt	   Subtensort   IncSubtensort   Rebroadcastt   Alloct   elemwiset   Elemwiset
   DimShuffleR   Rœ   R¥   R¨   t	   OptimizerR©   RË   RÍ   (    (    (    s-   /tmp/pip-build-X4mzal/theano/theano/ifelse.pyt   <module>   sT   øp$			023