o
    s::j                     @  sR  U d Z ddlmZ ddlmZmZmZmZmZ ddl	Z	ddl
Zddlm  mZ ddlZddlmZmZ eejejeeeeee ee ee ee df ZeejjeejjiZde d< dEddZ!dFddZ"	dGdHddZ#dIddZ$eej%ef Z&dJd!d"Z'dKdLd'd(Z(dMd,d-Z)d.dd/dNd8d9Z*dd:dOd?d@Z+G dAdB dBZ,G dCdD dDZ-dS )Pa  Graph builder for constructing ONNX IR graphs imperatively.

This module provides imperative builders for constructing ONNX IR graphs with automatic
constant promotion, type casting, and shape inference. The GraphBuilder class enables
programmatic construction of graphs with proper scoping, constant management, and node
creation. The OpBuilder class provides dynamic op dispatching via attribute access.
    )annotations)AnyCallableMappingSequenceUnionN)_inlinerparam_manipulationzdict[type, ir.DataType]_PYTHON_TYPE_TO_DTYPEelement_typetypereturnstrc                 C  s   t | }|dur| S dS )zEReturn a short type suffix for naming constants based on Python type.N )r
   get
short_name)r   dtype r   c/home/nk/hobo-godmode/plappi-mvp/.venv/lib/python3.10/site-packages/onnxscript/_internal/builder.py_type_suffix-   s   
r   r   ir.DataTypec                 C  s   |   S )zEReturn a short type suffix for naming constants based on ir.DataType.)r   r   r   r   r   _dtype_suffix3      r   value#int | float | bool | str | Sequencetype_suffixnumintc                 C  sL   t | tr
d| S t | tttfr!|rd|  d| S d|  S d| S )a  Generate a descriptive name for a constant value.

    Args:
        value: The constant value
        type_suffix: Type suffix (e.g., 'F', 'I64')
        num: A number used for generating unique names for str/sequences

    Returns:
        A name string for the constant
    
const_str_const__	const_1d_)
isinstancer   r   floatbool)r   r   r   r   r   r   _constant_name8   s
   


r&   graphir.GraphNonec           	   
     s  dd | j D   fddt| j D }| jdd}g }|D ]7}|j}|du r3td|jd	t	j
dd
g t	dt	jj|g|g|d|j d}| j|j || q!|r~|  dkrf| dnd}|durt| || dS |D ]	}| | qvdS dS )u.  Replace every initializer in *graph* with a ``Constant`` node.

    ONNX ``ir.Function`` bodies do not support initializers — all values
    must be produced by nodes.  Call this on the function-body graph
    **before** wrapping it in :class:`ir.Function` so that any constant
    initializers (e.g. from Python literals promoted by
    :class:`GraphBuilder`) become valid ``Constant`` nodes.

    The function preserves ``ir.Value`` identity: it reuses each existing
    ``ir.Value`` object as the output of the new ``Constant`` node so that
    all downstream references remain valid.

    Graph inputs that are *also* registered as initializers (the standard
    ONNX pattern for optional inputs with default values) are skipped
    because they are explicit function parameters, not embedded constants.
    c                 S  s   h | ]}t |qS r   id.0vr   r   r   	<setcomp>_       z1lift_initializers_to_constants.<locals>.<setcomp>c                   s   g | ]
}t | vr|qS r   r*   r,   graph_input_setr   r   
<listcomp>`   s    z2lift_initializers_to_constants.<locals>.<listcomp>r      NzInitializer z has no const_valueConstantr   initializer_)inputs
attributesoutputsversionnamer   )r7   listinitializersvaluesopset_importsr   const_value
ValueErrorr;   irNodeAttrAttributeTypeTENSORpopappend	num_nodesnodeinsert_before)	r'   to_liftopset_version	new_nodesr   tensorrJ   first_existingnr   r1   r   lift_initializers_to_constantsN   s:   

	rR   specTypeSpecir.TypeAndShapec                 C  sb   t | tjr| S t| dr'|  }t |tjs%tt| dt|d|S tdt| d)a|  Convert a *TypeSpec* to an :class:`ir.TypeAndShape`.

    Accepts an :class:`ir.TypeAndShape` directly, or any object with a
    ``to_ir_type_and_shape()`` method (e.g. a
    :class:`~onnxscript.onnx_types.TensorType` subclass such as
    ``FLOAT[1024]`` or ``FLOAT['M', 'N']``).

    .. deprecated::
        Use :func:`make_value` or construct ``ir.Value`` directly instead.
    to_ir_type_and_shapez!.to_ir_type_and_shape() returned z, expected ir.TypeAndShape.zPExpected ir.TypeAndShape or an object with a to_ir_type_and_shape() method, got .)r#   rB   TypeAndShapehasattrrV   	TypeErrorr   )rS   resultr   r   r   _resolve_type_spec   s   
r\   r;   	type_specTypeSpec | Noneir.Valuec                 C  s0   |durt |}tj| |j|jdS tj| dS )a  Create an :class:`ir.Value` from a name and optional :data:`TypeSpec`.

    Similar to :func:`onnx_ir.val` but accepts a :data:`TypeSpec` (e.g.
    ``FLOAT[3, 4]``) instead of separate *dtype* and *shape* arguments.

    Example::

        x = make_value("x", FLOAT[3, 4])
        y = make_value("y")  # untyped

    Args:
        name: The value name.
        type_spec: Optional type specification.  Accepts an
            :class:`ir.TypeAndShape`, or a
            :class:`~onnxscript.onnx_types.TensorType` subclass
            (e.g. ``FLOAT[3, 4]``).

    Returns:
        A fresh :class:`ir.Value` with the given name and optional type/shape.
    N)r;   r   shaper;   )r\   rB   Valuer   r`   )r;   r]   tsr   r   r   
