U
    dl                     @   s   d dl mZmZ d dlmZmZ d dlmZmZ G dd dej	Z
G dd deZe ZG dd	 d	e
ZG d
d de
ZG dd de
ZG dd deZG dd de
ZG dd deZG dd de
ZG dd de
ZG dd de
ZG dd de
ZdS )    )corecontext)Task	TaskGroup)	add_if_opadd_while_opc                       s   e Zd Z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dZdd Zdd Z fddZedd Zdd Z  ZS ) 
NetBuildera  
    Scope-driven mechanism for building nets, loops and conditional blocks.
    Args:
      name: NetBuilder's name
      initial_scope: list of blobs that are available for reading/writing
    Example:
        from caffe2.python.net_builder import NetBuilder, ops
        with NetBuilder() as nb:
            c = ops.Const(5)
            d = ops.Const(0)
            with ops.loop():
                ops.stop_if(ops.LE([c, ops.Const(0)]))
                ops.Add([c, ops.Const(-1)], [c])
                with ops.If(ops.GE([c, ops.Const(3)])):
                    ops.Add([d, ops.Const(10)], [d])
            ops.Print(c, [])
            ops.Print(d, [])
        step = core.to_execution_step(nb)
    NFc                 C   s   t jdd}|r|rtd|r0|s(|r0td|pTddd |rH|jnd |fD | _d| _d | _g | _|rv|  |rt	|j
nt	 | _|r|  jt	dd	 |D O  _t	| j| _
|| _|| _|| _d S )
NFrequiredz"Cannot set both _fullname and name.Stop blobs are not used with control operators/c                 s   s   | ]}|r|V  qd S N ).0nr   r   =/tmp/pip-unpacked-wheel-ua33x9lu/caffe2/python/net_builder.py	<genexpr>(   s     z&NetBuilder.__init__.<locals>.<genexpr>c                 S   s   g | ]}t |qS r   )str)r   br   r   r   
<listcomp>3   s     z'NetBuilder.__init__.<locals>.<listcomp>)r   currentAssertionErrorjoinname_frozen_current_net	_children_update_lexical_scopeset_lexical_scope_init_lexical_scope
_stop_blob_stop_blob_required_use_control_ops)selfr   Zinitial_scoper"   r!   Z	_fullnamer#   parentr   r   r   __init__!   s0    
zNetBuilder.__init__c                 C   s   | j rtd| jdkr|  }tj|d|d| _|jd| jd | j| j	d kr| j	
dtd | j	d jd| jd | jS )	a?  
        Returns the BlobReference to the stop_blob of this NetBuilder.
        If one is not yet available, creates one.
        This function assumes that the stop_blob() will be used immediatelly
        in the current net, so it doesn't initialize it if the current net is
        the first of the builder.
        r   N	stop_blob)netFZblob_outr   Zstop_blob_init)r#   r   r!   current_netr   BlobReferenceZNextNameConstr   r   insertNetr$   r(   r   r   r   r'   9   s    
 zNetBuilder.stop_blobc                 C   s2   | j rtd|  }t||g|g d | _d S )Nr   )r#   r   r'   opsOrr   )r$   blobr'   r   r   r   stop_ifM   s    zNetBuilder.stop_ifc                 C   s   | j rtd| j d S )Nz,This NetBuilder (%s) has been built already.)r   r   r   r$   r   r   r   _assert_mutableT   s    zNetBuilder._assert_mutablec                 C   s\   t | j| _| jD ]D}t|tjr6|  j| O  _qt|tr|j	r|  j|jO  _qdS )z
        Updates lexical scope based on the current list of children.
        Lexical scope contains names of blobs that are currently available
        and were introduced in the net builder
        N)
r   r    r   r   
isinstancer   r.   ZUsedBlobNamesr   r#   r$   childr   r   r   r   X   s    
z NetBuilder._update_lexical_scopec                 C   s   d | _ g | _t| j| _d S r   )r   r   r   r    r   r4   r   r   r   _reset_childrene   s    zNetBuilder._reset_childrenc                 C   sb   |    | jr2t|tjs2t|tr*|js2tdd | _| j	| t|tjrV|| _| 
  |S )Nz+Expected Net or NetBuilder with control ops)r5   r#   r6   r   r.   r   r   r   r   appendr   r7   r   r   r   addj   s    zNetBuilder.addc                 C   s0   |    | jd ks|d k	r*| t| | jS r   )r5   r   r;   r   r.   r$   r   r   r   r   r*   z   s    zNetBuilder.current_netc                 C   s.   | j D ]}t|dr|  qd | _d| _d S )NfreezeT)r   hasattrr=   r   r   r7   r   r   r   r=      s
    


