o
    Xi                    @  s2  d Z ddlmZ ddlZddlZddlZddlZddlZddlZddl	Z	ddl
Z
ddlZddlZddlZddlmZmZmZmZmZmZmZ ddlmZ ddlmZmZmZmZmZmZmZmZ ddl Z ddl!Z"ddl#m$Z$m%Z% ddl&Z&ddl&m'Z'm(Z(m)Z)m*Z*m+Z+m,Z,m-Z-m.Z. ej/rddl0mZ1 dd	l#m2Z2 ej3d
ee-j4e-j5f dZ6ej7dkZ8e9e(j:j;e(j:j<e(j:j=e(j:j>e(j:j?e(j:j@e(j:jAe(j:jBe(j:jCe(j:jDe(j:jEfZFeGeHZIdddZJdddZKG dd dejLe-jMe'jNZOdddZPddd ZQdd#d$ZRdd'd(ZSG d)d& d&eOe-jMee6 ZTG d*d+ d+eOe-jMZUG d,d- d-eOe-jMZVG d.d/ d/eOe-jMZWG d0d1 d1eOe-jMee6 ZXG d2d3 d3e-jYe'jNZZdd7d8Z[dd<d=Z\G d>d? d?e-j]e'jNZ^ddBdCZ_G dDdE dEeZ`ddHdIZaddKdLZbG dMdN dNe-jce'jNZdG dOdP dPe-jee'jNeZfG dQdR dRefZgG dSdT dTefZhG dUdV dVe-jee'jNeZiG dWdX dXeiZjG dYdZ dZeiZkG d[d\ d\eZldd_d`ZmG dadb dbZnG dcdG dGene-joe'jNZpe%dd				dddldmZqddsdtZrG dudv dve-jseed e'jNZtddydzZudd{d|ZvG d}d~ d~eed e'jNZwG dd de-jxe'jNZyG dd de-jzeed e'jNZ{G dd de-j|e-j}e'jNZ~	ddddZddddZddddZddddZ	ddddZddddZddddZddddZddddZ	ddddZddddZ	ddddZ	ddddZejG dd dZddddZ	ddddZdS )z4data structures for the intermediate representation.    )annotationsN)
CollectionHashableIterableIteratorMappingMutableSequenceSequence)Set)AnyCallableClassVarGeneric
NamedTupleProtocolSupportsIntUnion)TypeIs
deprecated)_display_enums_graph_containers_linked_list	_metadata_name_authority
_protocols_type_casting)	TypeGuardTArrayCompatible)boundlittleobjr   return%TypeGuard[_protocols.ArrayCompatible]c                 C  
   t | dS )zUse this function to check if an object is compatible with numpy.

    Avoid isinstance checks with the ArrayCompatible protocol for performance reasons.
    	__array__hasattrr!    r)   A/home/ubuntu/.local/lib/python3.10/site-packages/onnx_ir/_core.py_compatible_with_numpy`      
r+   &TypeGuard[_protocols.DLPackCompatible]c                 C  r$   )zUse this function to check if an object is compatible with DLPack.

    Avoid isinstance checks with the DLPackCompatible protocol for performance reasons.
    
__dlpack__r&   r(   r)   r)   r*   _compatible_with_dlpackh   r,   r/   c                   @  s   e Zd ZdZdZ			d,d-ddZd.ddZd.ddZed/ddZ	e	j
d0ddZ	ed/ddZej
d0ddZed1ddZed1ddZed2dd Zed3d"d#Zd4d$d%Zd&d'd5d*d+ZdS )6
TensorBasezCConvenience Shared methods for classes implementing TensorProtocol.)_doc_stringr   _metadata_props_nameNname
str | None
doc_stringmetadata_propsdict[str, str] | Noner"   Nonec                 C  s   d | _ || _|| _|| _d S N)r   r2   r3   r1   )selfr4   r6   r7   r)   r)   r*   __init__z   s   
zTensorBase.__init__strc                 C  s   | j  d| j S )z:Return a string representation of the shape and data type.,)dtypeshaper;   r)   r)   r*   _printable_type_shape      z TensorBase._printable_type_shapec                 C  s   | j j d|   dS )zPBase string for the repr method.

        Example: Tensor<FLOAT,[5,42]>
        <>)	__class____name__rB   rA   r)   r)   r*   
_repr_base   s   zTensorBase._repr_basec                 C     | j S )zThe name of the tensor.r3   rA   r)   r)   r*   r4         zTensorBase.namevaluec                 C  
   || _ d S r:   rJ   r;   rL   r)   r)   r*   r4         
c                 C  rI   )zThe documentation string.r1   rA   r)   r)   r*   r6      rK   zTensorBase.doc_stringc                 C  rM   r:   rP   rN   r)   r)   r*   r6      rO   intc                 C  s   t | j S )z%The number of elements in the tensor.)mathprodr@   numpyrA   r)   r)   r*   size   s   zTensorBase.sizec                 C  s   t | jj| j S )"The number of bytes in the tensor.)rR   ceilr?   itemsizerU   rA   r)   r)   r*   nbytes   s   zTensorBase.nbytesdict[str, str]c                 C     | j du ri | _ | j S )zThe metadata properties of the tensor.

        The metadata properties are used to store additional information about the tensor.
        Unlike ``meta``, this property is serialized to the ONNX proto.
        Nr2   rA   r)   r)   r*   r7         
zTensorBase.metadata_props_metadata.MetadataStorec                 C     | j du r
t  | _ | j S The metadata store for intermediate analysis.

        Write to the :attr:`metadata_props` if you would like the metadata to be serialized
        to the ONNX proto.
        Nr   MetadataStorerA   r)   r)   r*   meta      

zTensorBase.metac                 C  s   | |   dS )aJ  Write the tensor to a binary file.

        This method writes the raw bytes of the tensor to a file-like object.
        The file-like object must have a ``write`` method that accepts bytes.

        .. versionadded:: 0.1.11

        Args:
            file: A file-like object with a ``write`` method that accepts bytes.
        N)writetobytes)r;   filer)   r)   r*   tofile   s   zTensorBase.tofileFpagerk   boolc                C  s  t  }|d u rt }ndd l}|jd| }ddlm} | g }| 	 
 }|t|  |d t|}t|}tt|}	||  }
|dt|
 dt|
 d| d|	  d	}tt||k |j }|d
| d|d |t| }|d tj|ddd\}}||j||dddd d|}W d    n1 sw   Y  |d u rt| d S |rdd l}|j }|  || W d    d S 1 sw   Y  d S || d S )Nr   zComputing tensor stats for )asciichartpy zMin: z, Max: z, NaN count: z, Inf count: gư>zSparsity (abs<z): z.2fz
Histogram:P   F)binsdensity   z{:8.0f})heightformat)	bin_edgescfg
)r   require_rich
contextlibnullcontextrich.statusstatusStatusonnx_ir._thirdpartyrm   rT   flattenappendreprnpisnancount_nonzeroisinfminmaxabsrU   isfinite	histogramplotjoinprintrich.consoleconsoleConsolepager)r;   rk   richstatus_managerrm   linesarray
nan_values	nan_count	inf_countnumberssparse_threatholdsparsityfinite_numbershistru   textr   r)   r)   r*   display   sX   





!

"zTensorBase.display)NNN)r4   r5   r6   r5   r7   r8   r"   r9   r"   r=   r"   r5   rL   r5   r"   r9   r"   rQ   r"   rZ   r"   r^   r"   r9   rk   rl   r"   r9   )rG   
__module____qualname____doc__	__slots__r<   rB   rH   propertyr4   setterr6   rU   rY   r7   rd   ri   r   r)   r)   r)   r*   r0   p   s6    	




r0   r   
np.ndarrayr?   _enums.DataTyper9   c              
   C  s  |t v r|jdkr| jtjtjfvrtd| j d| d|jdkr@| jtjtj	tj
tjtjtjfvr@td| j d| d|tjjkr]| jtjtjtjfvr]td| j d| d|tjjkrx| jtjtjfvrxtd| j d| d|tjjkr| jtjtjfvrtd	| j d| d|tjjkr| jtjtjtjfvrtd
| j d| d|tjjkr| jtjtjfvrtd| j d| ddS z	tj| j}W n ty } ztd|d}~ww ||krtd| j d| ddS )a  Check if the numpy array dtype matches the IR data type.

    When the dtype is not one of the numpy native dtypes, the value needs need to be:

    - ``int8`` or ``uint8`` for int2, int4, with the sign bit extended to 8 bits.
    - ``uint8`` for uint2, uint4 or float4.
    - ``uint8`` for 8-bit data types.
    - ``uint16`` for bfloat16

    or corresponding dtypes from the ``ml_dtype`` package.
       z@The numpy array dtype must be uint16 or ml_dtypes.bfloat16 (not z) for IR data type .rr   z>The numpy array dtype must be uint8 or ml_dtypes.float8* (not zCThe numpy array dtype must be int8 or uint8 or ml_dtypes.int4 (not z?The numpy array dtype must be uint8 or or ml_dtypes.uint4 (not zDThe numpy array dtype must be uint8 or ml_dtypes.float4_e2m1fn (not zCThe numpy array dtype must be int8 or uint8 or ml_dtypes.int2 (not z<The numpy array dtype must be uint8 or ml_dtypes.uint2 (not NzFailed to convert the numpy dtype to an IR data type. If you are using a non-native dtype, be sure to specify the corresponding IR dtype when creating a Tensor.zThe numpy array dtype z! does not match the IR data type )_NON_NUMPY_NATIVE_TYPESbitwidthr?   r   uint16	ml_dtypesbfloat16	TypeErroruint8float8_e4m3fnuzfloat8_e4m3fnfloat8_e5m2fnuzfloat8_e5m2float8_e8m0fnur   DataTypeINT4int8int4UINT4uint4
FLOAT4E2M1float4_e2m1fnINT2int2UINT2uint2
from_numpy)r   r?   dtype_numpyer)   r)   r*    _check_numpy_representation_type  sr   r   c                 C  s  |t jjkr| tjS |t jjkr| tjS |t jjkr$| tj	S |t jj
kr0| tjS |t jjkr<| tjS |t jjkrH| tjS |t jjkrT| tjS |t jjkr`| tjS |t jjkrl| tjS |t jjkrx| tjS |t jjkr| tjS | S )a  Reinterpret the array when it is a bit representation of a dtype not supported by numpy.

    Args:
        array: The numpy array to reinterpret.
        dtype: The data type to reinterpret the array as.

    Returns:
        The array reinterpreted as the dtype.
    )r   r   BFLOAT16viewr   r   FLOAT8E4M3FNr   FLOAT8E4M3FNUZr   
FLOAT8E5M2r   FLOAT8E5M2FNUZr   
FLOAT8E8M0r   r   r   r   r   r   r   r   r   r   r   )r   r?   r)   r)   r*   #_maybe_view_np_array_with_ml_dtypesQ  s.   r   rh   rl   c                 C  s2   t | dsdS z|   W dS  ty   Y dS w )z0Check if the file-like object supports fileno().filenoFT)r'   r   	Exception)rh   r)   r)   r*   _supports_filenov  s   

r   tensorTensorc                 C  s   |   }| jtjjtjjtjjhv rt|}n| jtjj	tjj
hv r)t|}n| jj|jks4J dts?||jd}|S )zCreate a numpy array for the byte representation of the tensor.

    This function is used for serializing the tensor to bytes. It handles the
    special cases for 2-bit and 4-bit data types and endianness.
    zBug: The itemsize should matchrD   )rT   r?   r   r   r   r   r   r   pack_4bitx2r   r   pack_2bitx4rX   _IS_LITTLE_ENDIANastypenewbyteorder)r   r   r)   r)   r*   (_create_np_array_for_byte_representation  s    r   c                      s   e Zd ZdZdZ	d1dddddd2 fddZd1d3ddZddd4ddZd5ddZd6d d!Z	e
d7d#d$Ze
d8d&d'Ze
d9d(d)Zd:d*d+Zd;d-d.Zd<d/d0Z  ZS )=r   a"  An immutable concrete tensor.

    This class is a wrapper around the raw tensor data. The raw tensor data can be a numpy array
    compatible object (e.g. ``np.ndarray``, ``torch.Tensor``) or a ``DLPack`` compatible object.
    The tensor is immutable and the data is not copied at initialization.

    To create a tensor from a numpy array::

        >>> import numpy as np
        >>> array = np.array([1, 2, 3])
        >>> tensor = Tensor(array)
        >>> # The tensor itself can be treated as a numpy array because it implements the __array__ method
        >>> np.allclose(tensor, array)
        True

    To get a numpy array from the tensor, call :meth:`numpy`. To convert the tensor
    to a byte string for serialization, call :meth:`tobytes`.

    It is recommended to check the size of the tensor first before accessing the
    underlying data, because accessing the data may be expensive and incur IO
    overhead.

    Subclass this class to efficiently handle different types of tensors from different frameworks.

    Attributes:
        name: The name of the tensor.
        shape: The shape of the tensor.
        dtype: The data type of the elements of the tensor. It is an :class:`ir.DataType` enum.
        doc_string: Documentation string.
        raw: The raw data behind this tensor. It can be anything.
        size: The number of elements in the tensor.
        nbytes: The number of bytes in the tensor.
        metadata_props: Metadata that will be serialized to the ONNX file.
        meta: Metadata store for graph transform passes.
    _dtype_raw_shapeNr@   r4   r6   r7   rL   r   r?   _enums.DataType | Noner@   Shape | Noner4   r5   r6   r7   r8   r"   r9   c                  s  t  j|||d t|st|stdt| |du r8t|ds-tdt| dtt	|ddd| _
n|| _
| j
  t|tjrKt|}|du rbt|tjr^tj|j| _ntd	t|tjrmt|| || _t|tjr|t|| j}|| _dS )
aa  Initialize a tensor.

        Args:
            value: The backing data of the tensor. It can be a numpy array compatible object or a DLPack compatible object.
                When the dtype is not one of the numpy native dtypes, the value can
                be ``uint8`` (unpacked) or ml_dtypes types for 4-bit and 8-bit data types,
                and ``uint16`` or ml_dtype.bfloat16 for bfloat16 when the value is a numpy array;
                ``dtype`` must be specified in this case.
            dtype: The data type of the tensor. It can be None only when value is a numpy array.
                Users are responsible for making sure the dtype matches the value when value is not a numpy array.
            shape: The shape of the tensor. If None, the shape is obtained from the value.
            name: The name of the tensor.
            doc_string: The documentation string.
            metadata_props: The metadata properties.

        Raises:
            TypeError: If the value is not a numpy array compatible or a DLPack compatible object.
            TypeError: If the value is a numpy array and the dtype is specified but does not match the dtype of the array.
            ValueError: If the shape is not specified and the value does not have a shape attribute.
            ValueError: If the dtype is not specified and the value is not a numpy array.
        r4   r6   r7   )Expected an array compatible object, got Nr@   /Expected an object with a shape attribute, but : does not have shape. Please specify the shape explicitly.TfrozenzZThe dtype must be specified when the value is not a numpy array. Value type: {type(value)})superr<   r+   r/   r   typer'   
ValueErrorShapegetattrr   freeze
isinstancer   genericr   ndarrayr   r   r   r?   r   r   r   r   r;   rL   r?   r@   r4   r6   r7   rF   r)   r*   r<     s2   




zTensor.__init__r   r   c                 C  sN   t | jtjst| jr| j|S t| js!J dt| j t| jS )N6Bug: Expected DLPack or Numpy compatible objects, got )	r   r   r   r   r+   r%   r/   r   from_dlpackr;   r?   r)   r)   r*   r%     s   zTensor.__array__streamr   c                C  (   t | jr| jj|dS |  j|dS Nr   r/   r   r.   r%   r;   r   r)   r)   r*   r.        
zTensor.__dlpack__tuple[int, int]c                 C      t | jr
| j S |   S r:   r/   r   __dlpack_device__r%   rA   r)   r)   r*   r       