make_value   s   rd   r7   Sequence[ir.Value | None],tuple[list[ir.Value | None], list[ir.Value]]c                 C  s   t | }g }t|D ]7\}}|du r|tjd| d q
| dur.td|jd|jdur<td|jd|| q
||fS )u  Split an input list into trace args and graph inputs.

    For each ``None`` entry, a placeholder :class:`ir.Value` with a generated
    name (``input_0``, ``input_1``, …) is created and added to
    *graph_inputs* so that the function/graph signature declares the formal
    parameter.  The corresponding *trace_args* entry remains ``None`` so that
    the trace function can branch with ``if x is None:``.

    Returns:
        A tuple of (trace_args, graph_inputs) where trace_args preserves
        ``None`` holes and graph_inputs includes placeholders for absent
        optional inputs.

    Raises:
        ValueError: If any non-None input already has a producer or is
            already attached to a graph.
    Ninput_ra   zInput zD already has a producer node. Pass freshly created ir.Value objects.zG is already attached to a graph. Pass freshly created ir.Value objects.)	r<   	enumeraterH   rB   rb   producerrA   r;   r'   )r7   
trace_argsgraph_inputsir.   r   r   r   _split_optional_inputs   s   
rm   subgraph)r;   parenttrace_functionr   r9   Sequence[ir.Value]r?   dict[str, int]ro   GraphBuilder | Nonec             	   C  s"  t |\}}tj||g g |d}t||d}	|dur t|j|	_| |	jg|R  }
t|
ts1|
g}
t	|
t	|krHt
dt	|
 dt	| dt|
|D ];\}}|jrX|j|_|jdur}|jdury|j|jkryt
d|jd|j d	|j d
|j|_|jdur||j qM|j|
 |S )a	  Build an :class:`ir.Graph` suitable for use as a graph-valued attribute.

    This is a module-level utility that constructs a subgraph by tracing
    *trace_function*.  It is useful for building body graphs of control-flow ops
    such as ``Scan``, ``Loop``, and ``If``.

    Example - building a Scan body that adds two sequences element-wise::

        body = build_graph(
            lambda op, x, y: op.Add(x, y),
            inputs=[make_value("x", FLOAT[3, 4]), make_value("y", FLOAT[3, 4])],
            outputs=[make_value("sum", FLOAT[3, 4])],
            opset_imports={"": 23},
        )

    Args:
        trace_function: A callable with signature
            ``(op: OpBuilder, *inputs: ir.Value | None) -> ir.Value | Sequence[ir.Value]``.
            It is called once with freshly created placeholder inputs to record the
            graph topology.  ``None`` entries in *inputs* are passed through as ``None``
            to support optional inputs.
        inputs: A :class:`Sequence` of :class:`ir.Value` (or ``None`` for
            absent optional inputs).  Each ``ir.Value`` should be freshly
            created with a name and optional type/shape.  For ``None``
            entries, placeholder values are declared as formal graph inputs,
            while ``None`` is passed to *trace_function* for the
            corresponding argument position.
        outputs: A :class:`Sequence` of :class:`ir.Value` objects declaring
            the expected outputs.  After tracing, the name and type of each
            declared output are applied to the corresponding returned value.
        opset_imports: Opset version map for the subgraph (e.g.
            ``{"": 23}``).
        name: Name of the resulting :class:`ir.Graph`.
        parent: Optional parent :class:`GraphBuilder`.  When provided, the
            sub-builder's ``_root`` points to the root builder of the parent,
            so that :meth:`Parameter._realize` registers initializers in the
            root (main) graph rather than the subgraph.

    Returns:
        An :class:`ir.Graph` whose inputs and outputs are populated and whose
        nodes record the operations traced by *trace_function*.  This graph can be
        passed directly as a graph-valued attribute (e.g. the ``body`` attribute of
        a ``Scan`` or ``Loop`` node).
    )r;   r7   r9   nodesr?   ro   Nztrace_function returned z output(s), but z were declared in outputs.zOutput z: traced type z conflicts with declared type rW   )rm   rB   GraphGraphBuilderr<   _scope_stackopr#   r   lenrA   zipr;   r   r`   merge_shapesr9   extend)rp   r7   r9   r?   r;   ro   rj   rk   rn   sub_buildertrace_outputsreturned_valdeclared_valr   r   r   build_graph   sL   5