zNetBuilder.freezec                 C   s   |    | jS r   )r=   r   r4   r   r   r   get   s    zNetBuilder.getc                    s   t t| j|f|  | jrZt| jdkrZ| j}|   t|| j}|sRt	d|g| _| 
  |d k	rnd S | jr| jd k	st	d| j d d S )Nr   z&Expected a non-empty merge of childrenz/This NetBuilder (%s) requires a stop condition z"to be set with `stop` or `stop_if`)superr   __exit__r#   lenr   r9   
merge_netsr   r   r=   r"   r!   r   )r$   etypeargsr   Z
merged_net	__class__r   r   rA      s$     zNetBuilder.__exit__c                    s   d }| D ]~}d }t |tr^|js(td| }t|dkrLt |d tjsTtd|d }nt |tjsnt|}|r|| q|}q|r fdd|	 j
D }||	 j
d d < |S )Nz4Merging of NetBuilder supported only for control ops   r   zInvalid control op net builderc                    s   g | ]}| kr|qS r   r   )r   oouter_blob_namesr   r   r      s    z)NetBuilder.merge_nets.<locals>.<listcomp>)r6   r   r#   r   r?   rB   r   r.   Z	AppendNetProtoZexternal_output)Znets_or_buildersrK   r(   r   curnetsZexternal_outputsr   rJ   r   rC      s*    

zNetBuilder.merge_netsc                 C   s
   | j pdS )NzUn-named NetBuilderr   r4   r   r   r   __str__   s    zNetBuilder.__str__)NNFNNF)N)__name__
__module____qualname____doc__r&   r'   r3   r5   r   r9   r;   r*   r=   r?   rA   staticmethodrC   rP   __classcell__r   r   rF   r   r      s&         


,r   c                   @   s   e Zd ZdZd,ddZdd Zdd Zd	d
 Zdd Zd-ddZ	d.ddZ
d/ddZd0ddZd1ddZd2ddZd3ddZdd Zdd Zdd  Zd!d" Zd#d$ Zd4d%d&Zd5d(d)Zd6d*d+ZdS )7
Operationsz?
    Operations to be used in the context of a NetBuilder.
    Nc                 C   sB   |dks|dkst d|dk	r2t | |S t j|dS )a  
        Retrieves the current net, or add a new net to the builder.
        Args:
            net:   If provided, add the given net to the active builder.
                   Else, returns the current Net or creates a new one as needed.
            name:  if provided, creates a new Net with given name and makes
                   it the new current net of the active builder. Cannot
                   be provided if net is provided.
        Nz%Cannot provide both `net` and `name`.rO   )r   r   r   r;   r*   )r$   r(   r   r   r   r   r(      s    
zOperations.netc                 C   s6   | drt tjdddkr(tdt|  |S )zD
        Adds an operator call to the currently active Net.
        __Fr	   NzNo active NetBuilder.)
startswithAttributeErrorr   r   getattrr(   )r$   Zop_typer   r   r   __getattr__   s
    
zOperations.__getattr__c                 C   sl   ddl m} t }| F |d0 | }|| |W  5 Q R  W  5 Q R  S Q R X W 5 Q R X dS )zs
        Creates a local task group which will execute as the next step of
        the current NetBuilder.
        r   )tasklocalN)caffe2.pythonr]   r   r   ZClusterNoder   r;   )r$   r]   grouptgr   r   r   
task_group   s    

