B
    һd_<                 @   s   d Z ddlmZ ddlmZ ddlmZ dd Zdd Z	d	d
 Z
dd Zdd Zdd ZG dd deZG dd deZdd ZG dd deZdd ZdS )z=Classes and methods for processing debugger-decorated graphs.    )	graph_pb2)op_def_registry)
tf_loggingc             C   sR   d| krF|  dsF| d| d }t| | dd d }||fS | dfS dS )a  Get the node name from a string that can be node or tensor name.

  Args:
    name: An input node name (e.g., "node_a") or tensor name (e.g.,
      "node_a:0"), as a str.

  Returns:
    1) The node name, as a str. If the input name is a tensor name, i.e.,
      consists of a colon, the final colon and the following output slot
      will be stripped.
    2) If the input name is a tensor name, the output slot, as an int. If
      the input name is not a tensor name, None.
  :N   )endswithrfindint)name	node_nameoutput_slot r   Z/var/www/html/venv/lib/python3.7/site-packages/tensorflow/python/debug/lib/debug_graphs.pyparse_node_or_tensor_name   s
    r   c             C   s   t | \}}|S )N)r   )element_namer   _r   r   r   get_node_name-   s    r   c             C   s   t | \}}|dk	r|S dS )a  Get the output slot number from the name of a graph element.

  If element_name is a node name without output slot at the end, 0 will be
  assumed.

  Args:
    element_name: (`str`) name of the graph element in question.

  Returns:
    (`int`) output slot number.
  Nr   )r   )r   r   r   r   r   r   get_output_slot2   s    r   c             C   s
   |  dS )a=  Determine whether a node name is that of a debug Copy node.

  Such nodes are inserted by TensorFlow core upon request in
  RunOptions.debug_options.debug_tensor_watch_opts.

  Args:
    node_name: Name of the node.

  Returns:
    A bool indicating whether the input argument is the name of a debug Copy
    node.
  Z__copy_)
startswith)r   r   r   r   is_copy_nodeB   s    r   c             C   s
   |  dS )a/  Determine whether a node name is that of a debug node.

  Such nodes are inserted by TensorFlow core upon request in
  RunOptions.debug_options.debug_tensor_watch_opts.

  Args:
    node_name: Name of the node.

  Returns:
    A bool indicating whether the input argument is the name of a debug node.
  __dbg_)r   )r   r   r   r   is_debug_nodeR   s    r   c             C   s   d}| }| |std|  |t|d }|ddk rHtd|  ||dd d }|d|d }t||dd d }|d|d }|ddkrtd	|  |d|d }t||dd d }||||fS )
a~  Parse the name of a debug node.

  Args:
    node_name: Name of the debug node.

  Returns:
    1. Name of the watched node, as a str.
    2. Output slot index of the watched tensor, as an int.
    3. Index of the debug node, as an int.
    4. Name of the debug op, as a str, e.g, "DebugIdentity".

  Raises:
    ValueError: If the input node name is not a valid debug node name.
  r   z'Invalid prefix in debug node name: '%s'Nr      zInvalid debug node name: '%s'r   r   z,Invalid tensor name in debug node name: '%s')r   
ValueErrorlencountrindexr	   index)r   prefixr
   Zdebug_opZdebug_op_indexZwatched_node_nameZwatched_output_slotr   r   r   parse_debug_node_namea   s     
r   c               @   s   e Zd ZdS )GraphTracingReachedDestinationN)__name__
__module____qualname__r   r   r   r   r       s   r    c               @   s2   e Zd ZdZdddZdd Zdd Zd	d
 ZdS )DFSGraphTracerz,Graph input tracer using depth-first search.Nc             C   s.   || _ || _g | _g | _d| _g | _|| _dS )a  Constructor of _DFSGraphTracer.

    Args:
      input_lists: A list of dicts. Each dict is an adjacency (input) map from
        the recipient node name as the key and the list of input node names
        as the value.
      skip_node_names: Optional: a list of node names to skip tracing.
      destination_node_name: Optional: destination node name. If not `None`, it
        should be the name of a destination not as a str and the graph tracing
        will raise GraphTracingReachedDestination as soon as the node has been
        reached.

    Raises:
      GraphTracingReachedDestination: if stop_at_node_name is not None and
        the specified node is reached.
    r   N)_input_lists_skip_node_names_inputs_visited_nodes_depth_count_depth_list_destination_node_name)selfZinput_listsZskip_node_namesZdestination_node_namer   r   r   __init__   s    zDFSGraphTracer.__init__c             C   s   |  j d7  _ t|}|| jkr&t || jkr4dS || jkrBdS | j| x^| jD ]T}||krdqVxD|| D ]8}t|| jkrqn| j| | j	| j  | 