r   )r8   domainr8   0Mapping[str, ir.Attr] | Sequence[ir.Attr] | Noneir.Functionc                C  s   t |\}}tj|g g | d|d}t|}	| |	jg|R  }
|
dur:t|
ts,|
g}
|jr3td|j	|
 n|jsAtdt
| |du rLi }nt|trVt|}ndd |D }tj||||dS )	a(  Build an :class:`ir.Function` by tracing *trace_function*.

    This utility handles all boilerplate for constructing an ``ir.Function``:
    graph creation, input/output wiring, initializer lifting (so that Python
    literals work correctly inside function bodies), and attribute packaging.

    Example::

        fn = build_function(
            lambda op, x, y: op.Add(x, y),
            [make_value("x"), make_value("y")],
            domain="com.example",
            name="MyAdd",
            opset_imports={"": 23},
        )

    Args:
        trace_function: A callable with signature
            ``(op: OpBuilder, *inputs: ir.Value | None) -> ir.Value | Sequence[ir.Value] | None``.
            It is called once to trace the function body.  Return value(s)
            become function outputs.  If ``None`` is returned, the function
            uses whatever outputs were appended to ``graph.outputs`` by the
            trace function directly.
        inputs: A :class:`Sequence` of :class:`ir.Value` (or ``None`` for
            absent optional inputs).  ``None`` entries are represented by
            placeholder formal inputs in the generated function signature,
            while ``None`` is passed through to *trace_function* in the
            corresponding positions so the body can branch with
            ``if x is None``.
        domain: Function domain (e.g. ``"com.microsoft"``).
        name: Function name (e.g. ``"LinearAttention"``).
        attributes: Function-level attributes.  Accepts a
            :class:`Mapping` from name to :class:`ir.Attr`, a
            :class:`Sequence` of :class:`ir.Attr`, or ``None``.
        opset_imports: Opset version map (e.g. ``{"": 23}``).

    Returns:
        An :class:`ir.Function` with initializers automatically lifted to
        ``Constant`` nodes.
    _body)r7   r9   rt   r;   r?   Nzetrace_function both returned output values and appended to graph.outputs. Use one approach, not both.zMtrace_function returned None and did not append any outputs to graph.outputs.c                 S  s   i | ]}|j |qS r   ra   )r-   ar   r   r   
<dictcomp>  r0   z"build_function.<locals>.<dictcomp>)r   r;   r'   r8   )rm   rB   rv   rw   ry   r#   r   r9   rA   r}   rR   r   dictFunction)rp   r7   r   r;   r8   r?   rj   rk   r'   gbr   	attr_dictr   r   r   build_functionE  sD   1


