
    2Vh@                         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
  ed       G d d	e
             Zd
 Zd Zd Zd Zy)    N)tree)keras_exportKerasTensor)backend)	Operationzkeras.Functionc                   t     e Zd ZdZd fd	Zed        Zed        Zed        Zd Z	d Z
d Zdd	Zd
 Z xZS )Functiona  Class that encapsulates a computation graph of Keras operations.

    You can use a `Function` to capture the computation graph linking
    some input tensors to some output tensors, and reapply the same
    computation on new inputs.

    A `Function` is similar to a Functional Model, with the difference
    that it is stateless (it does not track state variables)
    and does not implement the `Layer` API.

    Example:

    ```python
    input_1 = keras.KerasTensor(shape=(None, 2, 3))
    input_2 = keras.KerasTensor(shape=(None, 2, 3))
    x = input_1 + input_2
    output = keras.ops.sigmoid(x)
    fn = keras.Function(inputs=[input_1, input_2], outputs=output)

    input_1_val = np.random.random((4, 2, 3))
    input_2_val = np.random.random((4, 2, 3))
    output_val = fn([input_1_val, input_2_val])
    ```

    Args:
        inputs: `KerasTensor` instance or nested structured of
            `KerasTensor` instances.
        outputs: `KerasTensor` instance or nested structured of
            `KerasTensor` instances. They should be computable
            given only the values of `inputs`.
        name: String. The name of the function.
    c                    t         
|   |       t               dk(  rt        | dd      }d| _        t        j                  d |      | _        t        j                  d |      | _        t        j                  |      | _
        t        j                  |      | _        | j                  st        d| d	|       | j                  st        d
| d	|       t               dk(  r| _        t        | j                  | j                        \  }}}}|| _        || _        || _        || _        | j                  D ]D  }	|	j$                  j&                  s|	j$                  j&                  j(                  r;t        d       y )N)name
tensorflow_self_setattr_trackingTFc                     | S N xs    F/home/dcms/DCMS/lib/python3.12/site-packages/keras/src/ops/function.py<lambda>z#Function.__init__.<locals>.<lambda>9   s    1     c                     | S r   r   r   s    r   r   z#Function.__init__.<locals>.<lambda>:   s    A r   z4`inputs` argument cannot be empty. Received:
inputs=z	
outputs=z5`outputs` argument cannot be empty. Received:
inputs=z#`inputs` not connected to `outputs`)super__init__r   getattrr   r   map_structure_inputs_struct_outputs_structflatten_inputs_outputs
ValueError	map_graph_nodes_nodes_by_depth_operations_operations_by_depth_keras_history	operation_outbound_nodes)selfinputsoutputsr   r   nodesnodes_by_depth
operationsoperations_by_depthinput	__class__s             r   r   zFunction.__init__-   s~   d#9$
 &-.&" +0D'"00fE#11+wG||F+W-||  "")% 
 }}  "")%  9$*@D'CLLL$--D
@
,? -%$7!\\ 	HE$$..,,66FF !FGG	Hr   c                      | j                   d d  S r   )r%   r*   s    r   r/   zFunction.operations[   s    ""r   c                     | j                   S )z1Flat list of the symbolic inputs of the Function.)r   r4   s    r   r+   zFunction.inputs_   s     ||r   c                     | j                   S )z2Flat list of the symbolic outputs of the Function.)r    r4   s    r   r,   zFunction.outputsd   s     }}r   c                 2   | j                  |       d}t        t        j                  |      | j                        D ]"  \  }}|j
                  |j
                  k7  s d} n |r!t        j                  d | j                        S | j                  |d       S )NTFc                 D    t        | j                  | j                        S )N)shapedtype)r   r9   r:   r   s    r   r   z.Function.compute_output_spec.<locals>.<lambda>t   s    +AGG177C r   c                     | j                   S r   )compute_output_specops    r   r   z.Function.compute_output_spec.<locals>.<lambda>|   s    B,B,B r   operation_fn)	_assert_input_compatibilityzipr   r   r   r9   r   r   _run_through_graph)r*   r+   shortcutr   x_refs        r   r<   zFunction.compute_output_speci   s    ((0 DLL0$,,? 	HAuww%++% 	 %%C$$  &&!B ' 
 	
r   c                 &   t        j                  d |      }t        t        j                  |      | j                        D ]'  \  }}|j
                  |_        |j                  |_        ) | j                  |      }t        j                  d |      S )Nc                     t        |       S )Nr9   r   r   s    r   r   z/Function.compute_output_shape.<locals>.<lambda>   s    k* r   c                     | j                   S r   rH   r   s    r   r   z/Function.compute_output_shape.<locals>.<lambda>   s
    AGG r   )r   map_shape_structurerB   r   r   r:   _dtypesparse_sparser<   r   )r*   input_shapeinput_shape_structr   rE   output_specs         r   compute_output_shapezFunction.compute_output_shape   s     "55*K

 DLL);<dllK 	%HAu{{AHAI	% ../AB!!"3[AAr   c                 L    | j                  |       | j                  |d       S )z'Computes output tensors for new inputs.c                     | S r   r   r=   s    r   r   zFunction.call.<locals>.<lambda>   s    r r   r?   )rA   rC   )r*   r+   s     r   callzFunction.call   s&    ((0&&vM&JJr   c                 :   t        j                  |      }i t        | j                  |      D ]  \  }}|t	        |      <    | j
                  }t        |j                               }|j                  d       |D ]  }||   }	|	D ]  }