zTensor.__dlpack_device__r=   c                 C  s@   t | jd}ddd |D }|   d| d| jdS )Nrw    c                 s  s    | ]}|  V  qd S r:   )strip).0liner)   r)   r*   	<genexpr>#      z"Tensor.__repr__.<locals>.<genexpr>(, name=))r   r   splitr   rH   r4   )r;   tensor_linestensor_textr)   r)   r*   __repr__   s   zTensor.__repr__r   c                 C  rI   z'The data type of the tensor. Immutable.r   rA   r)   r)   r*   r?   &  rK   zTensor.dtyper   c                 C  rI   z#The shape of the tensor. Immutable.r   rA   r)   r)   r*   r@   +  rK   zTensor.shapec                 C  rI   z&Backing data of the tensor. Immutable.r   rA   r)   r)   r*   raw0  rK   z
Tensor.rawc                 C  s   t | jtjr
| jS |  S zReturn the tensor as a numpy array.

        When the data type is not supported by numpy, the dtypes from the ``ml_dtype``
        package are used. The values can be reinterpreted as bit representations
        using the ``.view()`` method.
        )r   r   r   r   r%   rA   r)   r)   r*   rT   5  s   zTensor.numpybytesc                 C  s   t | }| S )Returns the value as bytes encoded in little endian.

        Override this method for more efficient serialization when the raw
        value is not a numpy array.
        )r   rg   r;   r   r)   r)   r*   rg   A  s   zTensor.tobytesc                 C  s>   t | jtjrt|rt| }|| dS ||   dS )Write the tensor to a binary file.

        .. versionadded:: 0.1.11

        Args:
            file: A file-like object with a ``write`` method that accepts bytes, or has an ``fileno()`` method.
        N)	r   r   r   r   r   r   ri   rf   rg   r;   rh   r   r)   r)   r*   ri   K  s   zTensor.tofiler:   )rL   r   r?   r   r@   r   r4   r5   r6   r5   r7   r8   r"   r9   r?   r   r"   r   r   r   r"   r   r"   r  r   r"   r   r"   r   r"   r   r"   r   r"   r  r   )rG   r   r   r   r   r<   r%   r.   r  r  r   r?   r@   r  rT   rg   ri   __classcell__r)   r)   r   r*   r     s.    $	G




c                      s   e Zd ZdZdZdddddJ fddZedKddZejdLddZedKdd Z	edMd!d"Z
edNd#d$ZedNd%d&ZedOd'd(ZedPd)d*Zd+d, ZdQdRd/d0Zdd1dSd3d4ZdTd6d7ZdMd8d9ZdUd:d;ZdVd=d>ZdWd?d@ZdXdBdCZdWdDdEZdWdFdGZdWdHdIZ  ZS )YExternalTensora  An immutable concrete tensor with its data store on disk.

    This class uses memory mapping to avoid loading the tensor into memory,
    when the data type is supported by numpy. Otherwise, the tensor is loaded
    into memory lazily when accessed.

    Calling :attr:`shape` does not incur IO. Checking shape before loading
    the tensor is recommended if IO overhead and memory usage is a concern.

    To obtain an array, call :meth:`numpy`. To obtain the bytes,
    call :meth:`tobytes`. To write the data to a file, call :meth:`tofile`.

    The :attr:`location` must be a relative path conforming to the ONNX
    specification. Given the correct :attr:`base_dir`, the :attr:`path` is computed
    to be the full path to the data file. Users should expect that the :attr:`path`
    always leads to the correct file. At initialization, paths are not checked.
    It is the user's responsibility to ensure the paths are valid and accessible.

    Attributes:
        location: The location of the data file. It is the path relative to the base directory.
        base_dir: The base directory for the external data. It is used to resolve relative paths.
            At serialization, only the :attr:`location` is serialized into the "location" field of the ``TensorProto``.
        path: The path to the data file. This is computed by joining :attr:`base_dir` and :attr:`location`.
        offset: The offset in bytes from the start of the file.
        length: The length of the data in bytes.
        dtype: The data type of the tensor.
        shape: The shape of the tensor.
        name: The name of the tensor. It must be specified.
        doc_string: The documentation string.
        metadata_props: The metadata properties.
    )	_array	_base_dirr   _length	_location_offsetr   _validr  Nrn   )r6   r7   base_dirlocationos.PathLike | stroffset
int | Nonelengthr?   r   r@   r   r4   r=   r6   r5   r7   r8   r2  r"   r9   c          
        s   t  j|||d tjrtj|rtd|| _|	| _	|| _
|| _|| _|| _|| _| j  || _d| _d| _|| _d| _d| _dS )af  Initialize an external tensor.

        Args:
            location: The location of the data file. It is the path relative to the base directory.
            offset: The offset in bytes from the start of the file.
            length: The length of the data in bytes.
            dtype: The data type of the tensor.
            shape: The shape of the tensor.
            name: The name of the tensor.
            doc_string: The documentation string.
            metadata_props: The metadata properties.
            base_dir: The base directory for the external data. It is used to resolve relative paths.
        r   zFThe location must be a relative path. Please specify base_dir as well.NT)r   r<   onnx_irDEBUGospathisabsr   r/  r-  r0  r.  r   r4   r   r   r6   r,  r  r2   r   r1  )
r;   r3  r5  r7  r?   r@   r4   r6   r7   r2  r   r)   r*   r<     s(   

zExternalTensor.__init__str | os.PathLikec                 C  rI   r:   r-  rA   r)   r)   r*   r2    rK   zExternalTensor.base_dirrL   c                 C  rM   r:   r>  rN   r)   r)   r*   r2    rO   c                 C  rI   r:   )r/  rA   r)   r)   r*   r3    rK   zExternalTensor.locationc                 C  s   t j| j| jS r:   )r:  r;  r   r-  r/  rA   r)   r)   r*   r;    s   zExternalTensor.pathc                 C  rI   r:   )r0  rA   r)   r)   r*   r5    rK   zExternalTensor.offsetc                 C  rI   r:   )r.  rA   r)   r)   r*   r7    rK   zExternalTensor.lengthc                 C  rI   r:   r  rA   r)   r)   r*   r?     rK   zExternalTensor.dtypec                 C  rI   r:   r  rA   r)   r)   r*   r@     rK   zExternalTensor.shapec                 C  s~  |    | jd u sJ d| jdkr"tj| j | j d| _d S t| j	d}t
j
| dt
jd| _W d    n1 s?w   Y  | jtjjtjjtjjtjjtjjhv rittj}| jd | jd  }nt| j d}| j}tj| j|| jpd|d| _| j }| jjd	krt| j|| j | _d S | jjdkrt| j|| j | _d S | j|| _d S )
Nz*Bug: The array should be loaded only once.r   r?   rb)access   rD   )r?   r5  count   )_check_validityr,  rU   r   emptyr@   rT   r?   openr;  mmapr   ACCESS_READr  r   r   r   r   r   r   r   r   r   
frombufferr5  r   r   unpack_4bitx2r   unpack_2bitx4reshape)r;   fdtrC  r@   r)   r)   r*   _load  sD   

	


zExternalTensor._loadr   r   c                 C  s4   |    | jd u r|   | jd usJ | j|S r:   )rE  r,  rP  r%   r   r)   r)   r*   r%     s
   
zExternalTensor.__array__r   r   c                C     t dNzqExternalTensor does not support DLPack because it uses memory mapping. Call numpy() to get a numpy array instead.NotImplementedErrorr  r)   r)   r*   r.        zExternalTensor.__dlpack__r  c                 C  rQ  rR  rS  rA   r)   r)   r*   r    rU  z ExternalTensor.__dlpack_device__c                 C  s6   |    d| j d| jd| jd| jd| jdS )Nz(location='z', name=z	, offset=z	, length=z, base_dir=r  )rH   r3  r4   r5  r7  r2  rA   r)   r)   r*   r  #  s   zExternalTensor.__repr__c                 C  s.   |    | jdu r|   | jdusJ | jS )zReturn the tensor as a numpy array.

        The data will be memory mapped into memory and will not taken up physical memory space.
        N)rE  r,  rP  rA   r)   r)   r*   rT   )  s
   
zExternalTensor.numpyr  c                 C  sP   |    | jdu r|   | jdusJ | jpd}| jp| j}| j|||  S )zXReturn the bytes of the tensor.

        This will load the tensor into memory.
        Nr   )rE  r  rP  r0  r.  rY   )r;   r5  r7  r)   r)   r*   rg   4  s   

zExternalTensor.tobytesc                 C  s   |    t| jd?}| jd ur|| j | jp| j}d}|dkrA|t||}|	| |t
|8 }|dks"W d    d S W d    d S 1 sLw   Y  d S )Nr@  i   r   )rE  rG  r;  r0  seekr.  rY   readr   rf   len)r;   rh   srcbytes_to_copy
chunk_sizechunkr)   r)   r*   ri   A  s   


"zExternalTensor.tofilerl   c                 C  rI   )zlCheck if the tensor is valid.

        The external tensor is valid if it has not been invalidated.
        r1  rA   r)   r)   r*   validM  s   zExternalTensor.validc                 C  s   |   std| dd S )NzThe external tensor 'z7' is invalidated. The data may be corrupted or deleted.)r^  r   rA   r)   r)   r*   rE  T  s
   
zExternalTensor._check_validityc                 C  
   d| _ dS )z~Invalidate the tensor.

        The external tensor is invalidated when the data is known to be corrupted or deleted.
        FNr]  rA   r)   r)   r*   
invalidateZ  r,   zExternalTensor.invalidatec                 C  s(   d| _ | jdur| j  d| _dS dS )zLDelete all references to the memory buffer and close the memory-mapped file.N)r,  r  closerA   r)   r)   r*   releasea  s
   


zExternalTensor.release)r3  r4  r5  r6  r7  r6  r?   r   r@   r   r4   r=   r6   r5   r7   r8   r2  r4  r"   r9   )r"   r=  )rL   r=  r"   r9   r   r"   r6  r%  r&  r:   r"  r#  r$  r(  r)  r   r"   rl   )rG   r   r   r   r   r<   r   r2  r   r3  r;  r5  r7  r?   r@   rP  r%   r.   r  r  rT   rg   ri   r^  rE  r`  rb  r*  r)   r)   r   r*   r+  [  sF     2/







r+  c                      s   e Zd ZdZdZdddddd5 fddZd6d7ddZddd8ddZd9ddZd:dd Z	e
d;d"d#Ze
d<d%d&Ze
d=d(d)Ze
d>d*d+Zd?d-d.Zd@d0d1ZdAd3d4Z  ZS )BStringTensorzaMultidimensional array of strings (as binary data to match the string_data field in TensorProto).)r   r   Nr   rL   (Sequence[bytes] | npt.NDArray[np.bytes_]r@   r   r4   r5   r6   r7   r8   r"   r9   c                  sh   t  j|||d |du r't|dstdt| dtt|ddd| _n|| _| j  || _	dS )a{  Initialize a tensor.

        Args:
            value: The backing data of the tensor. It can be a numpy array or a Sequence of bytes.
            shape: The shape of the tensor. If None, the shape is obtained from the value.
            name: The name of the tensor.
            doc_string: The documentation string.
            metadata_props: The metadata properties.
        r   Nr@   r   r   Tr   )
r   r<   r'   r   r   r   r   r   r   r   )r;   rL   r@   r4   r6   r7   r   r)   r*   r<   q  s   


zStringTensor.__init__r?   r   r   c                 C  sP   t | jtjr
| jS t | jtsJ dt| j tj| j|d| j	 S )NzBug: Expected a sequence, got r?  )
r   r   r   r   r	   r   r   rM  r@   rT   r   r)   r)   r*   r%     s   zStringTensor.__array__r   r   c                C  s
   ~t dNz$StringTensor does not support DLPackr   r  r)   r)   r*   r.     s   zStringTensor.__dlpack__r  c                 C  rQ  rg  rh  rA   r)   r)   r*   r       zStringTensor.__dlpack_device__r=   c                 C     |    d| jd| jdS Nr  r  r  rH   r   r4   rA   r)   r)   r*   r       zStringTensor.__repr__r   c                 C  s   t jjS r  )r   r   STRINGrA   r)   r)   r*   r?     s   zStringTensor.dtyper   c                 C  rI   r  r  rA   r)   r)   r*   r@     rK   zStringTensor.shaperQ   c                 C  s   t dd |  D S )rV   c                 s      | ]}t |V  qd S r:   rX  )r
  stringr)   r)   r*   r    r  z&StringTensor.nbytes.<locals>.<genexpr>)sumstring_datarA   r)   r)   r*   rY     s   zStringTensor.nbytesc                 C  rI   r  r  rA   r)   r)   r*   r    rK   zStringTensor.rawnpt.NDArray[np.bytes_]c                 C     |   S z#Return the tensor as a numpy array.)r%   rA   r)   r)   r*   rT        zStringTensor.numpyr  c                 C  rQ  )NzAStringTensor does not support tobytes. Use 'string_data' instead.)r   rA   r)   r)   r*   rg     ri  zStringTensor.tobytesSequence[bytes]c                 C  s"   t | jtjr| j  S | jS )z%Return the string data of the tensor.)r   r   r   r   r   tolistrA   r)   r)   r*   rs    s   zStringTensor.string_data)rL   rf  r@   r   r4   r5   r6   r5   r7   r8   r"   r9   r:   r"  r#  r$  r   r%  r&  r   )r"   rf  )r"   rt  r)  )r"   rx  )rG   r   r   r   r   r<   r%   r.   r  r  r   r?   r@   rY   r  rT   rg   rs  r*  r)   r)   r   r*   re  i  s.    	



re  c                      s   e Zd ZdZdZdddddd5 fddZd6ddZd7d8ddZddd9d d!Zd:d#d$Z	d;d&d'Z
ed<d(d)Zed=d*d+Zed>d,d-Zd?d.d/Zd@d1d2ZdA fd3d4Z  ZS )B
LazyTensora#  A tensor that lazily evaluates a function to get the actual tensor.

    This class takes a function returning an `ir.TensorProtocol`, a dtype, and a shape argument.
    The function is lazily evaluated to get the actual tensor when `tobytes()` or `numpy()` is called.

    Example::

        >>> import numpy as np
        >>> import onnx_ir as ir
        >>> weights = np.array([[1, 2, 3]])
        >>> def create_tensor():  # Delay applying transformations to the weights
        ...     weights_t = weights.transpose()
        ...     return ir.tensor(weights_t)
        >>> lazy_tensor = ir.LazyTensor(create_tensor, dtype=ir.DataType.INT64, shape=ir.Shape([1, 3]))
        >>> print(lazy_tensor.numpy())
        [[1]
         [2]
         [3]]

    Attributes:
        func: The function that returns the actual tensor.
        dtype: The data type of the tensor.
        shape: The shape of the tensor.
        cache: Whether to cache the result of the function. If False,
            the function is called every time the tensor content is accessed.
            If True, the function is called only once and the result is cached in memory.
            Default is False.
        name: The name of the tensor.
        doc_string: The documentation string.
        metadata_props: The metadata properties.
    )r   _funcr   _tensorcacheFN)r}  r4   r6   r7   func'Callable[[], _protocols.TensorProtocol]r?   r   r@   r   r}  rl   r4   r5   r6   r7   r8   r"   r9   c                  s4   t  j|||d || _|| _|| _d| _|| _dS )a  Initialize a lazy tensor.

        Args:
            func: The function that returns the actual tensor.
            dtype: The data type of the tensor.
            shape: The shape of the tensor.
            cache: Whether to cache the result of the function.
            name: The name of the tensor.
            doc_string: The documentation string.
            metadata_props: The metadata properties.
        r   N)r   r<   r{  r   r   r|  r}  )r;   r~  r?   r@   r}  r4   r6   r7   r   r)   r*   r<     s   
zLazyTensor.__init___protocols.TensorProtocolc                 C  s(   | j s|  S | jdu r|  | _| jS )z/Evaluate the function to get the actual tensor.N)r}  r{  r|  rA   r)   r)   r*   	_evaluate
  s
   

zLazyTensor._evaluater   r   c                 C  s   |   |S r:   )r  r%   r   r)   r)   r*   r%        zLazyTensor.__array__r   r   c                C  s   |   j|dS r   )r  r.   r  r)   r)   r*   r.        zLazyTensor.__dlpack__r  c                 C     |    S r:   )r  r  rA   r)   r)   r*   r       zLazyTensor.__dlpack_device__r=   c                 C  rj  )Nz(func=r  r  )rH   r{  r4   rA   r)   r)   r*   r    rm  zLazyTensor.__repr__c                 C  rI   r:   )r{  rA   r)   r)   r*   r        zLazyTensor.rawc                 C  rI   r  r  rA   r)   r)   r*   r?   $  rK   zLazyTensor.dtypec                 C  rI   r  r  rA   r)   r)   r*   r@   )  rK   zLazyTensor.shapec                 C  r  rv  )r  rT   rA   r)   r)   r*   rT   .     zLazyTensor.numpyr  c                 C  r  )zReturn the bytes of the tensor.)r  rg   rA   r)   r)   r*   rg   2  r  zLazyTensor.tobytesc                   s0   |   }t|dr|| d S t | d S )Nri   )r  r'   ri   r   )r;   rh   r   r   r)   r*   ri   6  s   
zLazyTensor.tofile)r~  r  r?   r   r@   r   r}  rl   r4   r5   r6   r5   r7   r8   r"   r9   r"   r  r:   r"  r#  r$  r   )r"   r  r%  r&  r(  r)  r   )rG   r   r   r   r   r<   r  r%   r.   r  r  r   r  r?   r@   rT   rg   ri   r*  r)   r)   r   r*   rz    s,     





rz  c                      s   e Zd ZdZdZddddd6 fddZd7d8ddZddd9ddZd:d d!Zd;d#d$Z	e
d<d%d&Ze
d=d(d)Ze
d>d*d+Zd?d,d-Zd@d/d0ZdAd2d3ZdBd4d5Z  ZS )CPackedTensorz`A tensor that stores 2bit and 4bit datatypes in packed format.

    .. versionadded:: 0.1.2
    r   Nr   rL   r   r?   r   r@   Shape | Sequence[int]r4   r5   r6   r7   r8   r"   r9   c                  s   t  j|||d t|st|stdt| t|| _| j  |j	dvr0td| || _