r   c                   @  s  e Zd ZdZdddd
dZddddZedddZedddZedddZ	edddZ
edddZ	ddd dd(d)Z		ddddd*dd5d6Zdd8d9Zdd;d<Z	ddd?d@Z	AdddFdGZddJdKZddRdSZddVdWZddYdZZdd]d^Zd_d`ddcddZ	A		dddedfZddgddldmZddAdnddqdrZdddudvZddwdxZddzd{Zdd|d}Zdd~dZdddZ dddZ!dddZ"dddZ#dS )rw   zxImperative builder for constructing ONNX IR graphs with automatic constant promotion, type casting, and shape inference.Nru   r'   r(   ro   rs   r   r)   c                C  sl   || _ || _|d ur|jn| | _d|jvrtd|jd }| d|| _g | _|d u r4i | _i | _	d S d S )Nr   z1Input graph does not have an import for domain "")
_graph_parent_rootr?   rA   opset_op_builderrx   _constant_cache
_functions)selfr'   ro   rM   r   r   r   __init__  s   


zGraphBuilder.__init__r4   r   r   r:   r   	OpBuilderc                 C  s   t | ||S )z:Create an OpBuilder bound to the given domain and version.)r   )r   r   r:   r   r   r   r     s   zGraphBuilder.opsetc                 C     | j S N)r   r   r   r   r   ry        zGraphBuilder.opc                 C  r   )z4The parent builder, or None for a top-level builder.)r   r   r   r   r   ro        zGraphBuilder.parentc                 C  r   )z1The root (top-level) builder in the parent chain.)r   r   r   r   r   root  r   zGraphBuilder.rootc                 C  r   r   )r   r   r   r   r   r'     r   zGraphBuilder.graph(dict[ir.OperatorIdentifier, ir.Function]c                 C     | j jS r   )r   r   r   r   r   r   	functions  r   zGraphBuilder.functionsT)qualifyrO   ir.TensorProtocolr;   
str | Noner   r%   r_   c                C  sT   |du r|j }|r| |}t|j}tj||t|j|d}| jj	
| |S )aT  Register a tensor as a graph initializer in the **root** graph.

        Initializers created through this method are stored in the root graph
        so that inner scopes (subgraphs) can reference them via ONNX's
        outer-scope visibility rules.  This does not apply to the ONNX
        default-input pattern created via :meth:`input` with ``const_value``,
        which registers an initializer on the owning graph.  For function
        bodies (which cannot have initializers), apply
        :func:`lift_initializers_to_constants` before wrapping in
        :class:`ir.Function`.
        N)r;   r`   r   r@   )r;   _qualify_initializer_namerB   Shaper`   rb   
TensorTyper   r   r   register_initializer)r   rO   r;   r   r`   r   r   r   r   initializer  s   
zGraphBuilder.initializer)r   r@   metadata_propsr   ir.DataType | Noner`   ,ir.Shape | Sequence[int | str | None] | Noner   ir.TypeProtocol | Noner@   ir.TensorProtocol | Noner   dict[str, str] | Nonec                C  s<   t j||||||d}| jj| |dur| j| |S )a  Create an input to the graph and return the corresponding ir.Value.

        Args:
            name: The name of the value.
            dtype: The data type of the TensorType of the value. This is used only when type is None.
            shape: The shape of the value.
            type: The type of the value. Only one of dtype and type can be specified.
            const_value: The constant tensor that initializes the value. Supply this argument
                when you want to create an initializer. The type and shape can be obtained from the tensor.
            metadata_props: The metadata properties that will be serialized to the ONNX proto.

        Returns:
            A Value object.
        )r;   r   r`   r   r@   r   N)rB   valr   r7   rH   r   )r   r;   r   r`   r   r@   r   r   r   r   r   input  s   zGraphBuilder.inputr   c                 C  s   |r||_ | jj| dS )zAdd an output to the graph.

        Args:
            value: The ir.Value to add as an output.
            name: The name to assign to the output value. If None, no renaming is done.
        N)r;   r   r9   rH   )r   r   r;   r   r   r   
add_output  s   zGraphBuilder.add_output
VALUE_LIKEc           	        s  | j }t ttttfrO|du rtt } |f}||j	v r%|j	| S |dur-t
|nd}t |t|j	}tj ||d}|j||dd}||j	|< |S t ttfr rt fdd D rt d ttttfr|du r{tt d }t |f}||j	v r|j	| S |durt
|nd}t |t|j	}tjt ||d}|j||dd}||j	|< |S | tj |d	S )
a  Materialise a constant as an initializer in the **root** graph.

        Child builders delegate to the root so that all constant initializers
        live in the root graph.  For subgraphs this is correct because ONNX
        allows inner scopes to reference outer-scope initializers.  For
        function bodies (which cannot reference outer initializers) callers
        should apply :func:`lift_initializers_to_constants` before wrapping
        the graph in :class:`ir.Function`.
        Nr   )r   r;   F)r;   r   c                 3  s"    | ]}t |t d  V  qdS )r   N)r#   r   r,   r   r   r   	<genexpr>B  s     z7GraphBuilder._get_or_create_constant.<locals>.<genexpr>r   r   )r   r#   r   r$   r%   r   r
   r   r   r   r   r&   rz   rB   rO   r   r<   tupleall)	r   r   r   r   	cache_keyr   r;   rO   ir_valuer   r   r   _get_or_create_constant&  sB   





z$GraphBuilder._get_or_create_constant	like_typeir.Value | Nonec                 C  sl   t |tjr|S |du r|S |dur|jdur|jjnd}|duo$|du }| ||}|r4| j||}|S )a%  Convert a permissible input (for a call to an op) into an ir.Value.

        Permissible values include ir.Value as well as python constants that can be converted
        into ONNX constant tensors. For constant values, the like_type is used to determine the
        target onnx type.
        N)r#   rB   rb   r   r   r   ry   CastLike)r   r   r   r   needs_dynamic_castr   r   r   r   _input_to_ir_valueU  s   	zGraphBuilder._input_to_ir_valuer   r9   int | Sequence[str | ir.Value]op_typerq   c                   s   t |trDj  |dk rtd| |dkr/r" d  n  }tj|dgS  fddt|D }fdd|D S g }|D ]-}t |tjr`|j	rZ|j	|_	|