zOperations.task_groupc                 C   s   |  tdS )z
        Stop execution of the current execution step.
            Example:
                ops.Print(a, 0)
                ops.stop()
                ops.Print(b, 0)
            In the example, 'b' will never be printed.
        T)r3   r0   r,   r4   r   r   r   stop   s    	zOperations.stopc                 C   s   t  |S )ah  
        Stop execution of the current execution step if the
        condition `blob` is met.
            Example:
                ops.Print(a, 0)
                ops.stop_if(ops.LE([x, ops.Const(0)]))
                ops.Print(b, 0)
            In the example, 'b' will only be printed if the value of scalar
            tensor 'x' is greater than 0.
        )r   r   r3   )r$   r2   r   r   r   r3     s    zOperations.stop_ifc                 C   s   t  t||dS )a  
        Creates a NetBuilder that will execute in a loop as the next step of
        the current NetBuilder. If `iters` is provided, the loop will execute
        for `iters` iterations and then stop. `iters` can be a constant or a
        BlobReference. If `iters` is not provided, the loop will execute
        until `ops.stop` or `ops.stop_if` is called.
            Examples:
                a = ops.Const(5)
                with ops.loop():
                    ops.stop_if(ops.LE([a, ops.Const(0)]))
                    ops.Print(a, 0)
                    ops.Add([a, ops.Const(-1)], [a])
            Above, 'a' will be printed 5 times, with values 5 to 1.

                with ops.loop(10) as loop:
                    ops.LogInfo(loop.iter())
            This will print the numbers from 0 to 9.

                x = ops.Add([ops.Const(10), ops.Const(10)])
                with ops.loop(x) as loop:
                    ops.LogInfo(loop.iter())
            This will print the numbers from 0 to 19.
        rO   )r   r   r;   _Loopr$   Zitersr   r   r   r   loop  s    zOperations.loopc                 C   s   t  t||dS )a$  
        Creates a NetBuilder that will execute once as the next step of the
        current NetBuilder. After execution, a bool tensor will indicate
        whether the inner execution was halted with `stop` or `stop_if`.
            Example:
                a = ops.Const(True)
                with ops.stop_guard() as sg1:
                    ops.stop_if(a)
                    ops.Print(ops.Const('did not stop'))
                b = ops.Const(False)
                with ops.stop_guard() as sg2:
                    ops.stop_if(b)
                    ops.Print(ops.Const('did not stop'))
                ops.Print(sg1.has_stopped(), [])
                ops.Print(sg2.has_stopped(), [])
            In the example, 'did not stop' will be printed once,
            followed by True and False.
        )has_stopped_blobr   )r   r   r;   