|| _t|tjrz|jtjksZ|jtjksZ|jtjksZ|jtjksZ|jtjkrctd|j d|j| jkr|td| j d| j d	|j d
dS dS )a  Initialize a tensor.

        Args:
            value: The backing data of the tensor. It can be a numpy array compatible object or a DLPack compatible object.
                The value MUST be packed in an integer dtype.
            dtype: The data type of the tensor. Must be one of INT2, UINT2, INT4, UINT4, FLOAT4E2M1.
            shape: The shape of the tensor.
            name: The name of the tensor.
            doc_string: The documentation string.
            metadata_props: The metadata properties.

        Raises:
            TypeError: If the value is not a numpy array compatible or a DLPack compatible object.
            TypeError: If the value is a numpy array and the dtype is not uint8 or one of the ml_dtypes dtypes.
        r   r   )rB  rD  zIPackedTensor only supports INT2, UINT2, INT4, UINT4, FLOAT4E2M1, but got z5PackedTensor expects the value to be packed, but got zD which is not packed. Please pack the value or use `onnx_ir.Tensor`. Expected the packed array to be  bytes (from shape ), but got  bytesN)r   r<   r+   r/   r   r   r   r   r   r   r   r   r   r   r   r?   r   r   r   r   r   r   rU   rY   r   r@   r   r   r)   r*   r<   L  s4   


zPackedTensor.__init__Fr   copyrl   r   c                 C  ru  r:   )rT   )r;   r?   r  r)   r)   r*   r%     ri  zPackedTensor.__array__r   r   c                C  r   r   r   r  r)   r)   r*   r.     r  zPackedTensor.__dlpack__r  c                 C  r  r:   r  rA   r)   r)   r*   r    r  zPackedTensor.__dlpack_device__r=   c                 C  rj  rk  rl  rA   r)   r)   r*   r    rm  zPackedTensor.__repr__c                 C  rI   r  r  rA   r)   r)   r*   r?     rK   zPackedTensor.dtyper   c                 C  rI   r  r  rA   r)   r)   r*   r@     rK   zPackedTensor.shapec                 C  rI   r  r  rA   r)   r)   r*   r    rK   zPackedTensor.rawc                 C  s&   |   }t|| j | j S r  )numpy_packedr   rK  r@   rT   r   r?   r  r)   r)   r*   rT     s   zPackedTensor.numpynpt.NDArray[np.uint8]c                 C  s   t | jtjst| jrt| j}nt| js"J dt| j t| j}|j	| j	kr?t
d| j	 d| j d|j	 d|tjS )z$Return the tensor as a packed array.r   r  r  r  r  )r   r   r   r   r+   asarrayr/   r   r   rY   r   r@   r   r   r  r)   r)   r*   r    s   zPackedTensor.numpy_packedr  c                 C  s&   |   }ts||jd}| S )r  rD   )r  r   r   r?   r   rg   r  r)   r)   r*   rg     s   zPackedTensor.tobytesc                 C  sF   t |r|  }ts||jd}|| dS ||   dS )r   rD   N)	r   r  r   r   r?   r   ri   rf   rg   r!  r)   r)   r*   ri     s   zPackedTensor.tofile)rL   r   r?   r   r@   r  r4   r5   r6   r5   r7   r8   r"   r9   NF)r?   r   r  rl   r"   r   r#  r$  r   r%  r&  r'  r(  )r"   r  r)  r   )rG   r   r   r   r   r<   r%   r.   r  r  r   r?   r@   r  rT   r  rg   ri   r*  r)   r)   r   r*   r  @  s*    7




r  c                   @  sT   e Zd ZdZdZdddZdddZdddZedddZ	dddZ
dddZdS )SymbolicDimzImmutable symbolic dimension that can be shared across multiple shapes.

    SymbolicDim is used to represent a symbolic (non-integer) dimension in a tensor shape.
    It is immutable and can be compared or hashed.
    _valuerL   r5   r"   r9   c                 C  s   t |tr	td|| _dS )zInitialize a symbolic dimension.

        Args:
            value: The value of the dimension. It should not be an int.

        Raises:
            TypeError: If value is an int.
        zrThe value of a SymbolicDim cannot be an int. If you are creating a Shape, use int directly instead of SymbolicDim.N)r   rQ   r   r  rN   r)   r)   r*   r<     s
   
	
zSymbolicDim.__init__otherobjectrl   c                 C  s    t |ts
| j|kS | j|jkS )z7Check equality with another SymbolicDim or string/None.)r   r  rL   r;   r  r)   r)   r*   __eq__  s   

zSymbolicDim.__eq__rQ   c                 C  
   t | jS )z0Return the hash of the symbolic dimension value.)hashrL   rA   r)   r)   r*   __hash__  rO   zSymbolicDim.__hash__c                 C  rI   )z5The value of the symbolic dimension (string or None).r  rA   r)   r)   r*   rL     rK   zSymbolicDim.valuer=   c                 C     | j  S r:   r  rA   r)   r)   r*   __str__  ri  zSymbolicDim.__str__c                 C  s   | j j d| j dS Nr  r  )rF   rG   r  rA   r)   r)   r*   r       zSymbolicDim.__repr__Nr   r  r  r"   rl   r   r   r   )rG   r   r   r   r   r<   r  r  r   rL   r  r  r)   r)   r)   r*   r    s    



r  rL   r  TypeIs[SupportsInt]c                 C  s    t | trdS t| drdS dS )zCheck if the value is compatible with int (i.e., can be safely cast to int).

    Args:
        value: The value to check.

    Returns:
        True if the value is an int or has an __int__ method, False otherwise.
    T__int__F)r   rQ   r'   )rL   r)   r)   r*   _is_int_compatible  s
   
	
r  dim,int | SupportsInt | SymbolicDim | str | NoneSymbolicDim | intc                 C  sR   | du s	t | trt| S t| rt| S t | tr| S td| dt|  d)a   Convert the value to a SymbolicDim if it is not an int.

    Args:
        dim: The dimension value, which can be int, str, None, or SymbolicDim.

    Returns:
        An int or SymbolicDim instance.

    Raises:
        TypeError: If the value is not int, str, None, or SymbolicDim.
    Nz2Expected int, str, None or SymbolicDim, but value z has type '')r   r=   r  r  rQ   r   r   )r  r)   r)   r*   _maybe_convert_to_symbolic_dim  s   
r  c                   @  sX  e Zd ZdZdZ		dLdMddZedNddZedOddZdPddZ	dQdRddZ
dSddZdTddZdSddZdUd!d"ZejdVd%d&ZejdWd(d&Zd)d& ZdXd,d-ZdYd/d0ZdZd2d3Zd[d5d6Zd[d7d8Zd\d;d<Zd\d=d>Zejd]d@dAZejdOdBdAZd^dOdCdAZejd]dDdEZejdOdFdEZd^dOdGdEZd]dHdIZdOdJdKZdS )_r   ar  Represents the shape of a tensor, including its dimensions and optional denotations.

    The :class:`Shape` class stores the dimensions of a tensor, which can be integers, None (unknown), or
    symbolic dimensions. It provides methods for querying and manipulating the shape, as well as for comparing
    shapes to other shapes or plain Python lists.

    A shape can be frozen (made immutable). When the shape is frozen, it cannot be
    unfrozen, making it suitable to be shared across tensors or values.
    Call :meth:`freeze` to freeze the shape.

    To update the dimension of a frozen shape, call :meth:`copy` to create a
    new shape with the same dimensions that can be modified.

    Use :meth:`get_denotation` and :meth:`set_denotation` to access and modify the denotations.

    .. note::
        Two shapes can be compared for equality. Be careful when comparing shapes with
        unknown dimensions (``None``), as they may not be considered semantically equal
        even if all dimensions are the same. You can use :meth:`has_unknown_dim` to
        check if a shape has any unknown dimensions.

    Example::

        >>> import onnx_ir as ir
        >>> shape = ir.Shape(["B", None, 3])
        >>> shape.rank()
        3
        >>> shape.is_static()
        False
        >>> shape.is_dynamic()
        True
        >>> shape.is_static(dim=2)
        True
        >>> shape[0] = 1
        >>> shape[1] = 2
        >>> shape.dims
        (1, 2, 3)
        >>> shape == [1, 2, 3]
        True
        >>> shape.frozen
        False
        >>> shape.freeze()
        >>> shape.frozen
        True

    Attributes:
        dims: A tuple of dimensions representing the shape.
            Each dimension can be an integer, None, or a :class:`SymbolicDim`.
        frozen: Indicates whether the shape is immutable. When frozen, the shape
            cannot be modified or unfrozen.
    )_dims_frozenNFdenotationsIterable[str | None] | Noner   rl   dims6Iterable[int | SupportsInt | SymbolicDim | str | None]r"   r9   c                C  sX   dd |D | _ |durt|ndgt| j  | _t| jt| j kr'td|| _dS )a  Initialize a shape.

        Args:
            dims: The dimensions of the shape. Each dimension can be an integer or a
                SymbolicDim or any Python object. When a ``dim`` is not an integer or a
                SymbolicDim, it is converted to a SymbolicDim.
            denotations: The denotations of the dimensions. If None, the denotations are not set.
                Standard denotation can optionally be used to denote tensor
                dimensions with standard semantic descriptions to ensure
                that operations are applied to the correct axis of a tensor.
                Refer to https://github.com/onnx/onnx/blob/main/docs/DimensionDenotation.md#denotation-definition
                for pre-defined dimension denotations.
            frozen: If True, the shape is immutable and cannot be modified. This
                is useful when the shape is initialized by a Tensor or when the shape
                is shared across multiple tensors. The default is False.
        c                 S     g | ]}t |qS r)   )r  r
  r  r)   r)   r*   
<listcomp>  s    z"Shape.__init__.<locals>.<listcomp>NzTThe number of denotations, when provided, must be equal to the number of dimensions.)r  listrX  _denotationsr   r  )r;   r  r  r   r)   r)   r*   r<   i  s   
zShape.__init__tuple[int | SymbolicDim, ...]c                 C  r  )zAll dimensions in the shape.

        This property is read-only. Use __getitem__ and __setitem__ to modify the shape or create a new shape.
        tupler  rA   r)   r)   r*   r    s   
z
Shape.dimsc                 C  rI   )a  Whether the shape is frozen.

        When the shape is frozen, it cannot be unfrozen, making it suitable to be shared.
        Call :meth:`freeze` to freeze the shape. Call :meth:`copy` to create a
        new shape with the same dimensions that can be modified.
        r  rA   r)   r)   r*   r        zShape.frozenc                 C  r_  )zuFreeze the shape.

        When the shape is frozen, it cannot be unfrozen, making it suitable to be shared.
        TNr  rA   r)   r)   r*   r     r,   zShape.freezec                 C  s   t | j| j|dS )zReturn a copy of the shape.r   )r   r  r  )r;   r   r)   r)   r*   r    rC   z
Shape.copyrQ   c                 C  r  )z-The rank of the tensor this shape represents.rX  r  rA   r)   r)   r*   rank  rO   z
Shape.ranktuple[int, ...]c                 C  s8   t dd | jD rtd|  dtdd | jD S )Nc                 s  s    | ]	}t |t V  qd S r:   r   rQ   r  r)   r)   r*   r        zShape.numpy.<locals>.<genexpr>zCannot convert the shape z to a tuple of intsc                 s  s    | ]}|V  qd S r:   r)   r  r)   r)   r*   r    s    )anyr  r   r  rA   r)   r)   r*   rT     s   zShape.numpyc                 C  r  r:   r  rA   r)   r)   r*   __len__     
zShape.__len__Iterator[int | SymbolicDim]c                 C  r  r:   )iterr  rA   r)   r)   r*   __iter__  r  zShape.__iter__indexint | SymbolicDimc                 C     d S r:   r)   r;   r  r)   r)   r*   __getitem__     zShape.__getitem__slicec                 C  r  r:   r)   r  r)   r)   r*   r    r  c                 C  s   t | j| S r:   r  r  r)   r)   r*   r    r  rL   int | SymbolicDim | str | Nonec                 C  s    | j rtdt|| j|< dS )a.  Set the dimension at the index.

        Args:
            index: The index of the dimension.
            value: The value of the dimension.

        Raises:
            TypeError: If the shape is frozen and cannot be modified.
            TypeError: If the value is not an int or SymbolicDim.
        z+The shape is frozen and cannot be modified.N)r  r   r  r  )r;   r  rL   r)   r)   r*   __setitem__  s   zShape.__setitem__r5   c                 C  
   | j | S )zReturn the denotation of the dimension at the index.

        Args:
            index: The index of the dimension.

        Returns:
            The denotation of the dimension.
        r  r  r)   r)   r*   get_denotation  s   
	zShape.get_denotation
denotationc                 C  s   || j |< dS )zSet the denotation of the dimension at the index.

        Args:
            index: The index of the dimension.
            denotation: The denotation of the dimension.
        Nr  )r;   r  r  r)   r)   r*   set_denotation  s   zShape.set_denotationr=   c                 C  s   | j j d| jdS r  )rF   rG   r  rA   r)   r)   r*   r    r  zShape.__repr__c                 C  s   dd dd | jD  dS )zKReturn a string representation of the shape.

        E.g. [n,1,3]
        [r>   c                 S  r  r)   r=   r  r)   r)   r*   r        z!Shape.__str__.<locals>.<listcomp>])r   r  rA   r)   r)   r*   r    s   zShape.__str__r  r  c                 C  s2   t |tr| j|jkS t |tsdS | jt|kS )znReturn True if the shapes are equal.

        Two shapes are equal if all their dimensions are equal.
        F)r   r   r  r   r  r  r)   r)   r*   r    s
   

zShape.__eq__c                 C  s   |  | S r:   )r  r  r)   r)   r*   __ne__  r  zShape.__ne__r  c                 C     dS )z'Return True if the dimension is static.Nr)   r;   r  r)   r)   r*   	is_static      zShape.is_staticc                 C  r  )z)Return True if all dimensions are static.Nr)   rA   r)   r)   r*   r    r  c                 C  s*   |du rt dd | jD S t| | tS )zaReturn True if the dimension is static. If dim is None, return True if all dimensions are static.Nc                 s      | ]}t |tV  qd S r:   r  r  r)   r)   r*   r        z"Shape.is_static.<locals>.<genexpr>)allr  r   rQ   r  r)   r)   r*   r    s   c                 C  r  )z(Return True if the dimension is dynamic.Nr)   r  r)   r)   r*   
is_dynamic  r  zShape.is_dynamicc                 C  r  )z(Return True if any dimension is dynamic.Nr)   rA   r)   r)   r*   r    r  c                 C  s   |d u r	|    S |  | S r:   )r  r  r)   r)   r*   r    s   
c                 C  s   | j | }t|to|jdu S )zReturn True if the dimension is unknown (None).

        A dynamic dimension without a symbolic name is considered unknown.

        .. versionadded:: 0.1.10

        Args:
            dim: The index of the dimension.
        N)r  r   r  rL   )r;   r  dim_objr)   r)   r*   is_unknown_dim  s   

zShape.is_unknown_dimc                 C  s
   d| j v S )zReturn True if any dimension is unknown (None).

        You can use :meth:`is_unknown_dim` to check if a specific dimension is unknown.

        .. versionadded:: 0.1.10
        N)r  rA   r)   r)   r*   has_unknown_dim%  s   
zShape.has_unknown_dimr  )r  r  r   rl   r  r  r"   r9   )r"   r  rd  r   F)r   rl   r   r"   r  )r"   r  )r  rQ   r"   r  )r  r  r"   r  )r  rQ   rL   r  r"   r9   )r  rQ   r"   r5   )r  rQ   r  r5   r"   r9   r   r  )r  rQ   r"   rl   r:   )rG   r   r   r   r   r<   r   r  r   r   r  r  rT   r  r  typingoverloadr  r  r  r  r  r  r  r  r  r  r  r  r)   r)   r)   r*   r   2  sP    4#
	







	



r   rq  r=   c                 C  s   d|  dS )zsReturn a quoted string.

    This function is used to quote value/node names in the IR for better readability.
    "r)   )rq  r)   r)   r*   _quoted0  s   r  c                   @  "   e Zd ZU dZded< ded< dS )UsagezA usage of a value in a node.

    Attributes:
        node: The node that uses the value.
        idx: The input index of the value in the node.
    NodenoderQ   idxNrG   r   r   r   __annotations__r)   r)   r)   r*   r  8  s   
 r  xValuec                 C  sR   | j d u rdS | j jdkr'z	| j   }W n
 ty    Y dS w d| dS dS )Nrn   
   z{...}{})const_valuerU   rT   ry  r   )r  datar)   r)   r*   _short_tensor_str_for_nodeD  s   