| qnW qVW |  j d8  _ dS )a  Trace inputs.

    Args:
      graph_element_name: Name of the node or an output tensor of the node, as a
        str.

    Raises:
      GraphTracingReachedDestination: if destination_node_name of this tracer
        object is not None and the specified node is reached.
    r   N)r)   r   r+   r    r&   r(   appendr%   r'   r*   trace)r,   Zgraph_element_namer   Z
input_listinpr   r   r   r/      s&    


zDFSGraphTracer.tracec             C   s   | j S )N)r'   )r,   r   r   r   inputs   s    zDFSGraphTracer.inputsc             C   s   | j S )N)r*   )r,   r   r   r   
depth_list   s    zDFSGraphTracer.depth_list)NN)r!   r"   r#   __doc__r-   r/   r1   r2   r   r   r   r   r$      s    
$r$   c             C   s8   d}x| j D ]}|jr|j}P qW |dkr4td |S )z,Infer device name from a partition GraphDef.NzsFailed to infer device name from partition GraphDef: none of the nodes of the GraphDef has a non-empty device name.)nodedeviceloggingwarn)Z	graph_defdevice_namer4   r   r   r   _infer_device_name   s    r9   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 Z	dd Z
dd Zdd Zedd Zedd Zedd Zedd Zedd Zedd  Zed!d" Zed#d$ Zed%d& Zed'd( Zed)d* ZdS ),
DebugGraphz&Represents a debugger-decorated graph.Nc             C   s   || _ d | _i | _i | _i | _i | _i | _i | _i | _i | _	g | _
i | _|| _| js^t|| _x|jD ]}| | qfW |   |   | |   |   d S )N)_debug_graph_def_non_debug_graph_def_node_attributes_node_inputs_node_reversed_ref_inputs_node_ctrl_inputs_node_recipients_node_ctrl_recipients_node_devices_node_op_types_copy_send_nodes	_ref_args_device_namer9   r4   _process_debug_graph_node%_prune_non_control_edges_of_debug_ops!_prune_control_edges_of_debug_ops*_prune_nodes_from_input_and_recipient_maps_get_copy_nodes_populate_recipient_maps)r,   debug_graph_defr8   r4   r   r   r   r-      s*    
zDebugGraph.__init__c             C   sB  t |jrdS |j| jkr.td| j|jf |j| j|j< g | j|j< g | j|j< g | j|j< g | j	|j< |j| j
krt | j
|j< | j
|j |jr|jn| j |j| j|j< | || j|j< xv|jD ]l}t|r|jdks|jdkr| j|j |dr(|dd }| j|j | q| j|j | qW dS )zProcess a node from the debug GraphDef.

    Args:
      node: (NodeDef) A partition-graph node to be processed.

    Raises:
      ValueError: If duplicate node names are encountered.
    Nz&Duplicate node name on device %s: '%s'Z_SendZ_Retval^r   )r   r
   r>   r   rG   attrr=   r@   rA   rB   rC   setaddr5   oprD   _get_ref_argsrF   inputr   rE   r.   r   )r,   r4   r0   Zcinpr   r   r   rH     s.    	
z$DebugGraph._process_debug_graph_nodec             C   sd   t |j}|dkrg S g }xBt|jD ]4\}}|jr(|dkrD|jnd|j|f }|| q(W |S )zDetermine whether an input of an op is ref-type.

    Args:
      node: A `NodeDef`.

    Returns:
      A list of the arg names (as strs) that are ref-type.
    Nr   z%s:%d)r   getrS   	enumerate
output_argZis_refr
   r.   )r,   r4   Zop_defZref_argsirX   Zarg_namer   r   r   rT   3  s    	zDebugGraph._get_ref_argsc             C   s*   g }x | j D ]}t|r|| qW |S )z(Find all Copy nodes in the loaded graph.)r>   r   r.   )r,   Z
copy_nodesr4   r   r   r   rL   G  s
    zDebugGraph._get_copy_nodesc             C   sR   xL| j D ]B}| j | }x2t|D ]&\}}t|r | j | d }|||< q W qW dS )zPrune (non-control) edges related to debug ops.

    Prune the Copy ops and associated _Send ops inserted by the debugger out
    from the non-control inputs and output recipients map. Replace the inputs
    and recipients with original ones.
    r   N)r>   rW   r   )r,   r4   r1   rY   r0   Zorig_inpr   r   r   rI   O  s    