|
j                  r|
j                  rt        fd|
j                  D              r;|
j                  j                        \  }} ||
j                        }| ||g|i |}n ||i |}t        |
j                  t        j                  |            D ]  \  }}|t	        |      <      g }| j                  D ]  }|j!                  t	        |                ! t        j"                  | j$                  |      S )zExecute the graph.

        At each node we compute outputs via
        `operation_fn(node.operation)(*args, **kwargs)`.
        Treversec              3   8   K   | ]  }t        |      v  y wr   )id).0r   tensor_dicts     r   	<genexpr>z.Function._run_through_graph.<locals>.<genexpr>   s     LAr!uK/Ls   )r   r   rB   r+   rY   r$   listkeyssortr(   is_inputanyinput_tensors	argumentsfill_inr,   appendpack_sequence_asr   )r*   r+   r@   call_fnr   yr.   
depth_keysdepthr-   nodeargskwargsr>   r,   output_tensorsr[   s                   @r   rC   zFunction._run_through_graph   s    f% V, 	#DAq!"K1	# --.--/0
% 	+E"5)E +~~L9K9KLL#~~55kBf!$..1&%b:4:6:G $1&1G  dll7.CD +DAq)*K1&++	+(  	6A!!+be"45	6 $$T%9%9>JJr   c                    	 t        j                  || j                         t	        t        j
                  |      | j                        D ]  \  }}t        |j                        t        |j                        k7  rIt        | j                  j                   d|j                   d|j                   d|j                   d      t	        |j                  |j                        D ]Y  \  }}|	|||k7  st        | j                  j                   d|j                   d|j                   d|j                   d        y # t        $ r t        d| j                   d|       w xY w)NzOFunction was called with an invalid input structure. Expected input structure: z
Received input structure: z, was passed incompatible inputs. For input 'z', expected shape z+, but received instead a tensor with shape .)r   assert_same_structurer   r!   rB   r   r   lenr9   r2   __name__r   )r*   r+   r   rE   dimref_dims         r   rA   z$Function._assert_input_compatibility   sr   	&&vt/B/BC DLL0$,,? 	HAu177|s5;;// ~~../ 077<zzl C&&+kk] 333477)1>  !$AGGU[[ 9 W&3?g~(#~~667 8??Dzzl K..3kk] ;;;<77)1F 	  	--1-@-@,A B--3H6 	s    E %E)r   )rs   
__module____qualname____doc__r   propertyr/   r+   r,   r<   rQ   rT   rC   rA   __classcell__)r2   s   @r   r
   r
   
   si    B,H\ # #    
,BK
)KVr   r
   c                 H    t        t        |             dz   t        |      z   S )Nz_ib-)strrY   )r>   