r  domainc                 C  s   | dkrdS | S )zNormalize 'ai.onnx' to ''.zai.onnxrn   r)   )r  r)   r)   r*   _normalize_domainP     r  c                
      s  e Zd ZdZdZ	dkddddddddddlddZdmdd Zdnd!d"Zdnd#d$Ze	dod%d&Z
e
jdpd)d&Z
e	dnd*d+Zejdqd,d+Ze	drd-d.Zejdsd/d.Ze	dnd0d1Zejdqd2d1Ze	dnd3d4Zejdqd5d4Ze	dtd7d8Zejdud;d8Zdvd>d?ZdwdAdBZdwdCdDZdxdGdHZdydKdLZdydMdNZe	dzdPdQZejd{dRdQZdvdSdTZe	d|dVdWZe	d}dYdZZe	d~d\d]Ze	dd_d`Zejddad`ZddcddZdedfd fdidjZ  ZS )r  a  IR Node.

    .. tip::
        For a more convenient way (that supports Python objects
        as attributes) to create a node, use the :func:`onnx_ir.node` constructor.

    If ``graph`` is provided, the node will be added to the graph. Otherwise,
    the user is responsible for calling ``graph.append(node)`` (or other mutation methods
    in :class:`Graph`) to add the node to the graph.

    After the node is initialized, it will add itself as a user of its input values.

    The output values of the node are created during node initialization and are immutable.
    To change the output values, create a new node and, for each use of the old outputs (``output.uses()``),
    replace the input in the consuming node by calling :meth:`replace_input_with`.
    You can also use the :func:`~onnx_ir.convenience.replace_all_uses_with` method
    to replace all uses of the output values.

    .. note::
        When the ``domain`` is ``"ai.onnx"``, it is normalized to ``""``.
    )_attributes_domain_graph_inputsr   r2   r3   _op_type_outputs	_overload_versionr6   r)   rn   N)r  num_outputsoutputsversiongraphr4   r6   r7   r  r=   op_typeinputsIterable[Value | None]
attributes#Iterable[Attr] | Mapping[str, Attr]r  r  r6  r  Sequence[Value] | Noner  r  Graph | Function | Noner4   r5   r6   r7   r8   c                C  s   |
| _ t|| _|| _t|| _| ||| _t|t	r"t|
 }tj|| d| _|| _|| _d| _|| _d| _|	durB|	|  || _t| jD ]\}}|durX|| | qJdS )a  Initialize a node and add it as a user of the input values.

        Args:
            domain: The domain of the operator. For onnx operators, this is an empty string.
                When it is ``"ai.onnx"``, it is normalized to ``""``.
            op_type: The name of the operator.
            inputs: The input values. When an input is ``None``, it is an empty input.
            attributes: The attributes. RefAttr can be used only when the node is defined in a Function.
            overload: The overload name when the node is invoking a function.
            num_outputs: The number of outputs of the node. If not specified, the number is 1.
            outputs: The output values. If ``None``, the outputs are created during initialization.
            version: The version of the operator. If ``None``, the version is unspecified and will follow that of the graph.
            graph: The graph that the node belongs to. If ``None``, the node is not added to any graph.
                A `Node` must belong to zero or one graph. If a :class:`Function`, the underlying graph
                of the function is assigned to the node.
            name: The name of the node. If ``None``, the node is anonymous. The name may be
                set by a :class:`Graph` if ``graph`` is specified.
            doc_string: The documentation string.
            metadata_props: The metadata properties.

        Raises:
            TypeError: If the attributes are not :class:`Attr`.
            ValueError: If ``num_outputs``, when not ``None``, is not the same as the length of the outputs.
            ValueError: If an output value is ``None``, when outputs is specified.
            ValueError: If an output value has a producer set already, when outputs is specified.
        ownerN)r3   r  r  r   r  r  _create_outputsr  r   r   valuesr   
Attributesr  r  r  r   r2   r  r   r6   	enumerate
_add_usage)r;   r  r  r	  r  r  r  r  r  r  r4   r6   r7   iinput_valuer)   r)   r*   r<   {  s.   *



zNode.__init__r"   tuple[Value, ...]c                   s   |dur|dur|t |krtd| d| |durV|D ]}|du r+td| | dur;td| d| qg }t|D ]\}} |_||_|| qBt|S |du r\d}|dusbJ t fdd	t|D S )
a  Check the parameters and create outputs for the node.

        Args:
            num_outputs: The number of outputs of the node.
            outputs: The output values of the node.

        Returns:
            The output values of the node.

        Raises:
            ValueError: If `num_outputs`, when not None, is not the same as the length of the outputs.
            ValueError: If an output value is None.
            ValueError: If an output value has a producer set already.
        NzXnum_outputs must be the same as len(outputs) when num_outputs is specified.num_outputs: z, outputs: z*Output value cannot be None. All outputs: zXSupplied output value cannot have a producer when used for initializing a Node. Output: z. All outputs:    c                 3  s    | ]	}t  |d V  qdS )r  Nr  r
  r  rA   r)   r*   r    r  z'Node._create_outputs.<locals>.<genexpr>)	rX  r   producerr  	_producer_indexr   r  range)r;   r  r  outputresultr  r)   rA   r*   r    s>   zNode._create_outputsc                 C  s   | j  d| j d| j | jdk  }dddd | jD  d }| jr7d	dd
d | j D  d nd}ddd | jD }| d| | | S )N:::rn   r  , c                 S  sF   g | ]}|d urd|j rt|j ndtt|  t| ndqS )N%
anonymous:r9   )r4   r  r=   idr  r
  r  r)   r)   r*   r    s    .z Node.__str__.<locals>.<listcomp>r  z {c                 S  s   g | ]\}}| d | qS )=r)   )r
  kvr)   r)   r*   r    s    r  c                 s  ro  r:   r  r)  r)   r)   r*   r    r  zNode.__str__.<locals>.<genexpr>u    ⬅️ )r  r   r  r   r  r  itemsr  )r;   node_type_textinputs_textattributes_textoutputs_textr)   r)   r*   r    s&   $zNode.__str__c                 C  sV   | j j d| jd| jd| jd| jd| jd| jd| jd| j	d	| j
d
S )N(name=z	, domain=z
, op_type=	, inputs=, attributes=z, overload=z
, outputs=z
, version=z, doc_string=r  )rF   rG   r3   r  r   r  r  r  r  r  r6   rA   r)   r)   r*   r    s    zNode.__repr__c                 C  rI   )zOptional name of the node.rJ   rA   r)   r)   r*   r4     rK   z	Node.namerL   r9   c                 C  rM   r:   rJ   rN   r)   r)   r*   r4     rO   c                 C  rI   )zThe domain of the operator. For onnx operators, this is an empty string.

        .. note:
            When domain is `"ai.onnx"`, it is normalized to `""`.
        r  rA   r)   r)   r*   r     s   zNode.domainc                 C     t || _d S r:   r  r  rN   r)   r)   r*   r  )     c                 C  rI   )aU  Opset version of the operator called.

        If ``None``, the version is unspecified and will follow that of the graph.
        This property is special to ONNX IR to allow mixed opset usage in a graph
        for supporting more flexible graph transformations. It does not exist in the ONNX
        serialization (protobuf) spec.
        r  rA   r)   r)   r*   r  -     	zNode.versionc                 C  rM   r:   r9  rN   r)   r)   r*   r  8  rO   c                 C  rI   )z The name of the operator called.r   rA   r)   r)   r*   r  <  rK   zNode.op_typec                 C  rM   r:   r;  rN   r)   r)   r*   r  A  rO   c                 C  rI   )z7The overload name when the node is invoking a function.r  rA   r)   r)   r*   r  E  rK   zNode.overloadc                 C  rM   r:   r<  rN   r)   r)   r*   r  J  rO   Sequence[Value | None]c                 C  rI   )a  The input values of the node.

        The inputs are immutable. To change the inputs, create a new node and
        replace the inputs of the using nodes of this node's outputs by calling
        :meth:`replace_input_with` on the using nodes of this node's outputs.
        r  rA   r)   r)   r*   r	  N  r  zNode.inputs_r   c                 C  rQ  )Nz_Node.inputs cannot be assigned to. Please use 'resize_inputs' and 'replace_input_with' instead.AttributeErrorr;   r?  r)   r)   r*   r	  X     new_sizerQ   c                C  sf   t | j}||krdS ||k r't||D ]}| |d q| jd| | _dS | jd||   | _dS )a  Resize the inputs of the node.

        If the new size is greater than the current size, new inputs are added as None.
        If the new size is less than the current size, the extra inputs are removed.

        After ``inputs`` is resized, you can use :meth:`replace_input_with` to set the new inputs.

        .. versionadded:: 0.1.13

        Args:
            new_size: The new number of inputs.
        Nr:   )rX  r  r   replace_input_with)r;   rD  current_sizer  r)   r)   r*   resize_inputs_  s   
zNode.resize_inputsSequence[Node]c                 C  s8   i }| j D ]}|dur|  }durd||< qt|S )zQReturn the predecessor nodes of the node, deduplicated, in a deterministic order.N)r	  r  r  )r;   predecessorsrL   r  r)   r)   r*   rI  x  s   
zNode.predecessorsc                 C  s@   i }| j D ]}|dusJ d| D ]}d||j< qqt|S )zOReturn the successor nodes of the node, deduplicated, in a deterministic order.Nz.Bug: Output values are not expected to be None)r  usesr  r  )r;   
successorsrL   usager)   r)   r*   rK    s   
zNode.successorsr  Value | Nonec                   s~    dk s t | jkrtd  | j  }t fddt| jD | _|dur1||   dur=|   dS dS )z"Replace an input with a new value.r   zIndex out of range: c                 3  s$    | ]\}}| krn|V  qd S r:   r)   )r
  r  	old_inputr  rL   r)   r*   r    s    
z*Node.replace_input_with.<locals>.<genexpr>N)rX  r	  r   r  r  r  _remove_usager  )r;   r  rL   rN  r)   rO  r*   rE    s   

zNode.replace_input_withnodesNode | Iterable[Node]c                C  $   | j du r	td| j | | dS )a  Insert a node before this node in the list of nodes in the graph.

        It is the same as calling ``graph.insert_before(self, nodes)``.

        Example::

            Before: previous_node -> self
                    previous_node' -> node -> next_node'
            After:  previous_node -> node -> self
                    previous_node' -> next_node'

        Args:
            nodes: A node or a sequence of nodes to put before this node.
        Nz4The node to prepend to does not belong to any graph.)r  r   insert_beforer;   rQ  r)   r)   r*   prepend     
zNode.prependc                C  rS  )a  Insert a node after this node in the list of nodes in the graph.

        It is the same as calling ``graph.insert_after(self, nodes)``.

        Example::

            Before: previous_node -> self
                    previous_node' -> node -> next_node'
            After:  previous_node -> self -> node
                    previous_node' -> next_node'

        Args:
            nodes:  A node or a sequence of nodes to put after this node.
        Nz3The node to append to does not belong to any graph.)r  r   insert_afterrU  r)   r)   r*   r     rW  zNode.appendSequence[Value]c                 C  rI   )a  The output values of the node.

        The outputs are always attached to this node once initialized (immutable),
        except that the list can be resized to remove or add outputs.

        Use :meth:`resize_outputs` to change the number of outputs of the node.
        r  rA   r)   r)   r*   r    r:  zNode.outputsc                 C  rQ  )Nz]Node.outputs cannot be assigned to. Please use 'resize_outputs' or create a new node instead.r@  rB  r)   r)   r*   r    rC  c                  s   t  j}||krdS ||k rC j|d D ]}| r(td| d|  q j|d D ]}d|_d|_q0 jd|  _dS  fddt||D } jt|  _dS )a  Resize the outputs of the node.

        If the new size is greater than the current size, new output values are created.
        If the new size is less than the current size, the extra output values are removed.
        The removed output values must not have any uses.

        .. versionadded:: 0.1.13

        Args:
            new_size: The new number of outputs.

        Raises:
            ValueError: If the new size is less than the current size and
                the removed outputs have uses.
        NzCannot remove output z because it has uses: c                   s   g | ]}t  |d qS )r  r  r  rA   r)   r*   r        z'Node.resize_outputs.<locals>.<listcomp>)rX  r  rJ  r   r  r  r   r  )r;   rD  rF  r!  new_outputsr)   rA   r*   resize_outputs  s    
zNode.resize_outputs_graph_containers.Attributesc                 C  rI   )a  The attributes of the node as ``dict[str, Attr]`` with additional access methods.

        Use it as a dictionary with keys being the attribute names and values being the
        :class:`Attr` objects.

        Use ``node.attributes.add(attr)`` to add an attribute to the node.
        Use ``node.attributes.get_int(name, default)`` to get an integer attribute value.
        Refer to the :class:`~onnx_ir._graph_containers.Attributes` for more methods.
        r  rA   r)   r)   r*   r    s   zNode.attributesr^   c                 C  r_   r`   rb   rA   r)   r)   r*   rd      re   z	Node.metarZ   c                 C  r[   )zThe metadata properties of the node.

        The metadata properties are used to store additional information about the node.
        Unlike ``meta``, this property is serialized to the ONNX proto.
        Nr\   rA   r)   r)   r*   r7     r]   zNode.metadata_propsGraph | Nonec                 C  rI   )zsThe graph that the node belongs to.

        If the node is not added to any graph, this property is None.
        r  rA   r)   r)   r*   r    s   z
Node.graphc                 C  rM   r:   rb  rN   r)   r)   r*   r    rO   _protocols.OperatorIdentifierc                 C     | j | j| jfS )zReturn the operator identifier of the node.

        The operator identifier is a tuple of the domain, op_type and overload.
        )r  r   r  rA   r)   r)   r*   op_identifier"  s   zNode.op_identifierFrj   rk   rl   c                  s8   t d| j | jrt d| j  t j|d dS )zfPretty print the node.

        This method is used for debugging and visualization purposes.
        zNode: zDoc: rj   N)r   r4   r6   r   r   )r;   rk   r   r)   r*   r   )  s   zNode.display)r)   )r  r=   r  r=   r	  r
  r  r  r  r=   r  r6  r  r  r  r6  r  r  r4   r5   r6   r5   r7   r8   )r  r6  r  r  r"   r  r   r   r   rL   r=   r"   r9   rc  )rL   r6  r"   r9   )r"   r=  )r?  r   r"   r9   )rD  rQ   r"   r9   r"   rH  )r  rQ   rL   rM  r"   r9   )rQ  rR  r"   r9   )r"   rY  )r?  rY  r"   r9   r"   r_  r   r   r"   ra  )rL   ra  r"   r9   r"   rc  r   ) rG   r   r   r   r   r<   r  r  r  r   r4   r   r  r  r  r  r	  rG  rI  rK  rE  rV  r   r  r^  r  rd   r7   r  re  r   r*  r)   r)   r   r*   r  U  s    
I
0

	


	





$


r  c                   @  sn   e Zd ZdZdZdddddZedddZejd ddZedddZ	d!ddZ
d"ddZd#ddZdS )$_TensorTypeBasez*Tensor types that are non recursive types.r   r  Nr  r?   r   r  r5   r"   r9   c                C     || _ || _d S r:   rl  )r;   r?   r  r)   r)   r*   r<   :  s   
z_TensorTypeBase.__init__c                 C  rI   r:   r  rA   r)   r)   r*   r?   >  r  z_TensorTypeBase.dtyperL   c                 C  rM   r:   r  rN   r)   r)   r*   r?   B  rO   c                 C  rI   )z+Return the element type of the tensor type.r?  rA   r)   r)   r*   	elem_typeF  rK   z_TensorTypeBase.elem_typerQ   c                 C     t t| S r:   r  r   rA   r)   r)   r*   r  K  r  z_TensorTypeBase.__hash__r  r  rl   c                 C  s   | j |j urdS | j|jkS r  )rF   r?   r  r)   r)   r*   r  N  s   z_TensorTypeBase.__eq__r=   c                 C  "   | j jd d }| d| jdS Nr  r  )rF   rG   r?   r;   
short_namer)   r)   r*   r  S     z_TensorTypeBase.__repr__)r?   r   r  r5   r"   r9   r%  rL   r   r"   r9   r   r  r   rG   r   r   r   r   r<   r   r?   r   ro  r  r  r  r)   r)   r)   r*   rk  5  s    

rk  c                   @  s   e Zd ZdZdddZdS )
TensorTypez A type that represents a tensor.r"   r=   c                 C  r  r:   r?  rA   r)   r)   r*   r  \  ri  zTensorType.__str__Nr   )rG   r   r   r   r  r)   r)   r)   r*   rz  Y  s    rz  c                   @     e Zd ZdZdS )SparseTensorTypez'A type that represents a sparse tensor.NrG   r   r   r   r)   r)   r)   r*   r|  `      r|  c                   @  sn   e Zd ZdZdZdddddZed ddZejd!ddZed"ddZ	d#ddZ
d$ddZd%ddZdS )&_RecursiveTypeBasez4Base for recursive types like Optional and Sequence.
_elem_typer  Nrm  ro  _protocols.TypeProtocolr  r5   r"   r9   c                C  rn  r:   r  )r;   ro  r  r)   r)   r*   r<   i  s   
z_RecursiveTypeBase.__init__r   c                 C     | j jS r:   r  r?   rA   r)   r)   r*   r?   o  rw  z_RecursiveTypeBase.dtyperL   c                 C     || j _d S r:   r  rN   r)   r)   r*   r?   s  r  c                 C  rI   r:   )r  rA   r)   r)   r*   ro  w  r  z_RecursiveTypeBase.elem_typerQ   c                 C  rp  r:   rq  rA   r)   r)   r*   r  {  r  z_RecursiveTypeBase.__hash__r  r  rl   c                 C  s*   t |tsdS | j|jkrdS | j|jkS r  )r   r  rF   ro  r  r)   r)   r*   r  ~  s
   