| qHt |trr|
tj|d qHtd	|S )
Nr   z,Number of outputs must be non-negative, got r4   r!   ra   c                   s2   g | ]}r d   d | n  d | qS )r!   r   r-   rl   )countr   r   r   r3   |  s    $z/GraphBuilder._adapt_outputs.<locals>.<listcomp>c                   s   g | ]}t j |d qS )ra   )rB   rb   _qualify_value_name)r-   rQ   r   r   r   r3     s    zOutput type not supported.)r#   r   r'   rI   rA   rB   rb   r   ranger;   rH   r   rZ   )r   r9   r   r;   namesadapted_outputsoutputr   )r   r   r   r   _adapt_outputsq  s*   


zGraphBuilder._adapt_outputs
int | Noneonnx.defs.OpSchema | Nonec                 C  s8   |d urz	t j|||W S  t jjy   Y d S w d S r   )onnxdefs
get_schemaSchemaError)r   r   r   r:   r   r   r   _get_schema  s   zGraphBuilder._get_schemaschemar7   -Sequence[ir.Value | ir.TensorProtocol | None]kwargsdict[str, Any]=tuple[Sequence[ir.Value | ir.TensorProtocol], dict[str, Any]]c                 C  s6   |d u r||fS t jj|}tj|t||dddS )NF)fill_defaultsallow_extra_args)rB   schemasOpSignaturefrom_op_schemar	   (separate_input_attributes_from_argumentsr<   )r   r   r7   r   op_signaturer   r   r   _partition_inputs_attributes  s   z)GraphBuilder._partition_inputs_attributesSequence[VALUE_LIKE]re   c           	        s  |du rfdd|D S |j }i g }t|D ]W\}}|t|k r'|| }n,|rD|d jtjjjjkrD|d }|j	sC|
|df qntdt| dt| d|j}d|vrh|vrht|tjrh||< |
||f qdfdd  fdd|D S )ak  Uses schema specification to support a limited form of auto-casting.

        * Scalars are promoted to tensors.
        * Further. they are cast to the required type when used in ops with other
        tensor inputs that are required to be of same type.
        Thus, in "A+1" or "Add(A, 1)", the value 1 will be converted to the same
        type as A.
        Nc                      g | ]}  |qS r   r   r   r   r   r   r3         z-GraphBuilder._cast_inputs.<locals>.<listcomp>zNumber of actual parameters z% exceeds number of formal parameters rW   (typevarr   r   r   c                   s4   | d u rd S |d u r  | S |}  | |S r   )r   r   )xr   	type_like)r   type_bindingsr   r   adapt  s   