z0DebugGraph._prune_non_control_edges_of_debug_opsc             C   sZ   xT| j D ]J}| j | }g }x|D ]}t|r || q W x|D ]}|| q@W qW dS )z-Prune control edges related to the debug ops.N)r@   r   r.   remove)r,   r4   ctrl_inputsZdebug_op_inputsctrl_inpZdebug_op_inpr   r   r   rJ   `  s    


z,DebugGraph._prune_control_edges_of_debug_opsc             C   s   x| j D ]v}| j | }xf|D ]^}t|}|| jkr<g | j|< | j| | || jkr|| jkrjg | j|< | j| | qW qW xV| jD ]L}| j| }x<|D ]4}|| jkrq|| jkrg | j|< | j| | qW qW dS )zPopulate the map from node name to recipient(s) of its output(s).

    This method also populates the input map based on reversed ref edges.
    N)	r>   r   rA   r.   rF   r?   r@   rE   rB   )r,   r4   r1   r0   r[   r\   r   r   r   rM   k  s&    











z#DebugGraph._populate_recipient_mapsc             C   s2   x,|D ]$}| j |= | j|= | j|= | j|= qW dS )zPrune nodes out of input and recipient maps.

    Args:
      nodes_to_prune: (`list` of `str`) Names of the nodes to be pruned.
    N)r>   r@   rA   rB   )r,   Znodes_to_pruner4   r   r   r   rK     s
    
z5DebugGraph._prune_nodes_from_input_and_recipient_mapsc             C   s   | j r
dS t | _ x| jjD ]}t|jst|jr8q| j j }|	| |j
dd= x | j|j D ]}|j
| qhW x$| j|j D ]}|j
d|  qW qW dS )zReconstruct non-debug GraphDef.

    Non-debug GraphDef means the original GraphDef without the Copy* and Debug
    nodes inserted by the debugger.
    NrO   )r<   r   ZGraphDefr;   r4   r   r
   r   rR   ZCopyFromrU   r>   r.   r@   )r,   r4   new_noder0   r\   r   r   r    _reconstruct_non_debug_graph_def  s    

z+DebugGraph._reconstruct_non_debug_graph_defc             C   s   | j S )N)rG   )r,   r   r   r   r8     s    zDebugGraph.device_namec             C   s   | j S )z The debugger-decorated GraphDef.)r;   )r,   r   r   r   rN     s    zDebugGraph.debug_graph_defc             C   s   |    | jS )zFThe GraphDef without the Copy* and Debug* nodes added by the debugger.)r^   r<   )r,   r   r   r   non_debug_graph_def  s    zDebugGraph.non_debug_graph_defc             C   s   | j S )N)rC   )r,   r   r   r   node_devices  s    zDebugGraph.node_devicesc             C   s   | j S )N)rD   )r,   r   r   r   node_op_types  s    zDebugGraph.node_op_typesc             C   s   | j S )N)r=   )r,   r   r   r   node_attributes  s    zDebugGraph.node_attributesc             C   s   | j S )N)r>   )r,   r   r   r   node_inputs  s    zDebugGraph.node_inputsc             C   s   | j S )N)r@   )r,   r   r   r   node_ctrl_inputs  s    zDebugGraph.node_ctrl_inputsc             C   s   | j S )N)r?   )r,   r   r   r   node_reversed_ref_inputs  s    z#DebugGraph.node_reversed_ref_inputsc             C   s   | j S )N)rA   )r,   r   r   r   node_recipients  s    zDebugGraph.node_recipientsc             C   s   | j S )N)rB   )r,   r   r   r   node_ctrl_recipients  s    zDebugGraph.node_ctrl_recipients)N)r!   r"   r#   r3   r-   rH   rT   rL   rI   rJ   rM   rK   r^   propertyr8   rN   r_   r`   ra   rb   rc   rd   re   rf   rg   r   r   r   r   r:      s*   
+r:   c             C   s
   t | jS )a  Reconstruct original (non-debugger-decorated) partition GraphDef.

  This method strips the input `tf.compat.v1.GraphDef` of the Copy* and
  Debug*-type nodes inserted by the debugger.

  The reconstructed partition graph is identical to the original (i.e.,
    non-debugger-decorated) partition graph except in the following respects:
      1) The exact names of the runtime-inserted internal nodes may differ.
         These include _Send, _Recv, _HostSend, _HostRecv, _Retval ops.
      2) As a consequence of 1, the nodes that receive input directly from such
         send- and recv-type ops will have different input names.
      3) The parallel_iteration attribute of while-loop Enter ops are set to 1.

  Args:
    debug_graph_def: The debugger-decorated `tf.compat.v1.GraphDef`, with the
      debugger-inserted Copy* and Debug* nodes.

  Returns:
    The reconstructed `tf.compat.v1.GraphDef` stripped of the debugger-inserted
    nodes.
  )r:   r_   )rN   r   r   r   reconstruct_non_debug_graph_def  s    ri   N)r3   Ztensorflow.core.frameworkr   Ztensorflow.python.frameworkr   Ztensorflow.python.platformr   r6   r   r   r   r   r   r   	Exceptionr    objectr$   r9   r:   ri   r   r   r   r   <module>   s   )M u