z_RecursiveTypeBase.__eq__r=   c                 C  rr  rs  )rF   rG   ro  ru  r)   r)   r*   r    rw  z_RecursiveTypeBase.__repr__)ro  r  r  r5   r"   r9   r%  rx  )r"   r  r   r  r   ry  r)   r)   r)   r*   r  d  s    

r  c                   @  r{  )SequenceTypez.A type that represents a sequence of elements.Nr}  r)   r)   r)   r*   r    r~  r  c                   @  r{  )OptionalTypez+A type that represents an optional element.Nr}  r)   r)   r)   r*   r    r~  r  c                   @  sB   e Zd ZdZdddZdddZddd	Zdd
dZdddZdS )_OpHandlerProtocolaP  Protocol for an object that can handle magic methods on Values.

    .. note::
        Only the basic arithmetic magic methods are supported on Values.

        Importantly, ``__eq__`` is not included because Values may need to be compared for identity.
        For consistency, none of the other comparison operators are included.
    r"   r  c                 C  r  r:   r)   r;   lhsrhsr)   r)   r*   Add  r  z_OpHandlerProtocol.Addc                 C  r  r:   r)   r  r)   r)   r*   Sub  r  z_OpHandlerProtocol.Subc                 C  r  r:   r)   r  r)   r)   r*   Mul  r  z_OpHandlerProtocol.Mulc                 C  r  r:   r)   r  r)   r)   r*   Div  r  z_OpHandlerProtocol.Divc                 C  r  r:   r)   )r;   operandr)   r)   r*   Neg  r  z_OpHandlerProtocol.NegN)r"   r  )	rG   r   r   r   r  r  r  r  r  r)   r)   r)   r*   r    s    
	


r  handler_OpHandlerProtocol | Nonec                 C  s   t j}| t _|S )a  Set the magic handler for Value arithmetic methods.

    Framework authors can implement custom context managers that set
    the magic handler to enable arithmetic operations on Values.

    Example::
        class MyOpHandler:
            def Add(self, lhs, rhs):
                # Implement addition logic here
                pass
            ...

        @contextlib.contextmanager
        def graph_context(graph):
            old_handler = onnx_ir.set_value_magic_handler(MyOpHandler(graph))
            try:
                yield
            finally:
                onnx_ir.set_value_magic_handler(old_handler)

    Args:
        handler: The magic handler to set.

    Returns:
        The previous magic handler.
    )WithArithmeticMethods_magic_handler)r  old_handlerr)   r)   r*   set_value_magic_handler  s   r  c                   @  sn   e Zd ZU dZdZde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dd ZdS )r  zMixin class that adds arithmetic methods to Value.

    This class is used to add arithmetic methods to Value that support arithmetic operations.
    Nz#ClassVar[_OpHandlerProtocol | None]r  c                 C  s   | j d u r	td| j S )NzWNo magic handler is set. Please use 'onnx_ir.set_value_magic_handler' to set a handler.)r  r   rA   r)   r)   r*   _get_magic_handler  s
   
z(WithArithmeticMethods._get_magic_handlerc                C     |   | |S r:   r  r  r  r)   r)   r*   __add__  r  zWithArithmeticMethods.__add__c                C  r  r:   r  r  r  r)   r)   r*   __sub__  r  zWithArithmeticMethods.__sub__c                C  r  r:   r  r  r  r)   r)   r*   __mul__  r  zWithArithmeticMethods.__mul__c                C  r  r:   r  r  r  r)   r)   r*   __truediv__  r  z!WithArithmeticMethods.__truediv__c                 C  s   |   | S r:   )r  r  rA   r)   r)   r*   __neg__  r  zWithArithmeticMethods.__neg__c                C     |   || S r:   r  r  r)   r)   r*   __radd__  r  zWithArithmeticMethods.__radd__c                C  r  r:   r  r  r)   r)   r*   __rsub__  r  zWithArithmeticMethods.__rsub__c                C  r  r:   r  r  r)   r)   r*   __rmul__  r  zWithArithmeticMethods.__rmul__c                C  r  r:   r  r  r)   r)   r*   __rtruediv__  r  z"WithArithmeticMethods.__rtruediv__)rG   r   r   r   r  r  r  r  r  r  r  r  r  r  r  r  r)   r)   r)   r*   r    s   
 r  c                	   @  s  e Zd ZdZdZ	d\ddddddddd]ddZd^ddZd^ddZd^ddZe	d_d d!Z
d`d#d$Zdad%d&Zdbd(d)Zdcd*d+Zddd-d.Zded2d3Zded4d5Ze	dfd6d7Zejdgd9d7Ze	dhd:d;Zejdid<d;Ze	djd>d?ZejdkdAd?Ze	dldBdCZejdmdDdCZe	dndEdFZejdodGdFZe	dpdIdJZe	dqdLdMZd`dNdOZd`dPdQZd`dRdSZ	TdrdsdWdXZdtdZd[ZdS )ur  a  IR Value.

    A value is a named entity that can be used to represent an input or output of a graph,
    a function, or a node. The information it stores generalizes over ``ValueInfoProto``
    in the ONNX specification.

    A :class:`Value` is always not owned or owned by exactly one node. When the value is not
    owned, it must be an input of a graph or a function. ``producer`` and ``index``
    are ``None``.

    When the value is owned by a node, it is an output of the node.
    The node that produces the value can be accessed with :meth:`producer`.
    The index of the output of the node that produces the value can be accessed with
    :meth:`index`.

    To find all the nodes that use this value as an input, call :meth:`uses`. Consuming
    nodes can be obtained with :meth:`consumers`.

    To check if the value is an is an input, output or initializer of a graph,
    use :meth:`is_graph_input`, :meth:`is_graph_output` or :meth:`is_initializer`.

    Use :attr:`graph` to get the graph that owns the value.

    .. note:: Magic methods
        Only the basic arithmetic magic methods are supported on Values.

        Importantly, ``__eq__`` is not included because Values may need to be compared for identity.
        For consistency, none of the other comparison operators are included.

    .. versionadded:: 0.1.14
        Value now supports arithmetic magic methods when a handler is set via
        :func:`onnx_ir.set_value_magic_handler`.
    )_const_valuer  r  _is_graph_input_is_graph_output_is_initializerr   r2   r3   r  r   _type_usesr6   N)r  r4   r@   r   r6   r  r7   r  Node | Noner  r6  r4   r5   r@   r   r   _protocols.TypeProtocol | Noner6   r   _protocols.TensorProtocol | Noner7   r8   r"   r9   c          	      C  sX   || _ || _d| _|| _|| _|| _|| _|| _i | _|| _	d| _
d| _d| _d| _dS )a  Initialize a value.

        When assigning a name to the value, the name of the backing `const_value` (Tensor)
        will also be updated. If the value is an initializer of a graph, the initializers
        dictionary of the graph will also be updated.

        .. versionchanged:: 0.1.10
            Assigning a name to the value will also update the graph initializer entry
            if the value is an initializer of a graph.

        Args:
            producer: The node that produces the value.
                It can be ``None`` when the value is initialized first than its producer.
            index: The index of the output of the defining node.
            name: The name of the value.
            shape: The shape of the value.
            type: The type of the value.
            doc_string: The documentation string.
            const_value: The constant tensor if the value is constant.
            metadata_props: Metadata that will be serialized to the ONNX file.
        NF)r  r  r   r2   r3   r   r  r  r  r6   r  r  r  r  )	r;   r  r  r4   r@   r   r6   r  r7   r)   r)   r*   r<   %	  s   !
zValue.__init__r=   c              	   C  s   | j r| j ndtt|  }| jd urd| jnd}| jd ur&d| jnd}|  }|d u r3d}n|j d ur@d|j  d}ndt| }|  d urTd|   nd}|  }|rad	| }| jj	 d
|| | | | | d	S )Nr'  z, type=rn   z, shape=z, producer='r  z, producer=anonymous_node:z, index=z, const_value=r2  r  )
r4   r=   r(  r   r@   r  r  _constant_tensor_partrF   rG   )r;   
value_name	type_text
shape_textr  producer_text
index_textconst_value_textr)   r)   r*   r  _	  s   

(zValue.__repr__c              	   C  st   | j d ur| j ndtt|  }| jd urt| jnd}| jd ur&t| jnd}dt| d| d| d|   S )Nr'  ?r&  rD   r>   rE   )r4   r=   r(  r@   r   r  r  )r;   r  r  r  r)   r)   r*   r  p	  s
    "zValue.__str__c                 C  s:   | j dur| j jdkrd| j  dS d| j jj dS dS )z@Display string for the constant tensor attached to str of Value.Nr  r  r  z(...)}rn   )r  rU   rF   rG   rA   r)   r)   r*   r  {	  s
   
zValue._constant_tensor_partra  c                 C  s&   | j dur| j S | jdur| jjS dS )aK  Return the graph that defines this value.

        When the value is an input/output/initializer of a graph, the owning graph
        is that graph. When the value is an output of a node, the owning graph is the
        graph that the node belongs to. When the value is not owned by any graph,
        it returns ``None``.
        N)r  r  r  rA   r)   r)   r*   r  	  s
   
	
zValue.graphrl   c                 C  s(   | j p| jp| j}|r| jdusJ |S )z-Return True if the value is owned by a graph.N)r  r  r  r  )r;   r"  r)   r)   r*   _owned_by_graph	  s   zValue._owned_by_graphc                 C  rI   )a  The node that produces this value.

        When producer is ``None``, the value does not belong to a node, and is
        typically a graph input or an initializer. You can use :meth:`graph``
        to find the graph that owns this value. Use :meth:`is_graph_input`, :meth:`is_graph_output`
        or :meth:`is_initializer` to check if the value is an input, output or initializer of a graph.
        )r  rA   r)   r)   r*   r  	  r  zValue.producerrH  c                 C  s   t dd | jD S )z8Return the nodes (deduplicated) that consume this value.c                 S  s   i | ]}|j d qS r:   )r  )r
  rL  r)   r)   r*   
<dictcomp>	  r  z#Value.consumers.<locals>.<dictcomp>r  r  rA   r)   r)   r*   	consumers	  s   zValue.consumersc                 C  rI   )z-The index of the output of the defining node.)r  rA   r)   r)   r*   r  	  r  zValue.indexCollection[Usage]c                 C  r  )zReturn a set of uses of the value.

        The set contains tuples of ``(Node, index)`` where the index is the index of the input
        of the node. For example, if ``node.inputs[1] == value``, then the use is ``(node, 1)``.
        r  rA   r)   r)   r*   rJ  	  s   

z
Value.usesuser  rQ   c                 C  s   d| j t||< dS )ztAdd a usage of this value.

        This is an internal method. It should only be called by the Node class.
        N)r  r  r;   r  r  r)   r)   r*   r  	  s   zValue._add_usagec                 C  s   | j t|| dS )zRemove a node from the uses of this value.

        This is an internal method. It should only be called by the Node class.
        N)r  popr  r  r)   r)   r*   rP  	  s   zValue._remove_usagec                 C  rI   r:   rJ   rA   r)   r)   r*   r4   	  r  z
Value.namerL   c                 C  s   | j |krd S |  }|r5|d u rtd| j}|d usJ ||jv r5|j| | ur5td|  d| d| jd ur>|| j_| j }|| _ |rj|d usNJ d| j}|d usWJ |d us]J |j| | |j|< d S d S )NzhInitializer value cannot have name set to None. Please pop() the value from initializers first to do so.zCannot rename initializer 'z' to 'z0': an initializer with that name already exists.zdebug: Should be guarded above)r3   is_initializerr   r  initializersr  r4   r  )r;   rL   r  r  old_namer)   r)   r*   r4   	  s4   

c                 C  rI   )zThe type of the tensor.

        Example types can be ``TensorType``, ``SparseTensorType``, ``SequenceType``, ``OptionalType``.
        To obtain the data type of the tensor, use ``type.dtype`` or conveniently
        :attr:`dtype`.
        r  rA   r)   r)   r*   r   	  r  z
Value.typec                 C  rM   r:   r  rN   r)   r)   r*   r   	  rO   r   c                 C  s   | j du rdS | j jS )zThe data type of the tensor.N)r  r?   rA   r)   r)   r*   r?   	  s   
zValue.dtyper   c                 C  s$   | j du rt|| _ dS || j _dS )zSet the data type of the tensor.

        If the type is not set, it will be initialized to a new TensorType. To
        set the type as other types like ``SequenceType``, initialize the type
        then set :attr:`type` instead.
        N)r  rz  r?   rN   r)   r)   r*   r?   
  s   
c                 C  rI   r:   r  rA   r)   r)   r*   r@   
  r  zValue.shapec                 C  s:   |d u r	d | _ d S t|tr|| _ d S tdt| d)Nz+Expected value to be a Shape or None, got 'r  )r   r   r   r   r   rN   r)   r)   r*   r@   
  s   
c                 C  rI   )aJ  The backing constant tensor for the value.

        If the ``Value`` has a ``const_value`` and is part of a graph initializers
        dictionary, the value is an initialized value. Its ``const_value``
        will appear as an ``initializer`` in the GraphProto when serialized.

        If the ``Value`` is not part of a graph initializers dictionary, the ``const_value``
        field will be ignored during serialization.

        ``const_value`` can be backed by different raw data types, such as numpy arrays.
        The only guarantee is that it conforms TensorProtocol.
        )r  rA   r)   r)   r*   r   
  s   zValue.const_valuec                 C  s8   t jr|d urt|tjstdt| d|| _d S )Nz4Expected value to be a TensorProtocol or None, got 'r  )r8  r9  r   r   TensorProtocolr   r   r  rN   r)   r)   r*   r  2
  s   
r^   c                 C  r_   r`   rb   rA   r)   r)   r*   rd   >
  re   z
Value.metarZ   c                 C  r[   )zThe metadata properties of the value.

        The metadata properties are used to store additional information about the value.
        Unlike ``meta``, this property is serialized to the ONNX proto.
        Nr\   rA   r)   r)   r*   r7   I
  r]   zValue.metadata_propsc                 C  rI   )z)Whether the value is an input of a graph.)r  rA   r)   r)   r*   is_graph_inputT
  r  zValue.is_graph_inputc                 C  rI   )z*Whether the value is an output of a graph.)r  rA   r)   r)   r*   is_graph_outputX
  r  zValue.is_graph_outputc                 C  rI   )z/Whether the value is an initializer of a graph.)r  rA   r)   r)   r*   r  \
  r  zValue.is_initializerFreplace_graph_outputsreplacementc                C  s|   |   r-| j}|dusJ |st| d|jdt|jD ]\}}|| u r,||j|< q|  D ]