z(GraphBuilder._cast_inputs.<locals>.adaptc                   s   g | ]	\}} ||qS r   r   )r-   r   r   )r   r   r   r3     s    )r   r   r   r   )r7   rh   rz   optionr   r   OpSchemaFormalParameterOptionVariadicis_homogeneousrH   rA   type_strr#   rB   rb   )	r   r   r7   expected_inputsargs_typevarsrl   r   expectedr   r   )r   r   r   r   _cast_inputs  s6   
zGraphBuilder._cast_inputsr8   c                 C  s   ~|d ur|S i S r   r   )r   r   r8   r   r   r   _cast_attributes  s   zGraphBuilder._cast_attributesrJ   ir.Nodec                 C  s(   | j | tj|g t| dS )zIAppend a node to the graph, run constant propagation and shape inference.N)r'   rH   
onnxscript	optimizerbasic_constant_propagation	inferenceinfer_outputs)r   rJ   r   r   r   add_node  s   zGraphBuilder.add_nodern   ra   rp   r   c                C  s   t |||t| jj|| dS )aR  Build an :class:`ir.Graph` suitable for use as a graph-valued attribute.

        The subgraph inherits the opset version from this :class:`GraphBuilder`.
        It is particularly useful for constructing the body graphs of control-flow ops
        such as ``Scan``, ``Loop``, and ``If``.

        Example - building a Scan body that adds two sequences element-wise::

            body = graph_builder.subgraph(
                lambda op, x, y: op.Add(x, y),
                inputs=[make_value("x", FLOAT[...]), make_value("y", FLOAT[...])],
                outputs=[make_value("sum", FLOAT[...])],
            )

        Args:
            trace_function: A callable with signature
                ``(op: OpBuilder, *inputs: ir.Value | None) -> ir.Value | Sequence[ir.Value]``.
                It is called once with freshly created placeholder inputs to record the
                graph topology.
            inputs: A :class:`Sequence` of :class:`ir.Value` (or ``None``
                for absent optional inputs).  Each ``ir.Value`` should be
                freshly created with a name and optional type/shape.
            outputs: A :class:`Sequence` of :class:`ir.Value` objects
                declaring the expected outputs.
            name: Name of the resulting :class:`ir.Graph`.

        Returns:
            An :class:`ir.Graph` whose inputs and outputs are populated and whose
            nodes record the operations traced by *trace_function*.  This graph can be
            passed directly as a graph-valued attribute (e.g. the ``body`` attribute of
            a ``Scan`` or ``Loop`` node).
        )r?   r;   ro   )r   r   r   r?   )r   rp   r7   r9   r;   r   r   r   rn     s   (
zGraphBuilder.subgraphc             	   C  s   | j  }| | d| }| ||}	| |||}
| |
||\}}| |
|}| |
|}tj	|||p8d||	||d}| 
 |jd< t|  |jd< t|  |jd< | | t|jdkrg|jS |jd S )	zKCreate an ONNX node and add it to the graph, returning its output value(s)._node_N)r8   r   r9   r:   r;   	namespacepkg.onnxscript.class_hierarchypkg.onnxscript.name_scopesr4   r   )r'   rI   _qualify_node_namer   r   r   r   r   rB   rJ   _build_namespacer   repr_scope_classes_scope_namesr   rz   r9   )r   r   r7   r   r   r:   r9   r   	node_nameoutput_valuesr   r8   rJ   r   r   r   call_op  s*   

zGraphBuilder.call_op_outputsfunction%ir.Function | onnxscript.OnnxFunctionr  %int | Sequence[str | ir.Value] | Nonec             	     s(  t |tjr
|j}nt |tjr| }|j}ntd|du r%t|j	} 
||j} fdd|D } j } |j d| }	tj|j||pMd||j|	|jd}
  |
jd< t  |
jd< t  |
jd	<  |
 | jj| < t|
j	d
krdS t|
j	dkr|
j	S |
j	d
 S )z*Call a function as a single function node.:Function must be an ir.Function or onnxscript.OnnxFunctionNc                   r   r   r   )r-   argr   r   r   r3   \  r   z%GraphBuilder.call.<locals>.<listcomp>r   )r   r7   r8   r9   r   r;   overloadr   r   r   r   r   r4   )r#   rB   r   r'   r   OnnxFunctionfunction_irrZ   rz   r9   r   r;   rI   r   rJ   r   r  r   r   r   r  r  r   r   r   
identifier)r   r  r  argsr   r'   r  adapted_argsr   r  rJ   r   r   r   callG  s:   