_StopGuardr$   rh   r   r   r   r   
stop_guard-  s    
zOperations.stop_guardc                 C   s   t  t||dS )a  
        Creates a NetBuilder that will execute once as the next step of the
        current NetBuilder if the blob `cond` is True.
            Example:
                with ops.If(ops.Const(True)):
                    ops.Print(ops.Const('Will print'))
                with ops.If(ops.Const(False)):
                    ops.Print(ops.Const('Wont print'))
            The example will print 'Will print' once.
        rO   )r   r   r;   _RunIfr$   Zcondr   r   r   r   IfC  s    zOperations.Ifc                 C   s   t  t||dS )zT
        Same as If, but uses 'If' operator instead of execution step logic
        rO   )r   r   r;   	_RunIfNetrm   r   r   r   IfNetP  s    zOperations.IfNetc                 C   s
   t |dS )z
        Else branch of IfNet, has to be specified immediately after IfNet.
            Example:
                with ops.IfNet(ops.LT([x, y])):
                    ...
                with ops.Else():
                    ...
        rO   )_RunElseNetr<   r   r   r   ElseV  s    	zOperations.Elsec                 C   s   t  t|dS )z9
        NetBuilder for 'While' control operator
        rO   )r   r   r;   _RunWhileNetr<   r   r   r   WhileNeta  s    zOperations.WhileNetc                 C   s    t t tstdt|dS )zD
        Loop's condition, executed within WhileNet context
        z$Use of Condition outside of WhileNetrO   )r6   r   r   rs   r   _RunWhileConditionr<   r   r   r   	Conditiong  s    zOperations.Conditionc                 C   s    t t j}|  tj| |S )a  
        Defines operations that will be executed once at task startup.
        Useful when implementing processors, that don't have access to the Task
        top-level structure.

        This setup will be run only once, even if multiple instances of the task
        will run in parallel. For instance-local initialization, use
        `task_instance_init` instead.

            Example:
                def my_processor(rec):
                    with ops.task_init():
                        one = ops.Const(1)
                        two = ops.Const(1)
                    return Tuple(
                        ops.Add(rec[0](), zero), ops.Add(rec[1](), two))
        )_SetupBuilderINITr(   add_attributer   
TASK_SETUPr$   setupr   r   r   	task_inito  s    
zOperations.task_initc                 C   s    t t j}|  tj| |S )a<  
        Define operations to be executed once at task shutdown.
        Useful when implementing processors, that don't have access to the Task
        top-level structure.

        This shutdown will be run only once, after all concurrent instances of
        the task have already finished. For instance-local shutdown,
        use `task_instance_exit` instead.

            Example:
                def read_queue(queue):
                    with ops.task_exit():
                        queue.close(ops.net())
                    return queue.read(ops.net())
        )rw   EXITr(   ry   r   rz   r{   r   r   r   	task_exit  s    
zOperations.task_exitc                 C   s    t t j}|  tj| |S )aw  
        Defines operations that will be executed once at startup of each
        instance of a task. This can be seen as "thread_local" initialization.
        It is guaranteed to run only after all `task_init` logic finishes.

        This setup will be run concurrently for each instance of a task.
        For global task initialization, use `task_init` instead.
        )rw   rx   r(   ry   r   TASK_INSTANCE_SETUPr{   r   r   r   task_instance_init  s    	
zOperations.task_instance_initc                 C   s    t t j}|  tj| |S )a(  
        Defines operations that will be executed once at shutdown of each
        instance of a task. This can be seen as "thread_local" finalization.

        This shutdown will be run concurrently for each instance of a task.
        For global task shutdown, use `task_exit` instead.
        )rw   r~   r(   ry   r   r   r{   r   r   r   task_instance_exit  s    
zOperations.task_instance_exitc                 C   s    t t j}|  tj| |S )a&  
        Similar to `task_init`, but executes at TaskGroup's startup instead,
        before any task of the group starts executing. This will run only
        once on each node, before initialization of any task, so it can be
        used e.g. to initialize blobs shared across tasks.
        )rw   rx   r(   ry   r   LOCAL_SETUPr{   r   r   r   
local_init  s    
zOperations.local_initc                 C   s"   t t j|}|  tj| |S )z
        Similar to `task_exit`, but executes at TaskGroup's exit instead,
        after all tasks of the group finished execution.
        This will run only once on each node.
        )rw   r~   r(   ry   r   r   )r$   r   r|   r   r   r   
local_exit  s    zOperations.local_exit  c                 C   s   t ||  |dS )am  
        Define operations to be executed at every time interval from
        task start-up to finish. These operations are guaranteed to
        execute at least once after all other operations of the task are
        finished.

            Example:
                with ops.task_reporter(interval_ms=10000):
                    ops.LogInfo('10s elapsed')
        )r(   r   )_ReporterBuilderr(   r$   interval_msr   r   r   r   task_reporter  s    zOperations.task_reporterc                 C   s   t ||dS )z
        Similar to task_report, but operations defined within this block
        will run repeatedly for as long as any of the tasks in the current
        TaskGroup have not finished.
        rO   )r   r   r   r   r   local_reporter  s    zOperations.local_reporter)NN)NN)NN)N)N)N)N)N)N)r   N)r   N)rQ   rR   rS   rT   r(   r\   rc   rd   r3   rg   rk   rn   rp   rr   rt   rv   r}   r   r   r   r   r   r   r   r   r   r   r   rW      s*   