\}}||| q1dS )a:  Replace all uses of this value with another value.

        .. tip::
            **Handling graph outputs**

            To also replace graph outputs that reference the values being replaced, either
            set ``replace_graph_outputs`` to True, or manually update the graph outputs
            before calling this function to avoid an error being raised when ``replace_graph_outputs=False``.

            Be careful when a value appears multiple times in the graph outputs -
            this is invalid. An identity node will need to be added on each duplicated
            outputs to ensure a valid ONNX graph.

            You may also want to assign the name of this value to the replacement value
            to maintain the name when it is a graph output.

        To replace usage of a sequence of values with another sequence of values, consider using
        :func:`onnx_ir.convenience.replace_all_uses_with`.

        .. versionadded:: 0.1.12

        Args:
            replacement: The value to replace all uses with.
            replace_graph_outputs: If True, graph outputs that reference this value
                will also be updated to reference the replacement.

        Raises:
            ValueError: When ``replace_graph_outputs`` is False && when the value to
                replace is a graph output.
        Nz is an output of graph zh. Set replace_graph_outputs=True or replace the graph output frist before calling replace_all_uses_with.)r  r  r   r4   r  r  rJ  rE  )r;   r  r  r  r  r!  	user_noder  r)   r)   r*   replace_all_uses_with`
  s   %
zValue.replace_all_uses_withr  c                  s    du rdS j }|du r  _dS |jr| }t|t kr-td d   fdd}tt| D ]\}\}}|||||< q;|_dS )a  Merge the shape of this value with another shape to update the existing shape, with the current shape's dimensions taking precedence.

        Two dimensions are merged as follows:

        * If both dimensions are equal, the merged dimension is the same.
        * If one dimension is SymbolicDim and the other is concrete, the merged dimension is the concrete one.
        * If both dimensions are SymbolicDim, a named symbolic dimension (non-None value) is preferred over an unnamed one (None value).
        * In all other cases where the dimensions differ, the current shape's dimension is taken (a warning is emitted when both are concrete integers).

        .. versionadded:: 0.1.14

        Args:
            other: The other shape to merge with.

        Returns:
            A new shape that is the result of merging this shape with the other shape.

        Raises:
            ValueError: If the shapes have different ranks.
            ValueError: If there are conflicting concrete dimensions.
        Nz)Shapes must have the same rank, got self=z, other=c              
     sp   | |kr| S t | tr!t |tr!td|  d| d d  d	t | ts(| S t |ts/|S | jd u r6|S | S )NzConflicting dimensions z and z when merging shapes r   )r   rQ   r   r  rL   )dim1dim2r  r;   r)   r*   
merge_dims
  s"   


z&Value.merge_shapes.<locals>.merge_dims)r@   r  r   r   rX  r   r  zip)r;   r  merged_shaper  r  r  r  r)   r  r*   merge_shapes
  s   

zValue.merge_shapesr:   )r  r  r  r6  r4   r5   r@   r   r   r  r6   r5   r  r  r7   r8   r"   r9   r   ri  rd  )r"   r  rg  rc  )r"   r  )r  r  r  rQ   r"   r9   r   r   )r"   r  )rL   r  r"   r9   )r"   r   rx  )r"   r   )rL   r   r"   r9   )r"   r  )rL   r  r"   r9   r   r   r  )r  rl   r  r  r"   r9   )r  r   r"   r9   )rG   r   r   r   r   r<   r  r  r  r   r  r  r  r  r  rJ  r  rP  r4   r   r   r?   r@   r  rd   r7   r  r  r  r  r  r)   r)   r)   r*   r    sn    "
:










$		




7z9Input is deprecated since 0.1.9. Use ir.val(...) instead.r4   r5   r@   r   r   r  r6   c                 C  s   t | |||dS )zCreate an input of a Graph or a Function.

    This is equivalent to calling ``Value(name=name, shape=shape, type=type, doc_string=doc_string)``.
    r4   r@   r   r6   r  r  r)   r)   r*   Input
  s   r  r  	to_removeAbstractSet[Node]graph_outputsAbstractSet[Value]c                   sX   | j D ]&}||v rtd| d fdd| D }|r)td|d|dqdS )	a   Check if a node is safe to remove.

    1. It checks to make sure there are no users of the node that are not
        to be removed before removing it.
    2. It checks the node does not contribute to any graph outputs.

    This check is typically O(1) assuming the number of uses of the node is small

    Args:
        node: The node to check.
        to_remove: A set of nodes that are to be removed.
            This set is used to check if the node is still being used by other
            nodes that are not to be removed.
        graph_outputs: A set of values that are outputs of the graph.

    Raises:
        ValueError: If the node does not belong to this graph or if there are users of the node.
        ValueError: If the node is still being used by other nodes not to be removed.
    zNode 'zG' is still an output of the graph and cannot be removed when safe=True.c                   s   g | ]
\}}| vr|qS r)   r)   )r
  userr?  r  r)   r*   r  
      z._check_node_safe_to_remove.<locals>.<listcomp>zOutput value 'zm' is still being used by other nodes that are not to be removed. All of its users that is not being removed: zD. Please make sure these nodes are no longer using the output value.N)r  r   rJ  )r  r  r  r!  uses_not_to_remover)   r  r*   _check_node_safe_to_remove
  s   

r  c                   @  s  e Zd ZdZdZdddddddiddZedjddZedjddZedkddZ	dld!d"Z
edmd#d$Zejdnd%d$Zedod'd(Zejdpd,d-Zejdqd0d-Zd1d- Zdrd2d3Zdsd5d6Zdsd7d8Zd9d: Zdtd<d=Zdud@dAZdrdBdCZdsdDdEZdvdGdHZdwdxdLdMZdydNdOZdzdPdQZdwd{dTdUZd|dXdYZd|dZd[Zd}d\d]Z ed~d_d`Z!eddbdcZ"ddedfZ#ddgdhZ$dS )Graphar  IR Graph.

    Graph represents a computation graph. In addition to the ONNX specification
    specified fields, it also contains a mapping of :attr:`opset_imports`. This
    allows different subgraphs to import different opsets. It is the responsibility
    of the deserializer to reconcile the different opsets.

    The `nodes` are not guaranteed to be topologically sorted. But the
    iteration order should be deterministic across different runs. It is the
    responsibility of the user to maintain a topological order of the nodes.

    Note that there is not a ``node`` attribute in the Graph. The Graph can be
    seen as a Sequence of nodes and should be used as such. For example, to obtain
    all nodes as a list, call ``list(graph)``.

    .. versionchanged:: 0.1.1
        Values with non-none producers will be rejected as graph inputs or initializers.

    .. versionadded:: 0.1.1
        Added ``add`` method to initializers and attributes.

    Attributes:
        name: The name of the graph.
        inputs: The input values of the graph.
        outputs: The output values of the graph.
        initializers: The initializers in the graph.
        doc_string: Documentation string.
        opset_imports: Opsets imported by the graph.
        metadata_props: Metadata that will be serialized to the ONNX file.
        meta: Metadata store for graph transform passes.
    )
r1   _initializersr  r   r2   r   _nodes_opset_importsr  r4   r)   Nr  r6   opset_importsr4   r7   r	  rY  r  rQ  Iterable[Node]r  r6   r5   r  dict[str, int] | Noner4   r7   r8   c          	      C  s   || _ t| || _t| || _t| dd |D | _|| _|p#i | _	d | _
|| _t | _t | _|   | | d S )Nc                 S  s   i | ]}|j |qS r)   )r4   )r
  initializerr)   r)   r*   r  E  r  z"Graph.__init__.<locals>.<dictcomp>)r4   r   GraphInputsr  GraphOutputsr  GraphInitializersr  r1   r  r   r2   r   DoublyLinkedSetr  r   NameAuthority:_set_input_and_initializer_value_names_into_name_authorityextend)	r;   r	  r  rQ  r  r6   r  r4   r7   r)   r)   r*   r<   3  s   


zGraph.__init__r"   MutableSequence[Value]c                 C  rI   r:   r>  rA   r)   r)   r*   r	  T  r  zGraph.inputsc                 C  rI   r:   rZ  rA   r)   r)   r*   r  X  r  zGraph.outputs#_graph_containers.GraphInitializersc                 C  rI   )a  The initializers of the graph as a ``dict[str, Value]``.

        The keys are the names of the initializers. The values are the :class:`Value` objects.

        This property additionally supports the ``add`` method, which takes a :class:`Value`
        and adds it to the initializers if it is not already present.

        .. note::
            When setting an initializer with ``graph.initializers[key] = value``,
            if the value does not have a name, it will be assigned ``key`` as its name.

        )r  rA   r)   r)   r*   r  \  s   zGraph.initializersrL   r  r9   c                 C  sp   |j s
td||j | jv r#| j|j  |ur#td|j  d||jdu r0td|d| j| dS )av  Register an initializer to the graph.

        This is a convenience method to register an initializer to the graph with
        checks.

        Args:
            value: The :class:`Value` to register as an initializer of the graph.
                It must have its ``.const_value`` set.

        Raises:
            ValueError: If a value of the same name that is not this value
                is already registered.
            ValueError: If the value does not have a name.
            ValueError: If the initializer is produced by a node.
            ValueError: If the value does not have its ``.const_value`` set.
        Initializer must have a name: zInitializer 'zi' is already registered, but it is not the same object: existing={self._initializers[value.name]!r}, new=NzValue 'z5' must have its const_value set to be an initializer.)r4   r   r  r  addrN   r)   r)   r*   register_initializerl  s   


zGraph.register_initializerc                 C  rI   r:   rP   rA   r)   r)   r*   r6     r  zGraph.doc_stringc                 C  rM   r:   rP   rN   r)   r)   r*   r6     rO   dict[str, int]c                 C  rI   r:   )r  rA   r)   r)   r*   r    r  zGraph.opset_importsr  rQ   r  c                 C  r  r:   r)   r  r)   r)   r*   r    r  zGraph.__getitem__r  rH  c                 C  r  r:   r)   r  r)   r)   r*   r    r  c                 C  r  r:   r  r  r)   r)   r*   r    r  c                 C  r  r:   rX  r  rA   r)   r)   r*   r    r  zGraph.__len__Iterator[Node]c                 C  r  r:   r  r  rA   r)   r)   r*   r    r  zGraph.__iter__c                 C  r  r:   reversedr  rA   r)   r)   r*   __reversed__  r  zGraph.__reversed__c                 C  s8   | j D ]}| j| q| j D ]}| j| qd S r:   )r	  r   register_or_name_valuer  r  rN   r)   r)   r*   r    s
   
z@Graph._set_input_and_initializer_value_names_into_name_authorityr  c                 C  sR   |j dur|j | urtd|d| j| |jD ]}| j| q| |_ |S )zcSet the graph reference for the node and assign names to it and its outputs if they don't have one.N
The node 'zG' belongs to another graph. Please remove it first with Graph.remove().)r  r   r   register_or_name_noder  r  )r;   r  rL   r)   r)   r*   (_set_node_graph_to_self_and_assign_names  s   

z.Graph._set_node_graph_to_self_and_assign_namesindex_or_name	int | strc                C  s>   t |tr	| | S | D ]}|j|kr|  S qtd| d)a  Get a node by index or name.

        This is an O(n) operation. Getting nodes on the ends of the graph (0 or -1) is O(1).

        .. note::
            If you need repeated random access, consider turning it into a list with ``list(graph)`` .
            Or a dictionary for repeated access by name: ``{node.name for node in graph}`` .

        When a name is provided and if there are multiple nodes with the same name,
        the first node with the name is returned.

        Args:
            index_or_name: The index or name of the node.

        Returns:
            The node if found.

        Raises:
            IndexError: If the index is out of range.
            ValueError: If the node with the given name is not found.
        zNode with name 'z' not found.)r   rQ   r4   r   )r;   r  r  r)   r)   r*   r    s   

z
Graph.nodec                 C     t | S )a8  Get the number of nodes in the graph in O(1) time.

        Note that this method returns the number of nodes this graph directly contains.
        It does not count nodes in subgraphs.

        This is an alias for ``len(graph)``. Use this if you prefer a more descriptive
        name for readability.
        rp  rA   r)   r)   r*   	num_nodes  s   
zGraph.num_nodesc                 C     t j| S aJ  Get all nodes in the graph and its subgraphs in O(#nodes + #attributes) time.

        This is an alias for ``onnx_ir.traversal.RecursiveGraphIterator(graph)``.
        Consider using
        :class:`onnx_ir.traversal.RecursiveGraphIterator` for more advanced
        traversals on nodes.

        .. versionadded:: 0.1.2
        r8  	traversalRecursiveGraphIteratorrA   r)   r)   r*   	all_nodes     zGraph.all_nodesIterator[Graph]c                 #  >    i  d fdd}t jj|dD ]}q  E dH  dS )ziGet all subgraphs in the graph in O(#nodes + #attributes) time.

        .. versionadded:: 0.1.2
        r"   r9   c                   B   | u rd S t | tstdt|  d|  vrd  | < d S d S NzExpected a Graph, got z. The model may be invalidr   r  r   r   r  seen_graphsr;   r)   r*   enter_subgraph     
z'Graph.subgraphs.<locals>.enter_subgraphenter_graphNr   r8  r  r  keysr;   r  r?  r)   r  r*   	subgraphs  s   
zGraph.subgraphsFallow_outer_scope_valuesrl   c                 C  s*   ddl m} |ji i i d|d}|| S )au  Create a deep copy of this graph in O(#nodes + #values) time.

        All nodes, values, and subgraphs are cloned. The cloned graph will have
        the same structure as this graph, but all nodes and values will be different
        objects.

        Tensors in initializers and constant values will be shared.

        .. versionadded:: 0.1.14
        .. versionadded:: 0.1.15
            Added ``allow_outer_scope_values`` argument.

        Args:
            allow_outer_scope_values: When True, values that are from outer scopes
                (not defined in this graph) will not be cloned. Instead, the cloned
                graph will reference the same outer scope values. This is useful
                when cloning subgraphs that reference values from the outer graph.
                When False (default), values from outer scopes will cause an error if they
                are referenced in the cloned graph.

        Returns:
            A deep copy of this graph.

        Raises:
            ValueError: If ``allow_outer_scope_values`` is False and the graph
                references values from outer scopes.
        r   _clonerF)attr_map	value_mapr7   resolve_ref_attrsr  r8  r  Clonerclone_graph)r;   r  r  clonerr)   r)   r*   clone
  s   
zGraph.clonec                C  s   |  | | j| dS )a  Append a node to the graph in O(1) time.

        Unique names will be assigned to the node and its values if any name is ``None``.

        Args:
            node: The node to append.

        Raises:
            ValueError: If the node belongs to another graph.
        N)r  r  r   r;   r  r)   r)   r*   r   2  s   
zGraph.appendc                  s"    fdd|D } j | dS )a5  Extend the graph with the given nodes in O(#new_nodes) time.

        Unique names will be assigned to the node and its values if any name is ``None``.

        Args:
            nodes: The nodes to extend the graph with.

        Raises:
            ValueError: If any node belongs to another graph.
        c                      g | ]}  |qS r)   r  r
  r  rA   r)   r*   r  K      z Graph.extend.<locals>.<listcomp>N)r  r  rU  r)   rA   r*   r  @  s   zGraph.extendsaferR  c                C  s   t |ts	|h}nt|}t| j}|D ]}|j| ur#td|d|r+t||| q|D ]}|rBtt|j	D ]}|
|d q9d|_| j| q.dS )a  Remove nodes from the graph in O(#num of nodes to remove) time.

        If any errors are raise, to ensure the graph is not left in an inconsistent state,
        the graph is not modified.

        Args:
            nodes: The node to remove.
            safe: If True, performs the following actions before removal:

                1. It checks to make sure there are no users of the node that are not
                to be removed before removing it.
                2. It checks the node does not contribute to any graph outputs.
                3. It removes references to all inputs so it is no longer a user of other nodes.

        Raises:
            ValueError: If any node to remove does not belong to this graph.
            ValueError: (When ``safe=True``) If the node does not belong to this graph or if there are users of the node.
            ValueError: (When ``safe=True``) If the node is still being used by other nodes not to be removed.
        r  z ' does not belong to this graph.N)r   r   	frozensetr  r  r   r  r   rX  r	  rE  r  remove)r;   rQ  r*  	nodes_setr  r  r  r)   r)   r*   r,  N  s"   


zGraph.remove	new_nodesIterable[Node] | Nodec                  4   t |tr|f} fdd|D } j|| dS )aZ  Insert new nodes after the given node in O(#new_nodes) time.

        Unique names will be assigned to the node and its values if any name is ``None``.

        Args:
            node: The node to insert after.
            new_nodes: The new nodes to insert.

        Raises:
            ValueError: If any node belongs to another graph.
        c                   r&  r)   r'  r(  rA   r)   r*   r    r)  z&Graph.insert_after.<locals>.<listcomp>N)r   r  r  rX  r;   r  r.  r)   rA   r*   rX  v     
zGraph.insert_afterc                  r0  )a\  Insert new nodes before the given node in O(#new_nodes) time.

        Unique names will be assigned to the node and its values if any name is ``None``.

        Args:
            node: The node to insert before.
            new_nodes: The new nodes to insert.

        Raises:
            ValueError: If any node belongs to another graph.
        c                   r&  r)   r'  r(  rA   r)   r*   r    r)  z'Graph.insert_before.<locals>.<listcomp>N)r   r  r  rT  r1  r)   rA   r*   rT    r2  zGraph.insert_beforec                   s  t tj| }dd dd |D D }t|ddd |D dd t|D  dfdd}|D ]N}|jD ]}|du r@q9| }||| q9|j	
 D ]2}t|tsWqO|jtjjkrj|jD ]}||| qaqO|jtjjkr|jD ]}|D ]}||| qxqtqOq4 fdd|D }	t|	 d}
|	rt|	\}}|jdusJ ||j | |
d7 }
| D ]}|  d8  < | dkrt|	 | |f q|	s|
t|krtd| D ]\}}|t| qdS )aw  Perform a topological sort of this graph and all subgraphs in O(#nodes + #values) time.

        This sort is stable. It preserves the original order as much as possible.

        Reference: https://github.com/madelson/MedallionTopologicalSort#stable-sort

        Raises:
            ValueError: If the graph contains a cycle, making topological sorting impossible.
        c                 S     i | ]}|g qS r)   r)   )r
  r  r)   r)   r*   r    s    zGraph.sort.<locals>.<dictcomp>c                 S  s   h | ]
}|j d ur|j qS r:   r  r(  r)   r)   r*   	<setcomp>  r  zGraph.sort.<locals>.<setcomp>r   c                 S  r3  r)   r)   r(  r)   r)   r*   r    s    c                 S  s   i | ]\}}|| qS r)   r)   )r
  r  r  r)   r)   r*   r    r\  childr  predecessorr  r"   r9   c                   s.   |du rdS |   |  |  d7  < dS )zHAdd a predecessor of a node, and increment the depth of the predecessor.Nr  )r   )r5  r6  )