zGraphBuilder.callr  _prefixSequence[str] | Noner  c                  s  t |tjr
|j}nt |tjr| jdd}ntd|d urBt|t|j	kr8t
d| dt|j	 d fdd|D }ng }|rK |  j } |j d	| d
}	tj||||	d\}
}dd |D }|
D ]}|j	D ]}|jrt||vr |j|_qu | qp|rt||D ]\}}|d ur||_qn|D ]}|d ur|jr |j|_q|r   t|dkrdS t|dkr|S |d S )NT)allow_outer_scope_valuesr  zNumber of rovided output names z+ does not match number of function outputs rW   c                   r   r   )r   )r-   r;   r   r   r   r3     s    
z,GraphBuilder.call_inline.<locals>.<listcomp>r   /)prefixc                 S  s   h | ]
}|d urt |qS r   r*   r,   r   r   r   r/     s    z+GraphBuilder.call_inline.<locals>.<setcomp>r   r   r4   )r#   rB   r   r'   r   r  clonerZ   rz   r9   rA   push_modulerI   r   r;   r   instantiater+   r   r   r{   
pop_module)r   r  r  r  r  r   r'   desired_output_namesr   node_name_prefixrt   r9   output_value_idsrJ   r   
output_valr;   r   r   r   call_inlinev  sV   



zGraphBuilder.call_inlinemodule
class_namec                 C  s   | j ||f dS )zPush a new module scope onto the stack.

        Args:
            module: The attribute name of the module (e.g. ``"layers.0"``).
            class_name: The qualified class name (e.g. ``"Gemma3DecoderLayer"``).
        N)rx   rH   )r   r#  r$  r   r   r   r    s   zGraphBuilder.push_modulec                 C  s   | j std| j   dS )z/Pop the most recent module scope off the stack.z5Cannot pop_module: no module context has been pushed.N)rx   RuntimeErrorrG   r   r   r   r   r    s   zGraphBuilder.pop_module	list[str]c                 C     dd | j D S )z?Return the list of module attribute names in the current scope.c                 S  s   g | ]\}}|qS r   r   r-   r;   r!   r   r   r   r3     r0   z-GraphBuilder._scope_names.<locals>.<listcomp>rx   r   r   r   r   r       zGraphBuilder._scope_namesc                 C  r'  )z4Return the list of class names in the current scope.c                 S  s   g | ]\}}|qS r   r   )r-   r!   clsr   r   r   r3     r0   z/GraphBuilder._scope_classes.<locals>.<listcomp>r)  r   r   r   r   r    r*  zGraphBuilder._scope_classesc                 C  r'  )z3Return non-empty module names for qualifying names.c                 S  s   g | ]\}}|r|qS r   r   r(  r   r   r   r3     s    z2GraphBuilder._scope_name_parts.<locals>.<listcomp>r)  r   r   r   r   _scope_name_parts  r*  zGraphBuilder._scope_name_partsc                 C  "   |   }|rd|d | S |S )zPrepend the current hierarchical context prefix to the given name.

        Uses ``.`` as separator, appropriate for parameter and initializer names.
        rW   r,  joinr   r;   partsr   r   r   r     s   z&GraphBuilder._qualify_initializer_namec                 C  s,   |   }|rdd| d | S d| S )zQualify a value name with the current scope using ``.`` separator.

        The name is prefixed with ``v_`` to distinguish values from parameters.
        v_rW   r.  r0  r   r   r   r     s   
z GraphBuilder._qualify_value_namec                 C  r-  )zAQualify a node name with the current scope using ``/`` separator.r  r.  r0  r   r   r   r     s   zGraphBuilder._qualify_node_namec                 C  sB   g }| j D ]\}}|s|r||r| d| n| qd|S )zBuild the namespace string for a node.

        Each scope entry is formatted as ``name: class_name`` joined by ``/``.
        z: r  )rx   rH   r/  )r   r1  r;   r+  r   r   r   r     s   
zGraphBuilder._build_namespace)r'   r(   ro   rs   r   r)   )r4   )r   r   r:   r   r   r   )r   r   )r   rs   r   rw   )r   r(   r   r   r   )rO   r   r;   r   r   r%   r   r_   )NN)r;   r   r   r   r`   r   r   r   r@   r   r   r   r   r_   )r   r_   r;   r   r   r)   )r   r   r   r   r   r_   )r   r   r   r   r   r   )r   )r9   r   r   r   r   rq   )r   r   r   r   r:   r   r   r   )r   r   r7   r   r   r   r   r   )r   r   r7   r   r   re   )r   r   r8   r   r   r   )rJ   r   r   r)   )
rp   r   r7   re   r9   rq   r;   r   r   r(   )r   Nr4   )r   r   r:   r   r9   r   r   r   r7   r   r   r   )r  r	  r  r
  )r  r	  r  r  r  r   )r#  r   r$  r   r   r)   )r   r)   )r   r&  )r;   r   r   r   r   r   )$__name__