node_indexs     r   make_node_keyr~      s    r"v;#j/11r   c                 &   t        | |      \  }|D ch c];  }t        |j                  |j                  j                  j	                  |            = }}i }i }t        |      D ]  }|j                  |d      }|j                  |j                  d      }t        ||      }|||j                  <   |||<   |j                  D ]&  }	|j                  |	d      }t        |dz   |      ||	<   (  | D ]P  }
|
j                  d   }|s||vsd||<   d|<   d||j                  d   <   |j                  t        |d             R t        j                  t              }|j                         D ]  \  }}||   j!                  |        t        j                  t              }|j                         D ]  \  }}||   j!                  |        t        |j#                               }|j%                  d       g }|D ]-  }||   }|j%                  fd       |j'                  |       / t        |j#                               }|j%                  d       t)               }| D ]  }|j                  |        g }|D ]  }||   D ]  }t+        j,                  |j.                        D ]K  }||vr |j                  }t1        d| d	| d
|       |j!                  |j                  j2                         M t+        j,                  |j4                        D ]  }|j                  |          |D cg c]  }|j2                   }}|D ]7  }|j7                  |      dk7  st1        d| d|j7                  |       d       ||||fS c c}w c c}w )a  Validates a graph's topology and gather its operations and nodes.

    Args:
        inputs: List of input tensors.
        outputs: List of outputs tensors.

    Returns:
        A tuple `(nodes, nodes_by_depth, operations, operations_by_depth)`.
        - nodes: set of Node instances
        - nodes_by_depth: dict mapping ints (depth) to lists of node instances.
        - operations: list of Operation instances.
        - operations_by_depth: dict mapping ints (depth) to lists of Operation
            instances.
    r      TrV   c                     |    S r   r   )r   operation_indicess    r   r   zmap_graph.<locals>.<lambda>+  s    0A!0D r   )keyz2Graph disconnected: cannot find parent for tensor z at operation 'zB'. The following previous operations were accessed without issue: z
The name "z
" is used z: times in the model. All operation names should be unique.)
_build_mapr~   r(   _inbound_nodesindexreversed
setdefaultgetmaxparent_nodesr'   addcollectionsdefaultdictr]   itemsre   r^   r_   extendsetr   r   rb   r!   r   r,   count)r+   r,   nodes_in_decreasing_depthrk   network_nodesnodes_depthsoperations_depthsrj   previous_depthnode_depinput_tinput_operationr.   r0   r(   ri   r/   operations_for_depthcomputable_tensorsr   operations_with_complete_input	all_namesr   r   s                          @r   r"   r"      s	   " 4>fg3N00 . 	dnndnn&C&C&I&I$&OPM 
 L23 D''a0 +..t~~qA
 E>*,1$..)"T
 )) 	DH)--h:N%(N%CL"	D#D0  A!0036GG12o.13o.>?L77:;mOQ?@A !,,T2N#))+ +eu$$T*+ &11$7-335 5	5E")))45 )..01JOODO! J 0259 	!!&D!E./0 n))+,JOODO!
  "q!" &(" *"5) 	*D\\$"4"45 	K.. $I$""#OI; ?**H)IK  /55dnn6I6IJ	K \\$,,/ *"&&q)*	**$ 2<<I<I< ??4 A%TF*Y__T-B,C DL L  .*6IIIIz =s   A N	2Nc           	          t               }t               }g }i }t        j                  |      D ]  }t        | |||||        ||fS )a  Topologically sort nodes in order from inputs to outputs.

    It uses a depth-first search to topologically sort nodes that appear in the
    _keras_history connectivity metadata of `outputs`.

    Args:
        outputs: the output tensors whose _keras_history metadata should be
                walked. This may be an arbitrary nested structure.

    Returns:
        A tuple like (ordered_nodes, operation_to_first_traversal_index)
        ordered_nodes: list of nodes appearing in the keras history,
            topologically sorted from original inputs to the `outputs`.
            (If outputs have different sets of ancestors, the inputs to one
            output may appear after a different output).
        operation_to_first_traversal_index:
            A dict mapping operation to the traversal index in the DFS where it
            is seen. Note: if a operation is shared by several nodes, the dict
            will onlystore the index corresponding to the *first* time the
            operation seen.
    )r   r   r   _build_map_helper)r+   r,   finished_nodesnodes_in_progressr   r   outputs          r   r   r   V  s_    , UN ",,w' 
%	

 %&777r   c           	         |j                   \  }}}|sy|j                  |   }	|	|v ry|	|v rt        d| d|j                   d      ||vrt	        |      ||<   |j                  |	       |	j                  s8|t        j                  |       vr!|	j                  D ]  }t        | |||||        |j                  |	       |j                  |	       |j                  |	       y)z"Recursive helper for `_build_map`.NzTensor z from operation 'z' is part of a cycle.)r'   r   r!   r   rr   r   r`   r   r   rb   r   removere   )
r+   tensorr   r   r   r   r(   r}   _rk   s
             r   r   r   |  s    			##J/D ~   fX.y~~.> ? 
 	
 ))'*+<'=)$ $==V4<<+??(( 	F!)!	 tT"$$T*r   )r   	keras.srcr   keras.src.api_exportr   keras.src.backendr   keras.src.backend.configr   keras.src.ops.operationr   r
   r~   r"   r   r   r   r   r   <module>r      sT      - ) , - Ky K  K\2vJr#8L1+r   