node_depthnode_predecessorsr)   r*   add_predecessor  s   z#Graph.sort.<locals>.add_predecessorNc                   s$   g | ]}| d kr | |fqS )r   r)   r(  )neg_node_indexr7  r)   r*   r    s    zGraph.sort.<locals>.<listcomp>r  z9Graph contains a cycle, topological sort is not possible.)r5  r  r6  r  r"   r9   )r  r8  r  r  dictfromkeysr  r	  r  r  r  r   Attrr   r   AttributeTypeGRAPHrL   GRAPHSheapqheapifyheappopr  r   heappushrX  r   r-  r  r  )r;   rQ  sorted_nodes_by_graphr9  r  r  predecessor_nodeattrattribute_graphpriority_queuenum_of_sorted_nodesr?  current_noder  sorted_nodesr)   )r:  r7  r8  r*   sort  sf   




z
Graph.sortr^   c                 C  r_   r`   rb   rA   r)   r)   r*   rd     re   z
Graph.metarZ   c                 C  r[   )zThe metadata properties of the graph.

        The metadata properties are used to store additional information about the graph.
        Unlike ``meta``, this property is serialized to the ONNX proto.
        Nr\   rA   r)   r)   r*   r7     r]   zGraph.metadata_propsr=   c                 C  r  r:   
_graph_strrA   r)   r)   r*   r    ri  zGraph.__str__c                 C  r  r:   _graph_reprrA   r)   r)   r*   r    ri  zGraph.__repr__r	  rY  r  rY  rQ  r  r  rY  r6   r5   r  r  r4   r5   r7   r8   r"   r  )r"   r  )rL   r  r"   r9   r   r   r"   r  r  rQ   r"   r  r  r  r"   rH  r   r"   r  )r  r  r"   r  )r  r   r"   r  r"   r
  r  )r  rl   r"   r  r  r  r"   r9   rQ  r  r"   r9   r*  rl   rQ  rR  r"   r9   r  r  r.  r/  r"   r9   r   r   r   r   )%rG   r   r   r   r   r<   r   r	  r  r  r  r6   r   r  r  r  r  r  r  r  r  r  r  r  r  r  r$  r   r  r,  rX  rT  rM  rd   r7   r  r  r)   r)   r)   r*   r    sb     !
 








(

(

e


r  r  Graph | GraphViewc                 C  s  dd dd | jD  }dd dd | jD  }d dd | j D }|r3dt|d d	 }d
| jp>dtt	|   dt|d dt|d dt|d d	}t
| }t
t|}g }t| D ]5\}}	|	jrq|	jndt	|	 }
d|
 d|	 }t|d|d  }| }||d| d|  qgd dd | jD }dtd |d td| d d }| d| S )z,Return a string representation of the graph.rw   ,
c                 s  ro  r:   r  r)  r)   r)   r*   r    r  z_graph_str.<locals>.<genexpr>c                 s  ro  r:   r  r)  r)   r)   r*   r    r  c                 s  ro  r:   r  r)  r)   r)   r*   r    r  
initializers=(
    
),zgraph(
    name=anonymous_graph:,
    inputs=(        
    ),
    outputs=(
    ),
):anonymous_node:# r  rD  rE    |  r%  c                 s  ro  r:   r  r)  r)   r)   r*   r  6  r  {

return 
})r   r	  r  r  r  textwrapindentr4   r=   r(  rX  r  r	  r   )r  r/  r1  initializers_text	signature
node_countnumber_width
node_linesr  r  	node_name	node_textindented_node_textreturnsbodyr)   r)   r*   rO    sD   


rO  c                 C  s   dd dd | jD  }dd dd | jD  }d dd | j D }|r3dt|d d	 }| jj d
| j	pBdt
t|  dt|d dt|d dt|d dt|  dS )z#Return an repr string of the graph.rw   r^  c                 s  ro  r:   r  r)  r)   r)   r*   r  C  r  z_graph_repr.<locals>.<genexpr>c                 s  ro  r:   r  r)  r)   r)   r*   r  D  r  c                 s  ro  r:   r  r)  r)   r)   r*   r  E  r  r_  r`  ra  z(
    name=rb  rc  rd  re  rf  z
    len()=rg  )r   r	  r  r  r  rn  ro  rF   rG   r4   r=   r(  rX  )r  r/  r1  rp  r)   r)   r*   rQ  A  s$   


rQ  c                   @  s   e Zd ZdZdZddddddd4ddZejd5ddZejd6ddZdd Zd7dd Z	d8d"d#Z
d8d$d%Zed9d'd(Zed:d*d+Zd;d-d.Zd;d/d0Zd<d2d3ZdS )=	GraphViewa  A read-only view on a graph.

    The GraphView is useful for analysis of a subgraph. It can be initialized
    with a subset of nodes from a :class:`Graph`. Creating GraphView does not
    change the ownership of the nodes, and so it is possible to create multiple
    GraphViews that contain the same nodes. If the underlying nodes / connections
    are mutated, the mutation will be reflected in all views as well.

    The graph view can be serialized to ONNX::

            graph_proto = ir.serde.serialize_graph(graph_view)

    It can also be used to create a model::

            model = ir.Model(graph_view, ir_version=8)
            model_proto = ir.serde.serialize_model(model)

    The model created with a GraphView will have a fixed topology, and its graph
    will remain read-only as a GraphView. No copying will be done during the
    initialization process.

    Attributes:
        name: The name of the graph.
        inputs: The input values of the graph.
        outputs: The output values of the graph.
        initializers: The initializers in the graph.
        doc_string: Documentation string.
        opset_imports: Opsets imported by the graph.
        metadata_props: Metadata that will be serialized to the ONNX file.
        meta: Metadata store for graph transform passes.
    )	r   r2   r6   r  r	  r4   rQ  r  r  r)   Nr  r	  rY  r  rQ  r  r  r6   r5   r  r  r4   r7   r8   c          
      C  st   || _ t|| _t|| _i | _|D ]}	|	j std|	|	| j|	j < q|| _|p+i | _d | _|| _	t|| _
d S )Nr  )r4   r  r	  r  r  r   r6   r  r   r2   r  )
r;   r	  r  rQ  r  r6   r  r4   r7   r  r)   r)   r*   r<     s   


zGraphView.__init__r  rQ   r"   r  c                 C  r  r:   r)   r  r)   r)   r*   r    r  zGraphView.__getitem__r  rH  c                 C  r  r:   r)   r  r)   r)   r*   r    r  c                 C  r  r:   r  r  r)   r)   r*   r    r  c                 C  r  r:   r  rA   r)   r)   r*   r    r  zGraphView.__len__r  c                 C  r  r:   r  rA   r)   r)   r*   r    r  zGraphView.__iter__c                 C  r  r:   r  rA   r)   r)   r*   r    r  zGraphView.__reversed__r^   c                 C  r_   r`   rb   rA   r)   r)   r*   rd     re   zGraphView.metarZ   c                 C  s   | j d u ri | _ | j S r:   r\   rA   r)   r)   r*   r7     s   
zGraphView.metadata_propsr=   c                 C  r  r:   rN  rA   r)   r)   r*   r    ri  zGraphView.__str__c                 C  r  r:   rP  rA   r)   r)   r*   r    ri  zGraphView.__repr__r  c                 C  s(   ddl m} |ji i i dd}|| S )a  Create a deep copy of this graph in O(#nodes + #values) time.

        All nodes, values, and subgraphs are cloned. The cloned graph will have
        the same structure as this graph, but all nodes and values will be different
        objects.

        Tensors in initializers and constant values will be shared.

        .. versionadded:: 0.1.14

        Returns:
            A deep copy of this graph.
        r   r  Fr  r  r7   r  r   )r;   r  r#  r)   r)   r*   r$    s   
zGraphView.clonerR  rU  rV  r   rW  r   r   r   r"   r  )rG   r   r   r   r   r<   r  r  r  r  r  r  r   rd   r7   r  r  r$  r)   r)   r)   r*   rz  U  s0     





rz  c                   @  s   e Zd ZdZ	 ddddddddd.ddZed/ddZed0ddZed1dd Zed2d"d#Z	d3d%d&Z
d3d'd(Zd4d*d+Zd5d,d-ZdS )6Model)

_functionsr   r2   r6   r  r  
ir_versionmodel_versionproducer_nameproducer_versionNr)   )r  r  r  r  r6   	functionsr7   r  r  r  rQ   r  r5   r  r  r  r6  r6   r  Sequence[Function]r7   r8   r"   r9   c          
      C  sJ   || _ || _|| _|| _|| _|| _|| _dd |D | _d | _|	| _	d S )Nc                 S  s   i | ]}|  |qS r)   )
identifierr
  r~  r)   r)   r*   r    r)  z"Model.__init__.<locals>.<dictcomp>)
r  r  r  r  r  r  r6   r~  r   r2   )
r;   r  r  r  r  r  r  r6   r  r7   r)   r)   r*   r<     s   
zModel.__init__-dict[_protocols.OperatorIdentifier, Function]c                 C  rI   r:   )r~  rA   r)   r)   r*   r    r  zModel.functionsr  c                 C  r  r:   )r  r  rA   r)   r)   r*   r    rw  zModel.opset_importsr^   c                 C  r_   r`   rb   rA   r)   r)   r*   rd     re   z
Model.metarZ   c                 C  r[   )zThe metadata properties of the model.

        The metadata properties are used to store additional information about the model.
        Unlike ``meta``, this property is serialized to the ONNX proto.
        Nr\   rA   r)   r)   r*   r7   %  r]   zModel.metadata_propsr=   c                 C  sr   d| j d| jd| jd| jd| jd| jd}t| j}dd	d
 | j	
 D }| d| d|  S )Nz<
    ir_version=,
    opset_imports=,
    producer_name=,
    producer_version=,
    domain=,
    model_version=z,
>z

c                 s  ro  r:   r  r  r)   r)   r*   r  <  r  z Model.__str__.<locals>.<genexpr>rw   )r  r  r  r  r  r  r=   r  r   r  r  )r;   rq  
graph_textfunctions_textr)   r)   r*   r  0  s    
	zModel.__str__c                 C  sV   d| j d| jd| jd| jd| jd| jd| jdtt	| j
d	  d
S )NzModel(
    ir_version=r  r  r  r  r  z,
    functions=z,
    graph=r`  rg  )r  r  r  r  r  r  r  rn  ro  r   r  r	  rA   r)   r)   r*   r  ?  s"   	zModel.__repr__Iterable[Graph]c                 c  s    | j V  | j  E dH  dS )zGet all graphs and subgraphs in the model.

        This is a convenience method to traverse the model. Consider using
        :class:`onnx_ir.traversal.RecursiveGraphIterator` for more advanced
        traversals on nodes.
        N)r  r  rA   r)   r)   r*   graphsL  s   zModel.graphsc                 C  sN   | j  }dd | j D }t|| j| j| j| j| j	| j
|t| jd	}|S )a  Create a deep copy of this model.

        All graphs, nodes, values, and subgraphs are cloned. The cloned model will have
        the same structure as this model, but all graphs, nodes, and values will be different
        objects.

        Tensors in initializers and constant values will be shared.

        .. versionadded:: 0.1.14

        Returns:
            A deep copy of this model.
        c                 S  s   g | ]}|  qS r)   )r$  r  r)   r)   r*   r  k  r  zModel.clone.<locals>.<listcomp>)r  r  r  r  r  r6   r  r7   )r  r$  r  r  r}  r  r  r  r  r  r6   r;  r7   )r;   	new_graphnew_functions	new_modelr)   r)   r*   r$  \  s   
zModel.clone)r  r  r  rQ   r  r5   r  r5   r  r5   r  r6  r6   r5   r  r  r7   r8   r"   r9   )r"   r  rT  r   r   r   )r"   r  )r"   r}  )rG   r   r   r   r<   r   r  r  rd   r7   r  r  r  r$  r)   r)   r)   r*   r}    s.    




r}  c                   @  s  e Zd ZdZdZ	dedfddZdgddZedhddZej	diddZedhddZ
e
j	diddZ
edhddZej	diddZedjddZedjd d!Zedkd#d$Zedld%d&Zejdmd*d+Zejdnd.d+Zd/d+ Zdod0d1Zdpd3d4Zdpd5d6Zedqd8d9Zej	drd:d9Zedsd<d=Zedtd?d@ZedudBdCZdpdDdEZdvdGdHZdwdIdJZdxdLdMZdydPdQZdzd{dVdWZd|dZd[Zd|d\d]Z d}d^d_Z!dhd`daZ"dhdbdcZ#ddS )~Functiona  IR functions.

    Like a graph, a function can have nodes that are not topologically sorted. It is
    the responsibility of the user to maintain a topological order of the nodes.

    Note that there is not a ``node`` attribute in the Function. The Function can be
    seen as a Sequence of nodes and should be used as such. For example, to obtain
    all nodes as a list, call ``list(function)``.

    Attributes:
        name: The function name.
        domain: The domain this function is defined in.
        overload: The overload name when the function is overloaded.
        inputs: The input values of the function.
        attributes: The attributes this function defines.
        outputs: The output values of the function.
        opset_imports: Opsets imported by the function.
        doc_string: Documentation string.
        meta: Metadata store for graph transform passes.
        metadata_props: Metadata that will be serialized to the ONNX file.
    )r  r  r  r3   r  rn   r  r=   r4   r  r  r  r  r  r"   r9   c                C  sB   || _ || _|| _|| _t|trt| }tj	|| d| _
d S )Nr  )r  r3   r  r  r   r   r  r  r   r  r  )r;   r  r4   r  r  r  r)   r)   r*   r<     s   
zFunction.__init__rc  c                 C  rd  r:   )r  r4   r  rA   r)   r)   r*   r    r  zFunction.identifierc                 C  rI   r:   rJ   rA   r)   r)   r*   r4     r  zFunction.namerL   c                 C  rM   r:   rJ   rN   r)   r)   r*   r4     rO   c                 C  rI   r:   r5  rA   r)   r)   r*   r    r  zFunction.domainc                 C  r6  r:   r7  rN   r)   r)   r*   r    r8  c                 C  rI   r:   r<  rA   r)   r)   r*   r    r  zFunction.overloadc                 C  rM   r:   r<  rN   r)   r)   r*   r    rO   r  c                 C  r  r:   )r  r	  rA   r)   r)   r*   r	    rw  zFunction.inputsc                 C  r  r:   )r  r  rA   r)   r)   r*   r    rw  zFunction.outputsr_  c                 C  rI   r:   r`  rA   r)   r)   r*   r    r  zFunction.attributesc                 C  rI   )a  The underlying Graph object that contains the nodes of this function.

        Only use this graph for identity comparison::

            if value.graph is function.graph:
                # Do something with the value that belongs to this function

        Otherwise use the Function object directly to access the nodes and other properties.

        .. versionadded:: 0.1.7
        rb  rA   r)   r)   r*   r    s   zFunction.graphr  rQ   r  c                 C  r  r:   r)   r  r)   r)   r*   r    r  zFunction.__getitem__r  rH  c                 C  r  r:   r)   r  r)   r)   r*   r    r  c                 C  s   | j |S r:   )r  r  r  r)   r)   r*   r    r  c                 C  
   | j  S r:   )r  r  rA   r)   r)   r*   r    r  zFunction.__len__r  c                 C  r  r:   )r  r  rA   r)   r)   r*   r    r  zFunction.__iter__c                 C  r  r:   )r  r  rA   r)   r)   r*   r    r  zFunction.__reversed__r5   c                 C  r  r:   r  r6   rA   r)   r)   r*   r6     rw  zFunction.doc_stringc                 C  r  r:   r  rN   r)   r)   r*   r6     r  r  c                 C  r  r:   )r  r  rA   r)   r)   r*   r    rw  zFunction.opset_importsr^   c                 C  r  )ra   )r  rd   rA   r)   r)   r*   rd         zFunction.metarZ   c                 C  r  )zThe metadata properties of the function.

        The metadata properties are used to store additional information about the function.
        Unlike ``meta``, this property is serialized to the ONNX proto.
        )r  r7   rA   r)   r)   r*   r7   	  r  zFunction.metadata_propsc                 C  r  r  r  rA   r)   r)   r*   r    r	  zFunction.all_nodesr
  c                 #  r  )zlGet all subgraphs in the function in O(#nodes + #attributes) time.

        .. versionadded:: 0.1.2
        r"   r9   c                   r  r  r  r  r  r)   r*   r  '  r  z*Function.subgraphs.<locals>.enter_subgraphr  Nr   r  r  r)   r  r*   r    s   
zFunction.subgraphsc                   sZ   ddl m} |ji i i dd  | j} fdd| j D }t| j| j	| j
||dS )a  Create a deep copy of this function in O(#nodes + #values) time.

        All nodes, values, and subgraphs are cloned. The cloned function will have
        the same structure as this function, but all nodes and values will be different
        objects.

        Tensors in initializers and constant values will be shared.

        .. versionadded:: 0.1.14

        Returns:
            A deep copy of this function.
        r   r  Fr{  c                   s   g | ]	}  |j|qS r)   )
clone_attrr4   r
  rG  r#  r)   r*   r  L  s    z"Function.clone.<locals>.<listcomp>)r  r4   r  r  r  )r8  r  r!  r"  r  r  r  r  r  r3   r  )r;   r  r  new_attributesr)   r  r*   r$  5  s$   
zFunction.cloner  c                C     | j | dS )z+Append a node to the function in O(1) time.N)r  r   r%  r)   r)   r*   r   X  r  zFunction.appendrQ  r  c                C  r  )z?Extend the function with the given nodes in O(#new_nodes) time.N)r  r  rU  r)   r)   r*   r  \  r  zFunction.extendFr*  rl   rR  c                C  s   | j j||d dS )a  Remove nodes from the graph in O(#num of nodes) time.

        If any errors are raise, to ensure the graph is not left in an inconsistent state,
        the graph is not modified.

        Args:
            nodes: The node to remove.
            safe: If True, performs the following actions before removal:

                1. It checks to make sure there are no users of the node that are not
                to be removed before removing it.
                2. It checks the node does not contribute to any graph outputs.
                3. It removes references to all inputs so it is no longer a user of other nodes.

        Raises:
            ValueError: If any node to remove does not belong to this graph.
            ValueError: (When ``safe=True``) If the node does not belong to this graph or if there are users of the node.
            ValueError: (When ``safe=True``) If the node is still being used by other nodes not to be removed.
        )r*  N)r  r,  )r;   rQ  r*  r)   r)   r*   r,  `  s   zFunction.remover.  r/  c                C     | j || dS )z<Insert new nodes after the given node in O(#new_nodes) time.N)r  rX  r1  r)   r)   r*   rX  v  rC   zFunction.insert_afterc                C  r  )z=Insert new nodes before the given node in O(#new_nodes) time.N)r  rT  r1  r)   r)   r*   rT  z  rC   zFunction.insert_beforec                 C  s   | j   dS )zWPerform a topological sort of this graph and all subgraphs in O(#nodes + #values) time.N)r  rM  rA   r)   r)   r*   rM  ~  r8  zFunction.sortc                 C  s  | j  d| j d| j | jdk  }ddd | jD }ddd | jD }ddd | j D }|rCd	t	|d
 d }d| j