__module____qualname____doc__r   r   propertyry   ro   r   r'   r   r   r   r   r   r   r   r   r   r   r   r   rn   r  r  r"  r  r  r  r  r,  r   r   r   r   r   r   r   r   rw     sp    
%
0




8
7,3?
	







rw   c                   @  s   e Zd ZdZ	d2d3ddZed4ddZed5ddZed6ddZd7ddZ	d8ddZ
d9d:d#d$Zed;d&d'Zdd(d<d+d,Zddd-d=d0d1ZdS )>r   zbDynamic op dispatcher that translates attribute access into ONNX node creation via a GraphBuilder.r   Nbuilderrw   r   r   r:   r   r   r)   c                 C  s   || _ || _|| _d S r   )_builder_domain_version)r   r;  r   r:   r   r   r   r     s   
zOpBuilder.__init__c                 C  r   r   )r<  r   r   r   r   r;    r   zOpBuilder.builderc                 C  r   r   )r=  r   r   r   r   r     r   zOpBuilder.domainc                 C  r   r   )r>  r   r   r   r   r:   	  r   zOpBuilder.versionr   r7   Sequence[Any]r   r   c                 C  s@   | d| j}| d| j}| dd}| jj||||||dS )Nr=  r>  r  r4   )r   r:   r9   )rG   r=  r>  r<  r  )r   r   r7   r   r   r:   r9   r   r   r   _call_op  s   zOpBuilder._call_opr   c                   s    fddS )Nc                    s     | |S r   )r@  )r  r   r   r   r   r   <lambda>  s    z'OpBuilder.__getattr__.<locals>.<lambda>r   )r   r   r   rA  r   __getattr__     zOpBuilder.__getattr__rO   r   r;   r   r_   c                 C  s   | j ||S r   )r<  r   )r   rO   r;   r   r   r   r     rD  zOpBuilder.initializerr   c                 C  r   r   )r<  r   r   r   r   r   r     r   zOpBuilder.functionsr  r  Sequence[str] | int | Nonec                O  s   | j j|g|R d|i|S )a  Call a function as a single function node.

        Args:
            function: The function to call (ir.Function or onnxscript.OnnxFunction).
            *args: Positional arguments to pass to the function.
            _outputs: Optional sequence of output names, or an integer specifying the number of outputs.
            **kwargs: Keyword arguments to pass to the function.

        Returns:
            The output value(s) from the function call.
        r  )r<  r  )r   r  r  r  r   r   r   r   r    s   zOpBuilder.callr  r  r  c                O  s    | j j|g|R ||d|S )a<  Inline a function body into the current graph.

        Args:
            function: The function to call (ir.Function or onnxscript.OnnxFunction).
            *args: Positional arguments to pass to the function.
            _outputs: Optional sequence of output names. If provided, must match the
                number of function outputs.
            _prefix: Optional prefix for module scoping (e.g., "layers.0").
            **kwargs: Keyword arguments to pass to the function.

        Returns:
            The output value(s) from the inlined function body.
        r  )r<  r"  )r   r  r  r  r  r   r   r   r   r"  3  s   zOpBuilder.call_inline)r   N)r;  rw   r   r   r:   r   r   r)   r3  r5  )r   r   )r   r   r7   r?  r   r   )r   r   r   r   r   )rO   r   r;   r   r   r_   r4  )r  rE  )r  r  r  r   )r6  r7  r8  r9  r   r:  r;  r   r:   r@  rC  r   r   r  r"  r   r   r   r   r     s(    

r   )r   r   r   r   )r   r   r   r   )r   )r   r   r   r   r   r   r   r   )r'   r(   r   r)   )rS   rT   r   rU   r   )r;   r   r]   r^   r   r_   )r7   re   r   rf   )rp   r   r7   re   r9   rq   r?   rr   r;   r   ro   rs   r   r(   )rp   r   r7   re   r   r   r;   r   r8   r   r?   rr   r   r   ).r9  
__future__r   typingr   r   r   r   r   r   onnx_irrB   onnxscript._internal._inference	_internal
_inferencer   onnxscript.optimizerr   onnxscript._internalr   r	   rb   TensorProtocolr   r$   r%   r   r   DataTypeINT64FLOATr
   __annotations__r   r   r&   rR   rX   rT   r\   rd   rm   r   r   rw   r   r   r   r   r   <module>   sZ   


9

/b`    V