rW   c                   @   s   e Zd ZdddZdd ZdS )r   Nc                 C   s   t | | || _|| _d S r   )r   r&   _netr   )r$   r   r(   r   r   r   r   r&     s    z_ReporterBuilder.__init__c                 G   s`   |d krJt | }|| j | jr6| jtj| nt	 j
|| jd tj| |f|  d S )N)r   )r   to_execution_stepZRunEveryMillisr   r   ry   r   ZREPORT_STEPr   r   Zreport_stepr   rA   )r$   rD   rE   stepr   r   r   rA     s    
 z_ReporterBuilder.__exit__)NNrQ   rR   rS   r&   rA   r   r   r   r   r     s   
r   c                   @   s.   e Zd ZdZdZd
ddZdd Zdd	 ZdS )rw   initexitNc                 C   s   t | | || _d S r   )r   r&   type)r$   r   r   r   r   r   r&     s    z_SetupBuilder.__init__c                 C   s   | j tjkrt| S d S r   )r   rw   rx   r   r   r/   r   r   r   r|     s    z_SetupBuilder.setupc                 C   s   | j tjkrt| S d S r   )r   rw   r~   r   r   r/   r   r   r   r     s    z_SetupBuilder.exit)N)rQ   rR   rS   rx   r~   r&   r|   r   r   r   r   r   rw     s
   
rw   c                   @   s   e Zd ZdddZdd ZdS )_RunOnceNc                 C   s   t | | d S r   )r   r&   r<   r   r   r   r&     s    z_RunOnce.__init__c                 G   s0   |d kr| j d k	rt  tj| |f|  d S r   )r!   r0   rd   r   rA   r$   rD   rE   r   r   r   rA     s    z_RunOnce.__exit__)Nr   r   r   r   r   r     s   
r   c                   @   s.   e Zd Zd
ddZdd Zdd Zdd	 ZdS )ri   Nc                 C   s   t | | || _d| _d S NF)r   r&   _stopped_ranrj   r   r   r   r&     s    z_StopGuard.__init__c                 C   s    t | }tjd| jd| _|S NTr)   )r   	__enter__r0   r,   r   r$   rr   r   r   r     s    
z_StopGuard.__enter__c                 G   s4   |d krd| _ tjd| jd tj| |f|  d S )NTFr)   )r   r0   r,   r   r   rA   r   r   r   r   rA     s    z_StopGuard.__exit__c                 C   s   | j std| jS )z
        Return a blob that will be set to scalar bool `True` after
        this net builder ran, iff it was halted early.
        zContext not used yet.)r   r   r   r4   r   r   r   has_stopped  s    z_StopGuard.has_stopped)NN)rQ   rR   rS   r&   r   rA   r   r   r   r   r   ri     s   
ri   c                   @   s.   e Zd Zd
ddZdd Zdd Zdd	 ZdS )re   Nc                 C   sX   t j| |dd |d k	rNtd| _td| _t|tjr@|nt|| _	nd | _	d S )NT)r"   rH   r   )
r   r&   r0   r,   _inc_iterr6   r   r+   
_num_itersrf   r   r   r   r&   (  s    z_Loop.__init__c                 C   s*   | j d k	std| jd k	s$td| jS )Nz/This loop does not have a number of iterations.z2iter() must be called from inside the loop context)r   r   r   r4   r   r   r   iter3  s    z
_Loop.iterc                 C   s0   t | }| jd k	r,tt| j| jg |S r   )r   r   r   r0   r3   ZGEr   )r$   Zbuilderr   r   r   r   :  s    

z_Loop.__enter__c                 G   sD   |d kr.| j d k	r.|  | j| jg| jg tj| |f|  d S r   )r   r*   ZAddr   r   r   rA   )r$   r   rE   r   r   r   rA   @  s    z_Loop.__exit__)NN)rQ   rR   rS   r&   r   r   rA   r   r   r   r   re   '  s   
re   c                   @   s2   e Zd Zd
ddZdd ZdddZddd	ZdS )rl   Nc                 C   sp   t | | |s|st|d k| _|d krDt|| _td| _n(|| _|d krV|nt	|t|g| _d S r   )
r   r&   r   _is_elser0   ZNot
_else_blobr,   _already_ranr1   )r$   	cond_blobr   r   r   r   r   r&   G  s    
z_RunIf.__init__c                 C   s*   t | }t| j tjd| jd |S r   )r   r   r0   r3   r   r,   r   r   r   r   r   r   S  s    
z_RunIf.__enter__c                 C   s.   | j rtdt t||p"| j| jdS )NzElse not allowed for an Else.r   r   r   r   r   r   r;   rl   r   r   rm   r   r   r   ElifY  s    
  z_RunIf.Elifc                 C   s,   | j rtdt t|p | j| jdS )NzElif not allowed for an Else.r   r   r<   r   r   r   rr   ^  s    z_RunIf.Else)NNN)N)N)rQ   rR   rS   r&   r   r   rr   r   r   r   r   rl   F  s   

rl   c                   @   s*   e Zd ZdZd	ddZdd Zdd ZdS )
ro   z6
    Generates a single net that uses If operator
    Nc                 C   s2   t j| |dd |std|| _d | _d | _d S )NTr   r#   z/Conditional blob is not specified for an If net)r   r&   r   
_cond_blob	_then_net	_else_net)r$   r   r   r   r   r   r&   h  s
    z_RunIfNet.__init__c                 C   s   t | |S r   )r   r;   r7   r   r   r   r;   o  s    z_RunIfNet.addc                 G   s   |d krn| j }|   t|| j| _| js8td| _t| jd }t	|| j
| j| j| j || _|g| _ tj| |f|  d S )NZempty_then_netz/if_net)r   r9   r   rC   r   r   r   r.   r   r   r   r   r   rA   )r$   r   rE   Z
_then_netsZif_netr   r   r   rA   r  s"      z_RunIfNet.__exit__)N)rQ   rR   rS   rT   r&   r;   rA   r   r   r   r   ro   d  s   
ro   c                   @   s"   e Zd ZdZdddZdd ZdS )rq   z+
    Else branch for _RunIfNet builder
    Nc                 C   sV   t j| |dd t jdd}|r>t|jdkr>t|jd tsFtd|jd | _d S )NTr   Fr	   r   zInvalid use of Else builder)	r   r&   r   rB   r   r6   ro   r   _if_builderr$   r   r%   r   r   r   r&     s    z_RunElseNet.__init__c                 G   s   |d krp| j }|   t|| j| j_| jjrpt| j	d }t
|| jj| j| jj| jj || j_|g| j_ tj| |f|  d S )Nz/if_else_net)r   r9   r   rC   r   r   r   r   r.   r   r   r   r   r   rA   )r$   r   rE   Z
_else_netsZif_else_netr   r   r   rA     s&     
z_RunElseNet.__exit__)NrQ   rR   rS   rT   r&   rA   r   r   r   r   rq     s   
rq   c                   @   s"   e Zd ZdZdddZdd ZdS )rs   z9
    Generates a single net that uses While operator
    Nc                 C   s   t j| |dd d | _d S )NTr   )r   r&   _cond_builderr<   r   r   r   r&     s    z_RunWhileNet.__init__c                 G   s   |d kr| j std| j j}| j j}| j}|   t|| j}|sPt	
d}t	
| jd }t||| j|| || _|g| _tj| |f|  d S )Nz/Condition builder must be specified in While opZempty_loop_body_netz
/while_net)r   r   r   	_cond_netr   r9   r   rC   r   r   r.   r   r   r   rA   )r$   r   rE   r   r   Z	loop_bodyZloop_body_netZ	while_netr   r   r   rA     s,     

 z_RunWhileNet.__exit__)Nr   r   r   r   r   rs     s   
rs   c                   @   s"   e Zd ZdZdddZdd ZdS )ru   z
    Computes loop's condition, used in the context of WhileNet.
    Last operator must have a single scalar boolean output that will be used
    as a condition value, no other blobs created in the condition net are
    visible outside of it
    Nc                 C   sl   t j| |dd t jdd}|r*t|ts2td|jr@tdt|jdksVtd| |_d | _	d | _
d S )	NTr   Fr	   z%Invalid use of loop condition builderz*Multiple loop condition builders specifiedr   z=Condition definition must be specified before the loop's body)r   r&   r   r6   rs   r   r   rB   r   r   r   r   r   r   r   r&     s    z_RunWhileCondition.__init__c                 G   s   |d kr| j }|   t|| j| _| js4tdt| j j	dksPtd| j j	d }t|j
dksvtdtj|j
d d d| _| j| _| jg| _ tj| |f|  d S )Nz Invalid loop condition specifiedr   zInvalid condition netr   rH   )r   r(   )r   r9   r   rC   r   r   r   rB   rL   opoutputr   r+   r   r   rA   )r$   r   rE   Zcondition_bodyZlast_opr   r   r   rA     s     
z_RunWhileCondition.__exit__)Nr   r   r   r   r   ru     s   
ru   N)r_   r   r   Zcaffe2.python.taskr   r   Zcaffe2.python.control_ops_utilr   r   ZManagedr   objectrW   r0   r   rw   r   ri   re   rl   ro   rq   rs   ru   r   r   r   r   <module>   s$    B  
!  