d| dt	|d dt	|d
 dt	|d d}t| }tt|}g }t| D ]5\}	}
|
jr||
jndt|
 }d| d|
 }t	|d|d  }| }||	d| d|  qrddd | jD }dt	d|d
 t	d| d
 d }| d| S )Nr#  r$  rn   r^  c                 s  ro  r:   r  r)  r)   r)   r*   r    r  z#Function.__str__.<locals>.<genexpr>c                 s  ro  r:   r  r)  r)   r)   r*   r    r  c                 s  s8    | ]}|j  d |j d|j |jdu  V  qdS )z: z = N)r4   r   rL   r  r)   r)   r*   r    s
    &
z
attributes={
r`  rm  z<
    opset_imports=z,
>
def z(
    inputs=(
rd  rf  z
    outputs=(
z	
    ),
)rh  ri  rw   r  rD  rE   rj  r%  c                 s  ro  r:   r  r)  r)   r)   r*   r    r  rk  rl  )r  r4   r  r   r	  r  r  r  rn  ro  r  rX  r=   r  r(  r	  r   )r;   	full_namer/  r1  r0  rq  rr  rs  rt  r  r  ru  rv  rw  rx  ry  r)   r)   r*   r    sN   (



	zFunction.__str__c                 C  s>   | j j d| jd| jd| jd| jd| jd| jdS )Nr  r%  r3  r4  z), outputs=r  )rF   rG   r  r4   r  r	  r  r  rA   r)   r)   r*   r    s   >zFunction.__repr__N)rn   )r  r=   r4   r=   r  r=   r  r  r  r  r"   r9   rj  r   rf  rS  rh  r|  rU  rV  r   rW  r   r   rT  r   r   rX  )r"   r  rY  rZ  r  r[  r\  r   )$rG   r   r   r   r   r<   r  r   r4   r   r  r  r	  r  r  r  r  r  r  r  r  r6   r  rd   r7   r  r  r$  r   r  r,  rX  rT  rM  r  r  r)   r)   r)   r*   r  {  sn    







#




,r  c                   @  s
  e Zd ZdZdZ	dFdddGddZedHddZejdIddZedJddZ	edKddZ
edLddZedMddZdNdd ZdOd#d$ZdHd%d&ZdHd'd(ZdPd*d+ZdQd-d.ZdHd/d0ZdRd2d3ZdSd5d6ZdTd8d9ZdUd;d<ZdVd>d?ZdWdAdBZdXdDdEZdS )Yr=  z-Base class for ONNX attributes or references.)r   r3   _ref_attr_namer  r  r6   Nr6   r4   r=   r   _enums.AttributeTyperL   r   ref_attr_namer5   r6   r"   r9   c                C  s   |d u rnJ|t jjkrt|}n?|t jjkrt|}n4|t jjkr+tdd |D }n$|t jjkr;tdd |D }n|t jj	t jj
t jjt jjhv rOt|}|| _|| _|| _|| _|| _d | _d S )Nc                 s  ro  r:   )rQ   r
  r,  r)   r)   r*   r    r  z Attr.__init__.<locals>.<genexpr>c                 s  ro  r:   )floatr  r)   r)   r*   r    r  )r   r>  INTrQ   FLOATr  INTSr  FLOATSSTRINGSTENSORSr@  TYPE_PROTOSr3   r  r  r  r6   r   )r;   r4   r   rL   r  r6   r)   r)   r*   r<     s.   


zAttr.__init__c                 C  rI   r:   rJ   rA   r)   r)   r*   r4     r  z	Attr.namec                 C  rM   r:   rJ   rN   r)   r)   r*   r4     rO   c                 C  rI   r:   r  rA   r)   r)   r*   r     r  z	Attr.typec                 C  rI   r:   r  rA   r)   r)   r*   rL     r  z
Attr.valuec                 C  rI   r:   )r  rA   r)   r)   r*   r    r  zAttr.ref_attr_namer^   c                 C  r_   r`   rb   rA   r)   r)   r*   rd     re   z	Attr.metarl   c                 C  s
   | j duS )z1Check if this attribute is a reference attribute.N)r  rA   r)   r)   r*   is_ref  rO   zAttr.is_refr  r  c                 C  sT   t |tjsdS | j|jkrdS | j|jkrdS | j|jkr dS | j|jkr(dS dS )NFT)r   r   AttributeProtocolr4   r   rL   r6   r  r)   r)   r*   r    s   zAttr.__eq__c                 C  sB   |   r
d| j S | jtjjkrtdt| j	 dS t
| j	S )N@rw   r`  )r  r  r   r   r>  r?  rn  ro  r=   rL   r   rA   r)   r)   r*   r    s
   
zAttr.__str__c                 C  sT   |   r| jj d| jd| jd| jdS | jj d| jd| jd| jdS )Nr  r%  z, ref_attr_name=r  )r  rF   rG   r4   r   r  rL   rA   r)   r)   r*   r  %  s   &&zAttr.__repr__r  c                 C  ,   | j tjjkrtd| j d| j  | jS )z#Get the attribute value as a float.Attribute 'z%' is not of type FLOAT. Actual type: )r   r   r>  r  r   r4   rL   rA   r)   r)   r*   as_float+  
   zAttr.as_floatrQ   c                 C  r  )z"Get the attribute value as an int.r  z#' is not of type INT. Actual type: )r   r   r>  r  r   r4   rL   rA   r)   r)   r*   as_int4  r  zAttr.as_intc                 C  J   | j tjjkrtd| j d| j  | j}t|ts#td| d|S )z$Get the attribute value as a string.r  z&' is not of type STRING. Actual type: Value of attribute 'z' is not a string.)	r   r   r>  rn  r   r4   rL   r   r=   rN   r)   r)   r*   	as_string=     
zAttr.as_stringr  c                 C  sL   | j tjjkrtd| j d| j  | j}t|tj	s$td| d|S )z$Get the attribute value as a tensor.r  z&' is not of type TENSOR. Actual type: r  z' is not a tensor.)
r   r   r>  TENSORr   r4   rL   r   r   r  rN   r)   r)   r*   	as_tensorH  s   zAttr.as_tensorr  c                 C  r  )z#Get the attribute value as a graph.r  z%' is not of type GRAPH. Actual type: r  z' is not a graph.)	r   r   r>  r?  r   r4   rL   r   r  rN   r)   r)   r*   as_graphS  r  zAttr.as_graphtuple[float, ...]c                 C  r  )z0Get the attribute value as a sequence of floats.r  z&' is not of type FLOATS. Actual type: )r   r   r>  r  r   r4   rL   rA   r)   r)   r*   	as_floats^  r  zAttr.as_floatsr  c                 C  r  )z.Get the attribute value as a sequence of ints.r  z$' is not of type INTS. Actual type: )r   r   r>  r  r   r4   rL   rA   r)   r)   r*   as_intsg  r  zAttr.as_intstuple[str, ...]c                 C  sV   | j tjjkrtd| j d| j  tjr(tdd | j	D s(td| d| j	S )z1Get the attribute value as a sequence of strings.r  z'' is not of type STRINGS. Actual type: c                 s  r  r:   )r   r=   r)  r)   r)   r*   r  w  r  z"Attr.as_strings.<locals>.<genexpr>r  z' is not a Sequence of strings.)
r   r   r>  r  r   r4   r8  r9  r  rL   rA   r)   r)   r*   
as_stringsp  s   zAttr.as_strings%tuple[_protocols.TensorProtocol, ...]c                 C  Z   | j tjjkrtd| j d| j  tjr(tdd | j	D s(td| dt
| j	S )z1Get the attribute value as a sequence of tensors.r  z'' is not of type TENSORS. Actual type: c                 s  s    | ]	}t |tjV  qd S r:   )r   r   r  r)  r)   r)   r*   r    r  z"Attr.as_tensors.<locals>.<genexpr>r  z' is not a Sequence of tensors.)r   r   r>  r  r   r4   r8  r9  r  rL   r  rA   r)   r)   r*   
as_tensors|     
zAttr.as_tensorstuple[Graph, ...]c                 C  r  )z0Get the attribute value as a sequence of graphs.r  z&' is not of type GRAPHS. Actual type: c                 s  r  r:   )r   r  r)  r)   r)   r*   r    r  z!Attr.as_graphs.<locals>.<genexpr>r  z' is not a Sequence of graphs.)r   r   r>  r@  r   r4   r8  r9  r  rL   r  rA   r)   r)   r*   	as_graphs  r  zAttr.as_graphsr:   )r4   r=   r   r  rL   r   r  r5   r6   r5   r"   r9   r   rf  )r"   r  )r"   r   r   r   rd  r  )r"   r  r   r  r|  )r"   r  r  )r"   r  )r"   r  )r"   r  )rG   r   r   r   r   r<   r   r4   r   r   rL   r  rd   r  r  r  r  r  r  r  r  r  r  r  r  r  r  r)   r)   r)   r*   r=    sB    )






	
	



	
	
r=  r  r  c                 C  s   t | |d||dS )a  Create a reference attribute.

    Args:
        name: The name of the attribute.
        type: The type of the attribute.
        ref_attr_name: The name of the referenced attribute.
        doc_string: Documentation string.

    Returns:
        A reference attribute.
    N)r  r6   )r=  )r4   r  r   r6   r)   r)   r*   RefAttr  s   r  float | np.floatingc                 C     t | tjj||dS )zCreate a float attribute.r  )r=  r   r>  r  r4   rL   r6   r)   r)   r*   AttrFloat32     r  int | np.integerc                 C  r  )zCreate an int attribute.r  )r=  r   r>  r  r  r)   r)   r*   	AttrInt64  r  r  c                 C  r  )zCreate a str attribute.r  )r=  r   r>  rn  r  r)   r)   r*   
AttrString  r  r  r  c                 C  r  )zCreate a tensor attribute.r  )r=  r   r>  r  r  r)   r)   r*   
AttrTensor     r  c                 C  r  )zCreate a graph attribute.r  )r=  r   r>  r?  r  r)   r)   r*   	AttrGraph  r  r  Sequence[float]c                 C  r  )z"Create a float sequence attribute.r  )r=  r   r>  r  r  r)   r)   r*   AttrFloat32s  r  r  Sequence[int]c                 C  r  )z!Create an int sequence attribute.r  )r=  r   r>  r  r  r)   r)   r*   
AttrInt64s  r  r  Sequence[str]c                 C  r  )z#Create a string sequence attribute.r  )r=  r   r>  r  r  r)   r)   r*   AttrStrings  r  r  #Sequence[_protocols.TensorProtocol]c                 C  r  )z#Create a tensor sequence attribute.r  )r=  r   r>  r  r  r)   r)   r*   AttrTensors  r  r  Sequence[Graph]c                 C  r  )z"Create a graph sequence attribute.r  )r=  r   r>  r@  r  r)   r)   r*   
AttrGraphs  r  r  _protocols.SparseTensorProtocolc                 C  r  )z!Create a sparse tensor attribute.r  )r=  r   r>  SPARSE_TENSORr  r)   r)   r*   AttrSparseTensor   r  r  )Sequence[_protocols.SparseTensorProtocol]c                 C  r  )z*Create a sparse tensor sequence attribute.r  )r=  r   r>  SPARSE_TENSORSr  r)   r)   r*   AttrSparseTensors-  r  r  c                   @  r  )TypeAndShapez?Type and shape.

    Useful for constructing a type proto.
    r  r   r   r@   Nr  r)   r)   r)   r*   r  :  s   
 r  c                 C  r  )zCreate a type attribute.r  )r=  r   r>  
TYPE_PROTOr  r)   r)   r*   AttrTypeProtoE  r  r  Sequence[TypeAndShape]c                 C  r  )z!Create a type sequence attribute.r  )r=  r   r>  r  r  r)   r)   r*   AttrTypeProtosP  r  r  )r!   r   r"   r#   )r!   r   r"   r-   )r   r   r?   r   r"   r9   )r   r   r?   r   r"   r   )rh   r   r"   rl   )r   r   r"   r   )rL   r  r"   r  )r  r  r"   r  )rq  r=   r"   r=   )r  r  r"   r=   )r  r=   r"   r=   )r  r  r"   r  )NNNN)
r4   r5   r@   r   r   r  r6   r5   r"   r  )r  r  r  r  r  r  r"   r9   )r  r]  r"   r=   r:   )
r4   r=   r  r=   r   r  r6   r5   r"   r=  )r4   r=   rL   r  r6   r5   r"   r=  )r4   r=   rL   r  r6   r5   r"   r=  )r4   r=   rL   r=   r6   r5   r"   r=  )r4   r=   rL   r  r6   r5   r"   r=  )r4   r=   rL   r  r6   r5   r"   r=  )r4   r=   rL   r  r6   r5   r"   r=  )r4   r=   rL   r  r6   r5   r"   r=  )r4   r=   rL   r  r6   r5   r"   r=  )r4   r=   rL   r  r6   r5   r"   r=  )r4   r=   rL   r  r6   r5   r"   r=  )r4   r=   rL   r  r6   r5   r"   r=  )r4   r=   rL   r  r6   r5   r"   r=  )r4   r=   rL   r  r6   r5   r"   r=  )r4   r=   rL   r  r6   r5   r"   r=  )r   
__future__r   abcry   dataclassesrA  loggingrR   rH  r:  sysrn  r  collections.abcr   r   r   r   r   r   r	   r
   AbstractSetr   r   r   r   r   r   r   r   r   rT   r   typing_extensionsr   r   r8  r   r   r   r   r   r   r   r   TYPE_CHECKINGnumpy.typingnptr   TypeVarArrayCompatibleDLPackCompatibler   	byteorderr   r+  r   r   r   r   r   r   r   r   r   r   r   r   r   	getLoggerrG   loggerr+   r/   ABCr  PrettyPrintabler0   r   r   r   r   r   r+  re  rz  r  SymbolicDimProtocolr  r  r  ShapeProtocolr   r  r  r  r  NodeProtocolr  TypeProtocolrk  rz  r|  r  r  r  r  r  r  ValueProtocolr  r  r  GraphProtocolr  rO  rQ  rz  ModelProtocolr}  FunctionProtocolr  r  ReferenceAttributeProtocolr=  r  r  r  r  r  r  r  r  r  r  r  r  r  	dataclassr  r  r  r)   r)   r)   r*   <module>   s  
$	((



 

F
%
 @  [| 
/
 


   c$(
 ,   c
$    

' 	   
; i
