
    2Vh              	           d dl Z d dlmZ d dlmZ d dlmZ  G d d      Z G d d e j                  dg d	            Z	d
 Z
y)    N)tree)KerasTensor)SymbolicArgumentsc                   P    e Zd ZdZ	 ddZd Zed        Zed        Zed        Z	y)	Nodea  A `Node` describes an operation `__call__()` event.

    A Keras Function is a DAG with `Node` instances as nodes, and
    `KerasTensor` instances as edges. Nodes aren't `Operation` instances,
    because a single operation could be called multiple times, which would
    result in graph cycles.

    A `__call__()` event involves input tensors (and other input arguments),
    the operation that was called, and the resulting output tensors.
    A `Node` will include all this information.

    Since a single `Operation` could be called multiple times,
    the `Node` instances are stored on operations as a list.
    Each time an operation is called, a node is added to `op._inbound_nodes`.
    Each time the output of an operation is used by another operation,
    a node is added to `op._outbound_nodes`.

    Every `KerasTensor` instance has a `KerasHistory` object attached,
    which tracks the `Node` that records the `__call__()` event that created
    the tensor. By recursively walking through `Node` instances
    via the `KerasHistory` metadata of `KerasTensor` instances, once can
    retrieve the entire DAG of a Keras Function.

    Args:
        operation: The Operation that was called in the `op.__call__()`
            event that this node represents.
        call_args: The positional arguments the operation was called with.
        call_kwargs: The keyword arguments the operation was called with.
        outputs: The output tensors of the `op.__call__()` call.
    Nc                 `   || _         t        |i || _        |g nt        j                  |      | _        | j
                  D ]#  }t        |t              rt        d| d|        t        d | j                  j                  D              }|s;| j                  j                  D ]"  }t        |d      rt        d dd      |_        $ | j                   j                  j                  |        | j                  j                  D ]6  }|j                  j                   }	|	|	j                   j                  |        8 |sRt#        | j                   j                        dz
  }
t%        | j
                        D ]  \  }}t        ||
|      |_         | j                  j                   | _        y )Nz1All operation outputs must be tensors. Operation z- returned a non-tensor. Non-tensor received: c              3   6   K   | ]  }|j                      y wN)record_history).0xs     B/home/dcms/DCMS/lib/python3.12/site-packages/keras/src/ops/node.py	<genexpr>z Node.__init__.<locals>.<genexpr>6   s      
%&   
s   _keras_historyr   	operation
node_indextensor_index   )r   r   	argumentsr   flattenoutputs
isinstancer   
ValueErroranykeras_tensorshasattrKerasHistoryr   _inbound_nodesappend_outbound_nodeslen	enumerateis_input)selfr   	call_argscall_kwargsr   r   zero_historytensorkt
inbound_opr   is               r   __init__zNode.__init__(   s    #*IEE$_r$,,w2G 	Aa- !!* ,,,-30 	  
*...*F*F
 

 ..66 v'78,8"&11-F) 	%%,,T2.... 	8B**44J%**11$7	8 T^^::;a?J&t||4 	6(4'JQ)% !NN888    c                 N    d| j                   j                   dt        |        dS )Nz<Node operation=z, id=>)r   nameidr%   s    r   __repr__zNode.__repr__T   s&    !$.."5"5!6eBtH:QGGr.   c                 .    | j                   j                  S r
   )r   r   r3   s    r   input_tensorszNode.input_tensorsW   s    ~~+++r.   c                     | j                   S r
   )r   r3   s    r   output_tensorszNode.output_tensors[   s    ||r.   c                     g }| j                   j                  D ]O  }|j                  j                  }|j                  j                  }|2|j                  |j                  |          Q |S )zyThe parent `Node`s.

        Returns:
            all the `Node`s whose output this node immediately depends on.
        )r   r   r   r   r   r    r   )r%   	node_depsr*   opr   s        r   parent_nodeszNode.parent_nodes_   sl     	.... 	@B"",,B**55J~  !2!2:!>?		@
 r.   )NNN)
__name__
__module____qualname____doc__r-   r4   propertyr6   r8   r<    r.   r   r   r      sW    @ DH*9XH , ,    r.   r   c                       e Zd ZdZdZy)r   a  Tracks the Operation call that created a Tensor.

    During construction of Keras Functions, this metadata is added to
    each Tensor produced as the output of an Operation.
    This allows Keras to track how each Tensor was produced, and
    this information is later retraced by the `Function` class to
    reconstruct the Operations graph.

    Attributes:
      operation: The Operation instance that produced the Tensor.
      node_index: The specific call to the Operation that produced this Tensor.
        Operations can be called multiple times in order to share weights. A new
        node is created every time an Operation is called. The corresponding
        node that represents the call event that produced the Tensor can be
        found at `op._inbound_nodes[node_index]`.
      tensor_index: The output index for this Tensor.
        Always zero if the Operation that produced this Tensor
        only has one output. Nested structures of
        Tensors are deterministically assigned an index via `nest.flatten`.
    rB   N)r=   r>   r?   r@   	__slots__rB   r.   r   r   r   o   s    
. Ir.   r   r   c                     t        | d      S )Nr   )r   )objs    r   is_keras_tensorrG      s    3())r.   )collections	keras.srcr   keras.src.backendr    keras.src.ops.symbolic_argumentsr   r   
namedtupler   rG   rB   r.   r   <module>rM      sC      ) >d dNKC>*r.   