# --------------------------------------------------------------------------
# ⚠️ WARNING - AUTO-GENERATED CODE - DO NOT EDIT ⚠️
# ⚙️ Generated by 'python -m opgen'
# --------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# --------------------------------------------------------------------------
# pylint: disable=W0221,W0222,R0901,W0237
# mypy: disable-error-code=override
# ruff: noqa: D214, D402, D405, D411, D416, D417
# --------------------------------------------------------------------------

from __future__ import annotations

from typing import Optional, Sequence, Tuple, TypeVar, Union

from onnx import GraphProto, SparseTensorProto, TensorProto
from onnx.defs import get_schema
from typing_extensions import TypeAlias

from onnxscript.onnx_opset._impl.opset12 import Opset12
from onnxscript.onnx_types import (
    BFLOAT16,
    BOOL,
    COMPLEX64,
    COMPLEX128,
    DOUBLE,
    FLOAT,
    FLOAT16,
    INT8,
    INT16,
    INT32,
    INT64,
    STRING,
    UINT8,
    UINT16,
    UINT32,
    UINT64,
)
from onnxscript.values import Op, Opset


class Opset13(Opset12):
    def __new__(cls):
        return Opset.__new__(cls, "", 13)

    T_Abs = TypeVar(
        "T_Abs",
        BFLOAT16,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    def Abs(self, X: T_Abs) -> T_Abs:
        r"""[🌐 Abs(13)](https://onnx.ai/onnx/operators/onnx__Abs.html#abs-13 "Online Documentation")


        Absolute takes one input data (Tensor<T>) and produces one output data
        (Tensor<T>) where absolute value, y = abs(x), is applied to
        the tensor elementwise.


        Args:
            X: (differentiable) Input tensor
        """

        schema = get_schema("Abs", 13, "")
        op = Op(self, "Abs", schema)
        return op(*self._prepare_inputs(schema, X))

    T_Add = TypeVar("T_Add", BFLOAT16, DOUBLE, FLOAT, FLOAT16, INT32, INT64, UINT32, UINT64)

    def Add(self, A: T_Add, B: T_Add) -> T_Add:
        r"""[🌐 Add(13)](https://onnx.ai/onnx/operators/onnx__Add.html#add-13 "Online Documentation")


        Performs element-wise binary addition (with Numpy-style broadcasting support).

        This operator supports **multidirectional (i.e., Numpy-style) broadcasting**; for more details please check `Broadcasting in ONNX <https://github.com/onnx/onnx/blob/master/docs/Broadcasting.md>`_.


        Args:
            A: (differentiable) First operand.

            B: (differentiable) Second operand.
        """

        schema = get_schema("Add", 13, "")
        op = Op(self, "Add", schema)
        return op(*self._prepare_inputs(schema, A, B))

    T_ArgMax = TypeVar(
        "T_ArgMax",
        BFLOAT16,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    def ArgMax(
        self,
        data: T_ArgMax,
        *,
        axis: int = 0,
        keepdims: int = 1,
        select_last_index: int = 0,
    ) -> INT64:
        r"""[🌐 ArgMax(13)](https://onnx.ai/onnx/operators/onnx__ArgMax.html#argmax-13 "Online Documentation")


        Computes the indices of the max elements of the input tensor's element along the
        provided axis. The resulting tensor has the same rank as the input if keepdims equals 1.
        If keepdims equals 0, then the resulting tensor has the reduced dimension pruned.
        If select_last_index is True (default False), the index of the last occurrence of the max
        is selected if the max appears more than once in the input. Otherwise the index of the
        first occurrence is selected.
        The type of the output tensor is integer.

        Args:
            data: (non-differentiable) An input tensor.

            axis: The axis in which to compute the arg indices. Accepted range is [-r,
                r-1] where r = rank(data).

            keepdims: Keep the reduced dimension or not, default 1 means keep reduced
                dimension.

            select_last_index: Whether to select the last index or the first index if
                the {name} appears in multiple indices, default is False (first index).
        """

        schema = get_schema("ArgMax", 13, "")
        op = Op(self, "ArgMax", schema)
        return op(
            *self._prepare_inputs(schema, data),
            axis=axis,
            keepdims=keepdims,
            select_last_index=select_last_index,
        )

    T_ArgMin = TypeVar(
        "T_ArgMin",
        BFLOAT16,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    def ArgMin(
        self,
        data: T_ArgMin,
        *,
        axis: int = 0,
        keepdims: int = 1,
        select_last_index: int = 0,
    ) -> INT64:
        r"""[🌐 ArgMin(13)](https://onnx.ai/onnx/operators/onnx__ArgMin.html#argmin-13 "Online Documentation")


        Computes the indices of the min elements of the input tensor's element along the
        provided axis. The resulting tensor has the same rank as the input if keepdims equals 1.
        If keepdims equals 0, then the resulting tensor has the reduced dimension pruned.
        If select_last_index is True (default False), the index of the last occurrence of the min
        is selected if the min appears more than once in the input. Otherwise the index of the
        first occurrence is selected.
        The type of the output tensor is integer.

        Args:
            data: (non-differentiable) An input tensor.

            axis: The axis in which to compute the arg indices. Accepted range is [-r,
                r-1] where r = rank(data).

            keepdims: Keep the reduced dimension or not, default 1 means keep reduced
                dimension.

            select_last_index: Whether to select the last index or the first index if
                the {name} appears in multiple indices, default is False (first index).
        """

        schema = get_schema("ArgMin", 13, "")
        op = Op(self, "ArgMin", schema)
        return op(
            *self._prepare_inputs(schema, data),
            axis=axis,
            keepdims=keepdims,
            select_last_index=select_last_index,
        )

    T1_Cast = TypeVar(
        "T1_Cast",
        BFLOAT16,
        BOOL,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        STRING,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    T2_Cast: TypeAlias = Union[
        BFLOAT16,
        BOOL,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        STRING,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    ]

    def Cast(self, input: T1_Cast, *, to: int) -> T2_Cast:
        r"""[🌐 Cast(13)](https://onnx.ai/onnx/operators/onnx__Cast.html#cast-13 "Online Documentation")


        The operator casts the elements of a given input tensor to a data type
        specified by the 'to' argument and returns an output tensor of the same size in
        the converted type. The 'to' argument must be one of the data types specified
        in the 'DataType' enum field in the TensorProto message.

        Casting from string tensor in plain (e.g., "3.14" and "1000") and scientific numeric representations
        (e.g., "1e-5" and "1E8") to float types is supported. For example, converting string "100.5" to an integer may
        yield result 100. There are some string literals reserved for special floating-point values;
        "+INF" (and "INF"), "-INF", and "NaN" are positive infinity, negative infinity, and not-a-number, respectively.
        Any string which can exactly match "+INF" in a case-insensitive way would be mapped to positive infinite. Similarly,
        this case-insensitive rule is applied to "INF" and "NaN". When casting from numeric tensors
        to string tensors, plain floating-point representation (such as "314.15926") would be used.
        Converting non-numerical-literal string such as "Hello World!" is an undefined behavior. Cases
        of converting string representing floating-point arithmetic value, such as "2.718", to INT is an undefined behavior.

        Conversion from a numerical type to any numerical type is always allowed.
        User must be aware of precision loss and value change caused by range difference between two types.
        For example, a 64-bit float 3.1415926459 may be round to a 32-bit float 3.141592. Similarly, converting
        an integer 36 to Boolean may produce 1 because we truncate bits which can't be stored in the targeted type.

        In more detail, the conversion among numerical types should follow these rules:

        * Casting from floating point to:
          * floating point: +/- infinity if OOR (out of range).
          * fixed point: undefined if OOR.
          * bool: +/- 0.0 to False; all else to True.
        * Casting from fixed point to:
          * floating point: +/- infinity if OOR. (+ infinity in the case of uint)
          * fixed point: when OOR, discard higher bits and reinterpret (with respect to two's complement representation for
            signed types). For example, 200 (int16) -> -56 (int8).
          * bool: zero to False; nonzero to True.
        * Casting from bool to:
          * floating point: `{1.0, 0.0}`.
          * fixed point: `{1, 0}`.
          * bool: no change.


        Args:
            input: (differentiable) Input tensor to be cast.

            to: The data type to which the elements of the input tensor are cast.
                Strictly must be one of the types from DataType enum in TensorProto
        """

        schema = get_schema("Cast", 13, "")
        op = Op(self, "Cast", schema)
        return op(*self._prepare_inputs(schema, input), to=to)

    T_Ceil = TypeVar("T_Ceil", BFLOAT16, DOUBLE, FLOAT, FLOAT16)

    def Ceil(self, X: T_Ceil) -> T_Ceil:
        r"""[🌐 Ceil(13)](https://onnx.ai/onnx/operators/onnx__Ceil.html#ceil-13 "Online Documentation")


        Ceil takes one input data (Tensor<T>) and produces one output data
        (Tensor<T>) where the ceil is, y = ceil(x), is applied to
        the tensor elementwise. If x is integral, +0, -0, NaN,  or infinite, x itself is returned.


        Args:
            X: (non-differentiable) Input tensor
        """

        schema = get_schema("Ceil", 13, "")
        op = Op(self, "Ceil", schema)
        return op(*self._prepare_inputs(schema, X))

    T_Clip = TypeVar(
        "T_Clip",
        BFLOAT16,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    def Clip(
        self, input: T_Clip, min: Optional[T_Clip] = None, max: Optional[T_Clip] = None
    ) -> T_Clip:
        r"""[🌐 Clip(13)](https://onnx.ai/onnx/operators/onnx__Clip.html#clip-13 "Online Documentation")


        Clip operator limits the given input within an interval. The interval is
        specified by the inputs 'min' and 'max'. They default to
        numeric_limits::lowest() and numeric_limits::max(), respectively.
        When 'min' is greater than 'max', the clip operator sets all the 'input' values to
        the value of 'max'. Thus, this is equivalent to 'Min(max, Max(input, min))'.


        Args:
            input: (differentiable) Input tensor whose elements to be clipped

            min: (optional, non-differentiable) Minimum value, under which element is
                replaced by min. It must be a scalar(tensor of empty shape).

            max: (optional, non-differentiable) Maximum value, above which element is
                replaced by max. It must be a scalar(tensor of empty shape).
        """

        schema = get_schema("Clip", 13, "")
        op = Op(self, "Clip", schema)
        return op(*self._prepare_inputs(schema, input, min, max))

    T_Concat = TypeVar(
        "T_Concat",
        BFLOAT16,
        BOOL,
        COMPLEX128,
        COMPLEX64,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        STRING,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    def Concat(self, *inputs: T_Concat, axis: int) -> T_Concat:
        r"""[🌐 Concat(13)](https://onnx.ai/onnx/operators/onnx__Concat.html#concat-13 "Online Documentation")

        Concatenate a list of tensors into a single tensor. All input tensors must have the same shape, except for the dimension size of the axis to concatenate on.

        Args:
            inputs: (variadic, differentiable) List of tensors for concatenation

            axis: Which axis to concat on. A negative value means counting dimensions
                from the back. Accepted range is [-r, r-1] where r = rank(inputs)..
        """

        schema = get_schema("Concat", 13, "")
        op = Op(self, "Concat", schema)
        return op(*self._prepare_inputs(schema, *inputs), axis=axis)

    T_Constant: TypeAlias = Union[
        BFLOAT16,
        BOOL,
        COMPLEX128,
        COMPLEX64,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        STRING,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    ]

    def Constant(
        self,
        *,
        sparse_value: Optional[SparseTensorProto] = None,
        value: Optional[TensorProto] = None,
        value_float: Optional[float] = None,
        value_floats: Optional[Sequence[float]] = None,
        value_int: Optional[int] = None,
        value_ints: Optional[Sequence[int]] = None,
        value_string: Optional[str] = None,
        value_strings: Optional[Sequence[str]] = None,
    ) -> T_Constant:
        r"""[🌐 Constant(13)](https://onnx.ai/onnx/operators/onnx__Constant.html#constant-13 "Online Documentation")


        This operator produces a constant tensor. Exactly one of the provided attributes, either value, sparse_value,
        or value_* must be specified.


        Args:
            sparse_value: The value for the elements of the output tensor in sparse
                format.

            value: The value for the elements of the output tensor.

            value_float: The value for the sole element for the scalar, float32, output
                tensor.

            value_floats: The values for the elements for the 1D, float32, output
                tensor.

            value_int: The value for the sole element for the scalar, int64, output
                tensor.

            value_ints: The values for the elements for the 1D, int64, output tensor.

            value_string: The value for the sole element for the scalar, UTF-8 string,
                output tensor.

            value_strings: The values for the elements for the 1D, UTF-8 string, output
                tensor.
        """

        schema = get_schema("Constant", 13, "")
        op = Op(self, "Constant", schema)
        return op(
            sparse_value=sparse_value,
            value=value,
            value_float=value_float,
            value_floats=value_floats,
            value_int=value_int,
            value_ints=value_ints,
            value_string=value_string,
            value_strings=value_strings,
        )

    T_DepthToSpace = TypeVar(
        "T_DepthToSpace",
        BFLOAT16,
        BOOL,
        COMPLEX128,
        COMPLEX64,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        STRING,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    def DepthToSpace(
        self, input: T_DepthToSpace, *, blocksize: int, mode: str = "DCR"
    ) -> T_DepthToSpace:
        r"""[🌐 DepthToSpace(13)](https://onnx.ai/onnx/operators/onnx__DepthToSpace.html#depthtospace-13 "Online Documentation")

        DepthToSpace rearranges (permutes) data from depth into blocks of spatial data.
        This is the reverse transformation of SpaceToDepth. More specifically, this op outputs a copy of
        the input tensor where values from the depth dimension are moved in spatial blocks to the height
        and width dimensions. By default, `mode` = `DCR`.
        In the DCR mode, elements along the depth dimension from the input tensor are rearranged in the
        following order: depth, column, and then row. The output y is computed from the input x as below:

        ::

            b, c, h, w = x.shape
            tmp = np.reshape(x, [b, blocksize, blocksize, c // (blocksize**2), h, w])
            tmp = np.transpose(tmp, [0, 3, 4, 1, 5, 2])
            y = np.reshape(tmp, [b, c // (blocksize**2), h * blocksize, w * blocksize])



        In the CRD mode, elements along the depth dimension from the input tensor are rearranged in the
        following order: column, row, and the depth. The output y is computed from the input x as below:

        ::

            b, c, h, w = x.shape
            tmp = np.reshape(x, [b, c // (blocksize ** 2), blocksize, blocksize, h, w])
            tmp = np.transpose(tmp, [0, 1, 4, 2, 5, 3])
            y = np.reshape(tmp, [b, c // (blocksize ** 2), h * blocksize, w * blocksize])




        Args:
            input: (differentiable) Input tensor of [N,C,H,W], where N is the batch
                axis, C is the channel or depth, H is the height and W is the width.

            blocksize: Blocks of [blocksize, blocksize] are moved.

            mode: DCR (default) for depth-column-row order re-arrangement. Use CRD for
                column-row-depth order.
        """

        schema = get_schema("DepthToSpace", 13, "")
        op = Op(self, "DepthToSpace", schema)
        return op(*self._prepare_inputs(schema, input), blocksize=blocksize, mode=mode)

    T_DequantizeLinear = TypeVar("T_DequantizeLinear", INT32, INT8, UINT8)

    def DequantizeLinear(
        self,
        x: T_DequantizeLinear,
        x_scale: FLOAT,
        x_zero_point: Optional[T_DequantizeLinear] = None,
        *,
        axis: int = 1,
    ) -> FLOAT:
        r"""[🌐 DequantizeLinear(13)](https://onnx.ai/onnx/operators/onnx__DequantizeLinear.html#dequantizelinear-13 "Online Documentation")


        The linear dequantization operator. It consumes a quantized tensor, a scale, and a zero point to compute the full precision tensor.
        The dequantization formula is `y = (x - x_zero_point) * x_scale`. `x_scale` and `x_zero_point` must have same shape, and can be either a scalar
        for per-tensor / per layer quantization, or a 1-D tensor for per-axis quantization.
        `x_zero_point` and `x` must have same type. `x` and `y` must have same shape. In the case of dequantizing int32,
        there's no zero point (zero point is supposed to be 0).


        Args:
            x: N-D quantized input tensor to be de-quantized.

            x_scale: Scale for input 'x'. It can be a scalar, which means a
                per-tensor/layer dequantization, or a 1-D tensor for per-axis
                dequantization.

            x_zero_point: (optional) Zero point for input 'x'. Shape must match x_scale.
                It's optional. Zero point is 0 when it's not specified.

            axis: (Optional) The axis of the dequantizing dimension of the input tensor.
                Ignored for per-tensor quantization. Negative value means counting
                dimensions from the back. Accepted range is [-r, r-1] where r =
                rank(input).
        """

        schema = get_schema("DequantizeLinear", 13, "")
        op = Op(self, "DequantizeLinear", schema)
        return op(*self._prepare_inputs(schema, x, x_scale, x_zero_point), axis=axis)

    T_Div = TypeVar("T_Div", BFLOAT16, DOUBLE, FLOAT, FLOAT16, INT32, INT64, UINT32, UINT64)

    def Div(self, A: T_Div, B: T_Div) -> T_Div:
        r"""[🌐 Div(13)](https://onnx.ai/onnx/operators/onnx__Div.html#div-13 "Online Documentation")


        Performs element-wise binary division (with Numpy-style broadcasting support).

        This operator supports **multidirectional (i.e., Numpy-style) broadcasting**; for more details please check `Broadcasting in ONNX <https://github.com/onnx/onnx/blob/master/docs/Broadcasting.md>`_.


        Args:
            A: (differentiable) First operand.

            B: (differentiable) Second operand.
        """

        schema = get_schema("Div", 13, "")
        op = Op(self, "Div", schema)
        return op(*self._prepare_inputs(schema, A, B))

    T_Dropout = TypeVar("T_Dropout", BFLOAT16, DOUBLE, FLOAT, FLOAT16)

    T1_Dropout = TypeVar("T1_Dropout", DOUBLE, FLOAT, FLOAT16)

    T2_Dropout: TypeAlias = BOOL

    def Dropout(
        self,
        data: T_Dropout,
        ratio: Optional[T1_Dropout] = None,
        training_mode: Optional[T2_Dropout] = None,
        *,
        seed: Optional[int] = None,
    ) -> Tuple[T_Dropout, T2_Dropout]:
        r"""[🌐 Dropout(13)](https://onnx.ai/onnx/operators/onnx__Dropout.html#dropout-13 "Online Documentation")


        Dropout takes an input floating-point tensor, an optional input ratio (floating-point scalar) and an optional input training_mode (boolean scalar). It produces two tensor outputs,
        output (floating-point tensor) and mask (optional `Tensor<bool>`). If `training_mode` is true then the output Y will be a random dropout;
        Note that this Dropout scales the masked input data by the following equation, so to convert the trained model into inference mode,
        the user can simply not pass `training_mode` input or set it to false.
        ::

            output = scale * data * mask,


        where
        ::

            scale = 1. / (1. - ratio).


        This operator has **optional** inputs/outputs. See `ONNX <https://github.com/onnx/onnx/blob/master/docs/IR.md>`_ for more details about the representation of optional arguments. An empty string may be used in the place of an actual argument's name to indicate a missing argument. Trailing optional arguments (those not followed by an argument that is present) may also be simply omitted.


        Args:
            data: (differentiable) The input data as Tensor.

            ratio: (optional, non-differentiable) The ratio of random dropout, with
                value in [0, 1). If this input was not set, or if it was set to 0, the
                output would be a simple copy of the input. If it's non-zero, output
                will be a random dropout of the scaled input, which is typically the
                case during training. It is an optional value, if not specified it will
                default to 0.5.

            training_mode: (optional, non-differentiable) If set to true then it
                indicates dropout is being used for training. It is an optional value
                hence unless specified explicitly, it is false. If it is false, ratio is
                ignored and the operation mimics inference mode where nothing will be
                dropped from the input data and if mask is requested as output it will
                contain all ones.

            seed: (Optional) Seed to the random generator, if not specified we will auto
                generate one.
        """

        schema = get_schema("Dropout", 13, "")
        op = Op(self, "Dropout", schema)
        return op(*self._prepare_inputs(schema, data, ratio, training_mode), seed=seed)

    T_Equal = TypeVar(
        "T_Equal",
        BFLOAT16,
        BOOL,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    T1_Equal: TypeAlias = BOOL

    def Equal(self, A: T_Equal, B: T_Equal) -> T1_Equal:
        r"""[🌐 Equal(13)](https://onnx.ai/onnx/operators/onnx__Equal.html#equal-13 "Online Documentation")


        Returns the tensor resulted from performing the `equal` logical operation
        elementwise on the input tensors `A` and `B` (with Numpy-style broadcasting support).

        This operator supports **multidirectional (i.e., Numpy-style) broadcasting**; for more details please check `Broadcasting in ONNX <https://github.com/onnx/onnx/blob/master/docs/Broadcasting.md>`_.


        Args:
            A: (non-differentiable) First input operand for the logical operator.

            B: (non-differentiable) Second input operand for the logical operator.
        """

        schema = get_schema("Equal", 13, "")
        op = Op(self, "Equal", schema)
        return op(*self._prepare_inputs(schema, A, B))

    T_Erf = TypeVar(
        "T_Erf",
        BFLOAT16,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    def Erf(self, input: T_Erf) -> T_Erf:
        r"""[🌐 Erf(13)](https://onnx.ai/onnx/operators/onnx__Erf.html#erf-13 "Online Documentation")


        Computes the error function of the given input tensor element-wise.


        Args:
            input: (differentiable) Input tensor
        """

        schema = get_schema("Erf", 13, "")
        op = Op(self, "Erf", schema)
        return op(*self._prepare_inputs(schema, input))

    T_Exp = TypeVar("T_Exp", BFLOAT16, DOUBLE, FLOAT, FLOAT16)

    def Exp(self, input: T_Exp) -> T_Exp:
        r"""[🌐 Exp(13)](https://onnx.ai/onnx/operators/onnx__Exp.html#exp-13 "Online Documentation")


        Calculates the exponential of the given input tensor, element-wise.


        Args:
            input: (differentiable) Input tensor
        """

        schema = get_schema("Exp", 13, "")
        op = Op(self, "Exp", schema)
        return op(*self._prepare_inputs(schema, input))

    T_Expand = TypeVar(
        "T_Expand",
        BFLOAT16,
        BOOL,
        COMPLEX128,
        COMPLEX64,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        STRING,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    def Expand(self, input: T_Expand, shape: INT64) -> T_Expand:
        r"""[🌐 Expand(13)](https://onnx.ai/onnx/operators/onnx__Expand.html#expand-13 "Online Documentation")


        Broadcast the input tensor following the given shape and the broadcast rule.
        The broadcast rule is similar to numpy.array(input) * numpy.ones(shape):
        Dimensions are right alignment;
        Two corresponding dimensions must have the same value, or one of them is equal to 1.
        Also, this operator is similar to numpy.broadcast_to(input, shape),
        but the major difference is numpy.broadcast_to() does not allow shape to be smaller than input.size().
        It is possible that the output.shape is not equal to shape, when some dimensions in shape is equal to 1,
        or the shape.ndim < input.shape.ndim.


        Args:
            input: (differentiable) Input tensor

            shape: (non-differentiable) A 1-D tensor indicates the shape you want to
                expand to, following the broadcast rule
        """

        schema = get_schema("Expand", 13, "")
        op = Op(self, "Expand", schema)
        return op(*self._prepare_inputs(schema, input, shape))

    T_Flatten = TypeVar(
        "T_Flatten",
        BFLOAT16,
        BOOL,
        COMPLEX128,
        COMPLEX64,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        STRING,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    def Flatten(self, input: T_Flatten, *, axis: int = 1) -> T_Flatten:
        r"""[🌐 Flatten(13)](https://onnx.ai/onnx/operators/onnx__Flatten.html#flatten-13 "Online Documentation")


        Flattens the input tensor into a 2D matrix. If input tensor has shape
        (d_0, d_1, ... d_n) then the output will have shape
        (d_0 X d_1 ... d_(axis-1), d_axis X d_(axis+1) ... X dn).


        Args:
            input: (differentiable) A tensor of rank >= axis.

            axis: Indicate up to which input dimensions (exclusive) should be flattened
                to the outer dimension of the output. The value for axis must be in the
                range [-r, r], where r is the rank of the input tensor. Negative value
                means counting dimensions from the back. When axis = 0, the shape of the
                output tensor is (1, (d_0 X d_1 ... d_n), where the shape of the input
                tensor is (d_0, d_1, ... d_n).
        """

        schema = get_schema("Flatten", 13, "")
        op = Op(self, "Flatten", schema)
        return op(*self._prepare_inputs(schema, input), axis=axis)

    T_Floor = TypeVar("T_Floor", BFLOAT16, DOUBLE, FLOAT, FLOAT16)

    def Floor(self, X: T_Floor) -> T_Floor:
        r"""[🌐 Floor(13)](https://onnx.ai/onnx/operators/onnx__Floor.html#floor-13 "Online Documentation")


        Floor takes one input data (Tensor<T>) and produces one output data
        (Tensor<T>) where the floor is, y = floor(x), is applied to
        the tensor elementwise. If x is integral, +0, -0, NaN,  or infinite, x itself is returned.


        Args:
            X: (non-differentiable) Input tensor
        """

        schema = get_schema("Floor", 13, "")
        op = Op(self, "Floor", schema)
        return op(*self._prepare_inputs(schema, X))

    T_Gather = TypeVar(
        "T_Gather",
        BFLOAT16,
        BOOL,
        COMPLEX128,
        COMPLEX64,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        STRING,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    Tind_Gather = TypeVar("Tind_Gather", INT32, INT64)

    def Gather(self, data: T_Gather, indices: Tind_Gather, *, axis: int = 0) -> T_Gather:
        r"""[🌐 Gather(13)](https://onnx.ai/onnx/operators/onnx__Gather.html#gather-13 "Online Documentation")


        Given `data` tensor of rank r >= 1, and `indices` tensor of rank q, gather
        entries of the axis dimension of `data` (by default outer-most one as axis=0) indexed by `indices`, and concatenates
        them in an output tensor of rank q + (r - 1).

        It is an indexing operation that indexes into the input `data` along a single (specified) axis.
        Each entry in `indices` produces a `r-1` dimensional slice of the input tensor.
        The entire operation produces, conceptually, a `q`-dimensional tensor of `r-1` dimensional slices,
        which is arranged into a `q + (r-1)`-dimensional tensor, with the `q` dimensions taking the
        place of the original `axis` that is being indexed into.

        The following few examples illustrate how `Gather` works for specific shapes of `data`,
        `indices`, and given value of `axis`:
        | data shape | indices shape | axis | output shape | output equation |
        | --- | --- | --- | --- | --- |
        | (P, Q) | ( )  (a scalar)   | 0 | (Q)       | output[q] = data[indices, q] |
        | (P, Q, R) | ( )  (a scalar)   | 1 | (P, R)       | output[p, r] = data[p, indices, r] |
        | (P, Q) | (R, S) | 0 | (R, S, Q) | output[r, s, q] = data[ [indices[r, s], q] |
        | (P, Q) | (R, S) | 1 | (P, R, S) | output[p, r, s] = data[ p, indices[r, s]] |

        More generally, if `axis = 0`, let `k = indices[i_{0}, ..., i_{q-1}]`
        then `output[i_{0}, ..., i_{q-1}, j_{0}, ..., j_{r-2}] = input[k , j_{0}, ..., j_{r-2}]`:

        ::

            data = [
                [1.0, 1.2],
                [2.3, 3.4],
                [4.5, 5.7],
            ]
            indices = [
                [0, 1],
                [1, 2],
            ]
            output = [
                [
                    [1.0, 1.2],
                    [2.3, 3.4],
                ],
                [
                    [2.3, 3.4],
                    [4.5, 5.7],
                ],
            ]



        If `axis = 1`, let `k = indices[i_{0}, ..., i_{q-1}]`
        then `output[j_{0}, i_{0}, ..., i_{q-1}, j_{1}, ..., j_{r-2}] = input[j_{0}, k, j_{1}, ..., j_{r-2}]`:

        ::

            data = [
                [1.0, 1.2, 1.9],
                [2.3, 3.4, 3.9],
                [4.5, 5.7, 5.9],
            ]
            indices = [
                [0, 2],
            ]
            axis = 1,
            output = [
                    [[1.0, 1.9]],
                    [[2.3, 3.9]],
                    [[4.5, 5.9]],
            ]




        Args:
            data: (differentiable) Tensor of rank r >= 1.

            indices: (non-differentiable) Tensor of int32/int64 indices, of any rank q.
                All index values are expected to be within bounds [-s, s-1] along axis
                of size s. It is an error if any of the index values are out of bounds.

            axis: Which axis to gather on. Negative value means counting dimensions from
                the back. Accepted range is [-r, r-1] where r = rank(data).
        """

        schema = get_schema("Gather", 13, "")
        op = Op(self, "Gather", schema)
        return op(*self._prepare_inputs(schema, data, indices), axis=axis)

    T_GatherElements = TypeVar(
        "T_GatherElements",
        BFLOAT16,
        BOOL,
        COMPLEX128,
        COMPLEX64,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        STRING,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    Tind_GatherElements = TypeVar("Tind_GatherElements", INT32, INT64)

    def GatherElements(
        self, data: T_GatherElements, indices: Tind_GatherElements, *, axis: int = 0
    ) -> T_GatherElements:
        r"""[🌐 GatherElements(13)](https://onnx.ai/onnx/operators/onnx__GatherElements.html#gatherelements-13 "Online Documentation")



        GatherElements takes two inputs `data` and `indices` of the same rank r >= 1
        and an optional attribute `axis` that identifies an axis of `data`
        (by default, the outer-most axis, that is axis 0). It is an indexing operation
        that produces its output by indexing into the input data tensor at index
        positions determined by elements of the `indices` tensor.
        Its output shape is the same as the shape of `indices` and consists of one value
        (gathered from the `data`) for each element in `indices`.

        For instance, in the 3-D case (r = 3), the output produced is determined
        by the following equations:
        ::

            out[i][j][k] = input[index[i][j][k]][j][k] if axis = 0,
            out[i][j][k] = input[i][index[i][j][k]][k] if axis = 1,
            out[i][j][k] = input[i][j][index[i][j][k]] if axis = 2,



        This operator is also the inverse of ScatterElements. It is similar to Torch's gather operation.

        Example 1:
        ::

            data = [
                [1, 2],
                [3, 4],
            ]
            indices = [
                [0, 0],
                [1, 0],
            ]
            axis = 1
            output = [
                [1, 1],
                [4, 3],
            ]


        Example 2:
        ::

            data = [
                [1, 2, 3],
                [4, 5, 6],
                [7, 8, 9],
            ]
            indices = [
                [1, 2, 0],
                [2, 0, 0],
            ]
            axis = 0
            output = [
                [4, 8, 3],
                [7, 2, 3],
            ]




        Args:
            data: (differentiable) Tensor of rank r >= 1.

            indices: (non-differentiable) Tensor of int32/int64 indices, with the same
                rank r as the input. All index values are expected to be within bounds
                [-s, s-1] along axis of size s. It is an error if any of the index
                values are out of bounds.

            axis: Which axis to gather on. Negative value means counting dimensions from
                the back. Accepted range is [-r, r-1] where r = rank(data).
        """

        schema = get_schema("GatherElements", 13, "")
        op = Op(self, "GatherElements", schema)
        return op(*self._prepare_inputs(schema, data, indices), axis=axis)

    T_GatherND = TypeVar(
        "T_GatherND",
        BFLOAT16,
        BOOL,
        COMPLEX128,
        COMPLEX64,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        STRING,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    def GatherND(self, data: T_GatherND, indices: INT64, *, batch_dims: int = 0) -> T_GatherND:
        r"""[🌐 GatherND(13)](https://onnx.ai/onnx/operators/onnx__GatherND.html#gathernd-13 "Online Documentation")


        Given `data` tensor of rank `r` >= 1, `indices` tensor of rank `q` >= 1, and `batch_dims` integer `b`, this operator gathers
        slices of `data` into an output tensor of rank `q + r - indices_shape[-1] - 1 - b`.

        `indices` is an q-dimensional integer tensor, best thought of as a `(q-1)`-dimensional tensor of index-tuples into `data`,
        where each element defines a slice of `data`

        `batch_dims` (denoted as `b`) is an integer indicating the number of batch dimensions, i.e the leading `b` number of dimensions of
        `data` tensor and `indices` are representing the batches, and the gather starts from the `b+1` dimension.

        Some salient points about the inputs' rank and shape:

        1) r >= 1 and q >= 1 are to be honored. There is no dependency condition to be met between ranks `r` and `q`

        2) The first `b` dimensions of the shape of `indices` tensor and `data` tensor must be equal.

        3) b < min(q, r) is to be honored.

        4) The `indices_shape[-1]` should have a value between 1 (inclusive) and rank `r-b` (inclusive)

        5) All values in `indices` are expected to be within bounds [-s, s-1] along axis of size `s` (i.e.) `-data_shape[i] <= indices[...,i] <= data_shape[i] - 1`.
           It is an error if any of the index values are out of bounds.

        The output is computed as follows:

        The output tensor is obtained by mapping each index-tuple in the `indices` tensor to the corresponding slice of the input `data`.

        1) If `indices_shape[-1] > r-b` => error condition

        2) If `indices_shape[-1] == r-b`, since the rank of `indices` is `q`, `indices` can be thought of as `N` `(q-b-1)`-dimensional tensors
           containing 1-D tensors of dimension `r-b`, where `N` is an integer equals to the product of 1 and all the elements in the batch dimensions
           of the indices_shape. Let us think of each such `r-b` ranked tensor as `indices_slice`. Each *scalar value* corresponding to `data[0:b-1,indices_slice]`
           is filled into the corresponding location of the `(q-b-1)`-dimensional tensor to form the `output` tensor (Example 1 below)

        3) If `indices_shape[-1] < r-b`, since the rank of `indices` is `q`, `indices` can be thought of as `N` `(q-b-1)`-dimensional tensor
           containing 1-D tensors of dimension `< r-b`. Let us think of each such tensors as `indices_slice`. Each *tensor slice* corresponding
           to `data[0:b-1, indices_slice , :]` is filled into the corresponding location of the `(q-b-1)`-dimensional tensor
           to form the `output` tensor (Examples 2, 3, 4 and 5 below)

        This operator is the inverse of `ScatterND`.

        **Example 1**

        ::

            batch_dims = 0
            data    = [[0,1],[2,3]]   # data_shape    = [2, 2]
            indices = [[0,0],[1,1]]   # indices_shape = [2, 2]
            output  = [0,3]           # output_shape  = [2]



        **Example 2**

        ::

            batch_dims = 0
            data    = [[0,1],[2,3]]  # data_shape    = [2, 2]
            indices = [[1],[0]]      # indices_shape = [2, 1]
            output  = [[2,3],[0,1]]  # output_shape  = [2, 2]



        **Example 3**

        ::

            batch_dims = 0
            data    = [[[0,1],[2,3]],[[4,5],[6,7]]] # data_shape    = [2, 2, 2]
            indices = [[0,1],[1,0]]                 # indices_shape = [2, 2]
            output  = [[2,3],[4,5]]                 # output_shape  = [2, 2]



        **Example 4**

        ::

            batch_dims = 0
            data    = [[[0,1],[2,3]],[[4,5],[6,7]]] # data_shape    = [2, 2, 2]
            indices = [[[0,1]],[[1,0]]]             # indices_shape = [2, 1, 2]
            output  = [[[2,3]],[[4,5]]]             # output_shape  = [2, 1, 2]



        **Example 5**

        ::

            batch_dims = 1
            data    = [[[0,1],[2,3]],[[4,5],[6,7]]] # data_shape    = [2, 2, 2]
            indices = [[1],[0]]                     # indices_shape = [2, 1]
            output  = [[2,3],[4,5]]                 # output_shape  = [2, 2]




        Args:
            data: (differentiable) Tensor of rank r >= 1.

            indices: (non-differentiable) Tensor of rank q >= 1. All index values are
                expected to be within bounds [-s, s-1] along axis of size s. It is an
                error if any of the index values are out of bounds.

            batch_dims: The number of batch dimensions. The gather of indexing starts
                from dimension of data[batch_dims:]
        """

        schema = get_schema("GatherND", 13, "")
        op = Op(self, "GatherND", schema)
        return op(*self._prepare_inputs(schema, data, indices), batch_dims=batch_dims)

    T_Gemm = TypeVar("T_Gemm", BFLOAT16, DOUBLE, FLOAT, FLOAT16, INT32, INT64, UINT32, UINT64)

    def Gemm(
        self,
        A: T_Gemm,
        B: T_Gemm,
        C: Optional[T_Gemm] = None,
        *,
        alpha: float = 1.0,
        beta: float = 1.0,
        transA: int = 0,
        transB: int = 0,
    ) -> T_Gemm:
        r"""[🌐 Gemm(13)](https://onnx.ai/onnx/operators/onnx__Gemm.html#gemm-13 "Online Documentation")

        General Matrix multiplication:
        https://en.wikipedia.org/wiki/Basic_Linear_Algebra_Subprograms#Level_3

        * A' = transpose(A) if transA else A
        * B' = transpose(B) if transB else B

        Compute Y = alpha * A' * B' + beta * C, where input tensor A has shape (M, K) or (K, M),
        input tensor B has shape (K, N) or (N, K), input tensor C is broadcastable to shape (M, N),
        and output tensor Y has shape (M, N). A will be transposed before doing the
        computation if attribute transA is non-zero, same for B and transB.
        This operator supports **unidirectional broadcasting** (tensor C should be unidirectional broadcastable to tensor A * B); for more details please check `Broadcasting in ONNX <https://github.com/onnx/onnx/blob/master/docs/Broadcasting.md>`_.
        This operator has **optional** inputs/outputs. See `ONNX <https://github.com/onnx/onnx/blob/master/docs/IR.md>`_ for more details about the representation of optional arguments. An empty string may be used in the place of an actual argument's name to indicate a missing argument. Trailing optional arguments (those not followed by an argument that is present) may also be simply omitted.


        Args:
            A: (differentiable) Input tensor A. The shape of A should be (M, K) if
                transA is 0, or (K, M) if transA is non-zero.

            B: (differentiable) Input tensor B. The shape of B should be (K, N) if
                transB is 0, or (N, K) if transB is non-zero.

            C: (optional, differentiable) Optional input tensor C. If not specified, the
                computation is done as if C is a scalar 0. The shape of C should be
                unidirectional broadcastable to (M, N).

            alpha: Scalar multiplier for the product of input tensors A * B.

            beta: Scalar multiplier for input tensor C.

            transA: Whether A should be transposed

            transB: Whether B should be transposed
        """

        schema = get_schema("Gemm", 13, "")
        op = Op(self, "Gemm", schema)
        return op(
            *self._prepare_inputs(schema, A, B, C),
            alpha=alpha,
            beta=beta,
            transA=transA,
            transB=transB,
        )

    T_Greater = TypeVar(
        "T_Greater",
        BFLOAT16,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    T1_Greater: TypeAlias = BOOL

    def Greater(self, A: T_Greater, B: T_Greater) -> T1_Greater:
        r"""[🌐 Greater(13)](https://onnx.ai/onnx/operators/onnx__Greater.html#greater-13 "Online Documentation")


        Returns the tensor resulted from performing the `greater` logical operation
        elementwise on the input tensors `A` and `B` (with Numpy-style broadcasting support).

        This operator supports **multidirectional (i.e., Numpy-style) broadcasting**; for more details please check `Broadcasting in ONNX <https://github.com/onnx/onnx/blob/master/docs/Broadcasting.md>`_.


        Args:
            A: (non-differentiable) First input operand for the logical operator.

            B: (non-differentiable) Second input operand for the logical operator.
        """

        schema = get_schema("Greater", 13, "")
        op = Op(self, "Greater", schema)
        return op(*self._prepare_inputs(schema, A, B))

    T_Hardmax = TypeVar("T_Hardmax", BFLOAT16, DOUBLE, FLOAT, FLOAT16)

    def Hardmax(self, input: T_Hardmax, *, axis: int = -1) -> T_Hardmax:
        r"""[🌐 Hardmax(13)](https://onnx.ai/onnx/operators/onnx__Hardmax.html#hardmax-13 "Online Documentation")


        The operator computes the hardmax values for the given input:

         Hardmax(element in input, axis) = 1 if the element is the first maximum value along the specified axis, 0 otherwise

        The "axis" attribute indicates the dimension along which Hardmax
        will be performed. The output tensor has the same shape
        and contains the Hardmax values of the corresponding input.


        Args:
            input: (differentiable) The input tensor of rank >= axis.

            axis:
        Describes the dimension Hardmax will be performed on.
        Negative value
                means counting dimensions
        from the back. Accepted range is [-r, r-1]
                where r = rank(input).
        """

        schema = get_schema("Hardmax", 13, "")
        op = Op(self, "Hardmax", schema)
        return op(*self._prepare_inputs(schema, input), axis=axis)

    T_Identity = TypeVar(
        "T_Identity",
        BFLOAT16,
        BOOL,
        COMPLEX128,
        COMPLEX64,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        STRING,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    def Identity(self, input: T_Identity) -> T_Identity:
        r"""[🌐 Identity(13)](https://onnx.ai/onnx/operators/onnx__Identity.html#identity-13 "Online Documentation")

        Identity operator

        Args:
            input: (differentiable) Input tensor
        """

        schema = get_schema("Identity", 13, "")
        op = Op(self, "Identity", schema)
        return op(*self._prepare_inputs(schema, input))

    B_If: TypeAlias = BOOL

    V_If: TypeAlias = Union[
        Sequence[BOOL],
        Sequence[COMPLEX128],
        Sequence[COMPLEX64],
        Sequence[DOUBLE],
        Sequence[FLOAT],
        Sequence[FLOAT16],
        Sequence[INT16],
        Sequence[INT32],
        Sequence[INT64],
        Sequence[INT8],
        Sequence[STRING],
        Sequence[UINT16],
        Sequence[UINT32],
        Sequence[UINT64],
        Sequence[UINT8],
        BOOL,
        COMPLEX128,
        COMPLEX64,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        STRING,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    ]

    def If(self, cond: B_If, *, else_branch: GraphProto, then_branch: GraphProto) -> V_If:
        r"""[🌐 If(13)](https://onnx.ai/onnx/operators/onnx__If.html#if-13 "Online Documentation")

        If conditional

        Args:
            cond: Condition for the if. The tensor must contain a single element.

            else_branch: Graph to run if condition is false. Has N outputs: values you
                wish to be live-out to the enclosing scope. The number of outputs must
                match the number of outputs in the then_branch.

            then_branch: Graph to run if condition is true. Has N outputs: values you
                wish to be live-out to the enclosing scope. The number of outputs must
                match the number of outputs in the else_branch.
        """

        schema = get_schema("If", 13, "")
        op = Op(self, "If", schema)
        return op(
            *self._prepare_inputs(schema, cond),
            else_branch=else_branch,
            then_branch=then_branch,
        )

    T1_IsNaN = TypeVar("T1_IsNaN", BFLOAT16, DOUBLE, FLOAT, FLOAT16)

    T2_IsNaN: TypeAlias = BOOL

    def IsNaN(self, X: T1_IsNaN) -> T2_IsNaN:
        r"""[🌐 IsNaN(13)](https://onnx.ai/onnx/operators/onnx__IsNaN.html#isnan-13 "Online Documentation")

        Returns which elements of the input are NaN.

        Args:
            X: (non-differentiable) input
        """

        schema = get_schema("IsNaN", 13, "")
        op = Op(self, "IsNaN", schema)
        return op(*self._prepare_inputs(schema, X))

    T_LRN = TypeVar("T_LRN", BFLOAT16, DOUBLE, FLOAT, FLOAT16)

    def LRN(
        self,
        X: T_LRN,
        *,
        alpha: float = 9.999999747378752e-05,
        beta: float = 0.75,
        bias: float = 1.0,
        size: int,
    ) -> T_LRN:
        r"""[🌐 LRN(13)](https://onnx.ai/onnx/operators/onnx__LRN.html#lrn-13 "Online Documentation")


        Local Response Normalization proposed in the [AlexNet paper](https://papers.nips.cc/paper/4824-imagenet-classification-with-deep-convolutional-neural-networks.pdf).
        It normalizes over local input regions.
        The local region is defined across the channels. For an element `X[n, c, d1, ..., dk]` in a tensor
        of shape `(N x C x D1 x D2, ..., Dk)`, its region is
        `{X[n, i, d1, ..., dk] | max(0, c - floor((size - 1) / 2)) <= i <= min(C - 1, c + ceil((size - 1) / 2))}`.

        `square_sum[n, c, d1, ..., dk] = sum(X[n, i, d1, ..., dk] ^ 2)`,
        where `max(0, c - floor((size - 1) / 2)) <= i <= min(C - 1, c + ceil((size - 1) / 2))`.

        `Y[n, c, d1, ..., dk] = X[n, c, d1, ..., dk] / (bias + alpha / size * square_sum[n, c, d1, ..., dk] ) ^ beta`


        Args:
            X: (differentiable) Input data tensor from the previous operator; dimensions
                for image case are (N x C x H x W), where N is the batch size, C is the
                number of channels, and H and W are the height and the width of the
                data. For non image case, the dimensions are in the form of (N x C x D1
                x D2 ... Dn), where N is the batch size. Optionally, if dimension
                denotation is in effect, the operation expects the input data tensor to
                arrive with the dimension denotation of [DATA_BATCH, DATA_CHANNEL,
                DATA_FEATURE, DATA_FEATURE ...].

            alpha: Scaling parameter.

            beta: The exponent.

            size: The number of channels to sum over
        """

        schema = get_schema("LRN", 13, "")
        op = Op(self, "LRN", schema)
        return op(
            *self._prepare_inputs(schema, X),
            alpha=alpha,
            beta=beta,
            bias=bias,
            size=size,
        )

    T_Less = TypeVar(
        "T_Less",
        BFLOAT16,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    T1_Less: TypeAlias = BOOL

    def Less(self, A: T_Less, B: T_Less) -> T1_Less:
        r"""[🌐 Less(13)](https://onnx.ai/onnx/operators/onnx__Less.html#less-13 "Online Documentation")


        Returns the tensor resulted from performing the `less` logical operation
        elementwise on the input tensors `A` and `B` (with Numpy-style broadcasting support).

        This operator supports **multidirectional (i.e., Numpy-style) broadcasting**; for more details please check `Broadcasting in ONNX <https://github.com/onnx/onnx/blob/master/docs/Broadcasting.md>`_.


        Args:
            A: (non-differentiable) First input operand for the logical operator.

            B: (non-differentiable) Second input operand for the logical operator.
        """

        schema = get_schema("Less", 13, "")
        op = Op(self, "Less", schema)
        return op(*self._prepare_inputs(schema, A, B))

    T_Log = TypeVar("T_Log", BFLOAT16, DOUBLE, FLOAT, FLOAT16)

    def Log(self, input: T_Log) -> T_Log:
        r"""[🌐 Log(13)](https://onnx.ai/onnx/operators/onnx__Log.html#log-13 "Online Documentation")


        Calculates the natural log of the given input tensor, element-wise.


        Args:
            input: (differentiable) Input tensor
        """

        schema = get_schema("Log", 13, "")
        op = Op(self, "Log", schema)
        return op(*self._prepare_inputs(schema, input))

    T_LogSoftmax = TypeVar("T_LogSoftmax", BFLOAT16, DOUBLE, FLOAT, FLOAT16)

    def LogSoftmax(self, input: T_LogSoftmax, *, axis: int = -1) -> T_LogSoftmax:
        r"""[🌐 LogSoftmax(13)](https://onnx.ai/onnx/operators/onnx__LogSoftmax.html#logsoftmax-13 "Online Documentation")


        The operator computes the log of softmax values for the given input:

         LogSoftmax(input, axis) = Log(Softmax(input, axis=axis))

        The "axis" attribute indicates the dimension along which LogSoftmax
        will be performed. The output tensor has the same shape
        and contains the LogSoftmax values of the corresponding input.


        Args:
            input: (differentiable) The input tensor of rank >= axis.

            axis:
        Describes the dimension LogSoftmax will be performed on.
        Negative
                value means counting dimensions
        from the back. Accepted range is [-r,
                r-1] where r = rank(input).
        """

        schema = get_schema("LogSoftmax", 13, "")
        op = Op(self, "LogSoftmax", schema)
        return op(*self._prepare_inputs(schema, input), axis=axis)

    I_Loop: TypeAlias = INT64

    B_Loop: TypeAlias = BOOL

    V_Loop = TypeVar(
        "V_Loop",
        Sequence[BOOL],
        Sequence[COMPLEX128],
        Sequence[COMPLEX64],
        Sequence[DOUBLE],
        Sequence[FLOAT],
        Sequence[FLOAT16],
        Sequence[INT16],
        Sequence[INT32],
        Sequence[INT64],
        Sequence[INT8],
        Sequence[STRING],
        Sequence[UINT16],
        Sequence[UINT32],
        Sequence[UINT64],
        Sequence[UINT8],
        BOOL,
        COMPLEX128,
        COMPLEX64,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        STRING,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    def Loop(
        self,
        M: Optional[I_Loop],
        cond: Optional[B_Loop],
        *v_initial: V_Loop,
        body: GraphProto,
    ) -> V_Loop:
        r"""[🌐 Loop(13)](https://onnx.ai/onnx/operators/onnx__Loop.html#loop-13 "Online Documentation")


        Generic Looping construct. This loop has multiple termination conditions:

        1) Trip count. Iteration count specified at runtime. Set by
           specifying the input M. Optional. Set to empty string to omit.
           Note that a static trip count (specified at graph construction time) can be
           specified by passing in a constant node for input M.
        2) Loop termination condition. This is an input to the op that determines
           whether to run the first iteration and also a loop-carried dependency for
           the body graph. The body graph must yield a value for the condition variable,
           whether this input is provided or not.

        This table summarizes the operating modes of this operator with equivalent
        C-style code:

        Operator inputs defined as (max_trip_count, condition_var).

            input ("", ""):
                for (int i=0; ; ++i) {
                  cond = ... // Note this value is ignored, but is required in the body
                }

            input ("", cond) // Note this is analogous to a while loop
                bool cond = ...;
                for (int i=0; cond; ++i) {
                  cond = ...;
                }

            input ("", 1) // Note this is analogous to a do-while loop
                bool cond = true
                for (int i=0; cond; ++i) {
                  cond = ...;
                }

            input (trip_count, "") // Note this is analogous to a for loop
                int trip_count = ...
                for (int i=0; i < trip_count; ++i) {
                  cond = ...; // ignored
                }

            input (trip_count, cond)
                int trip_count = ...;
                bool cond = ...;
                for (int i=0; i < trip_count && cond; ++i) {
                  cond = ...;
                }


        *Sample usage - cond as well as trip count*

            graph predict-net {
              %a = Constant[value = <Scalar Tensor [3]>]()
              %b = Constant[value = <Scalar Tensor [6]>]()
              %keepgoing = Constant[value = <Scalar Tensor [1]>]()
              %max_trip_count = Constant[value = <Scalar Tensor [10]>]()
              %keepgoing_out, %b_out, %user_defined_vals = Loop[body = <graph body-net>](%max_trip_count, %keepgoing, %b)
              return
            }

            graph body-net (
              %i[INT32, scalar]           // iteration number
              %keepgoing_in[BOOL, scalar] // incoming loop-termination-condition; not used
              %b_in[INT32, scalar]        // incoming value of loop-carried-dependency b
            ) {
              %my_local = Add(%a, %b_in)
              %b_out = Sub(%a, %b_in) // outgoing value of loop-carried-dependency b
              %keepgoing_out = Greater(%my_local, %b_out) // outgoing loop-termination-condition
              %user_defined_val = Add(%b_in, %b_in) // scan-output value to be accumulated
              return %keepgoing_out, %b_out, %user_defined_val
            }

        *Sample equivalent C code*

            {
              /* User-defined code (enclosing scope) */
              int a = 3, b = 6;
              bool keepgoing = true; // Analogous to input cond
              /* End user-defined code */

              /* Implicitly-defined code */
              const int max_trip_count = 10; // Analogous to input M
              int user_defined_vals[]; // Imagine this is resizable
              /* End implicitly-defined code */
              /* initialize loop-carried variables and scan-output variables */
              bool keepgoing_out = keepgoing
              int b_out = b

              for (int i=0; i < max_trip_count && keepgoing_out; ++i) {
                /* Implicitly-defined code: bind actual parameter values
                   to formal parameter variables of loop-body */
                bool keepgoing_in = keepgoing_out;
                bool b_in = b_out;

                /* User-defined code (loop body) */
                int my_local = a + b_in; // Reading value "a" from the enclosing scope is fine
                b_out = a - b_in;
                keepgoing_out = my_local > b_out;
                user_defined_val = b_in + b_in; // b_in and b_out are different variables
                /* End user-defined code */

                /* Implicitly defined-code */
                user_defined_vals[i] = user_defined_val // accumulate scan-output values
              }
              // int t = my_local; // Can't do this. my_local is not accessible here.

              // The values below are bound to the output variables of the loop and therefore accessible
              // b_out; user_defined_vals; keepgoing_out;
            }

        There are several things of note in this code snippet:

        1) Values from the enclosing scope (i.e. variable "a" here) are in scope and can
           be referenced in the inputs of the loop.
        2) Any values computed in the loop body that needs to be used in a subsequent
           iteration or after the loop are modelled using a pair of variables in the loop-body,
           consisting of an input variable (eg., b_in) and an output variable (eg., b_out).
           These are referred to as loop-carried dependences. The loop operation node
           supplies the input value of the input variable for the first iteration, and
           returns the output value of the output variable produced by the final
           iteration.
        3) Scan_output variables are used to implicitly concatenate values computed across
           all the iterations. In the above example, the value of user_defined_val computed
           over all iterations are concatenated and returned as the value of user_defined_vals
           after the loop.
        4) Values created in the body cannot be accessed in the enclosing scope,
           except using the mechanism described above.

        Note that the semantics of this op support "diagonal" or "wavefront" execution.
        (See Step 3 here for an example:
        https://devblogs.nvidia.com/optimizing-recurrent-neural-networks-cudnn-5/).
        Frontends should emit multi-layer RNNs as a series of While operators (with
        time being the inner looping dimension), with each successive layer consuming
        the scan_outputs from the previous layer, possibly going through several
        point-wise operators (e.g. dropout, residual connections, linear layer).

        The input/output of subgraph (produced by loop node) matching is based on order instead of name. The implementation will figure out the names based on this order.


        Args:
            M: (optional) A maximum trip-count for the loop specified at runtime.
                Optional. Pass empty string to skip.

            cond: (optional) A boolean termination condition. Optional. Pass empty
                string to skip.

            v_initial: (variadic, heterogeneous) The initial values of any loop-carried
                dependencies (values that change across loop iterations)

            body: The graph run each iteration. It has 2+N inputs: (iteration_num,
                condition, loop carried dependencies...). It has 1+N+K outputs:
                (condition, loop carried dependencies..., scan_outputs...). Each
                scan_output is created by concatenating the value of the specified
                output value at the end of each iteration of the loop. It is an error if
                the dimensions or data type of these scan_outputs change across loop
                iterations.
        """

        schema = get_schema("Loop", 13, "")
        op = Op(self, "Loop", schema)
        return op(*self._prepare_inputs(schema, M, cond, *v_initial), body=body)

    T_MatMul = TypeVar(
        "T_MatMul", BFLOAT16, DOUBLE, FLOAT, FLOAT16, INT32, INT64, UINT32, UINT64
    )

    def MatMul(self, A: T_MatMul, B: T_MatMul) -> T_MatMul:
        r"""[🌐 MatMul(13)](https://onnx.ai/onnx/operators/onnx__MatMul.html#matmul-13 "Online Documentation")


        Matrix product that behaves like [numpy.matmul](https://numpy.org/doc/stable/reference/generated/numpy.matmul.html).


        Args:
            A: (differentiable) N-dimensional matrix A

            B: (differentiable) N-dimensional matrix B
        """

        schema = get_schema("MatMul", 13, "")
        op = Op(self, "MatMul", schema)
        return op(*self._prepare_inputs(schema, A, B))

    T_Max = TypeVar(
        "T_Max",
        BFLOAT16,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    def Max(self, *data_0: T_Max) -> T_Max:
        r"""[🌐 Max(13)](https://onnx.ai/onnx/operators/onnx__Max.html#max-13 "Online Documentation")


        Element-wise max of each of the input tensors (with Numpy-style broadcasting support).
        All inputs and outputs must have the same data type.
        This operator supports **multidirectional (i.e., Numpy-style) broadcasting**; for more details please check `Broadcasting in ONNX <https://github.com/onnx/onnx/blob/master/docs/Broadcasting.md>`_.


        Args:
            data_0: (variadic, differentiable) List of tensors for max.
        """

        schema = get_schema("Max", 13, "")
        op = Op(self, "Max", schema)
        return op(*self._prepare_inputs(schema, *data_0))

    T_Mean = TypeVar("T_Mean", BFLOAT16, DOUBLE, FLOAT, FLOAT16)

    def Mean(self, *data_0: T_Mean) -> T_Mean:
        r"""[🌐 Mean(13)](https://onnx.ai/onnx/operators/onnx__Mean.html#mean-13 "Online Documentation")


        Element-wise mean of each of the input tensors (with Numpy-style broadcasting support).
        All inputs and outputs must have the same data type.
        This operator supports **multidirectional (i.e., Numpy-style) broadcasting**; for more details please check `Broadcasting in ONNX <https://github.com/onnx/onnx/blob/master/docs/Broadcasting.md>`_.


        Args:
            data_0: (variadic, differentiable) List of tensors for mean.
        """

        schema = get_schema("Mean", 13, "")
        op = Op(self, "Mean", schema)
        return op(*self._prepare_inputs(schema, *data_0))

    T_MeanVarianceNormalization = TypeVar(
        "T_MeanVarianceNormalization", BFLOAT16, DOUBLE, FLOAT, FLOAT16
    )

    def MeanVarianceNormalization(
        self, X: T_MeanVarianceNormalization, *, axes: Sequence[int] = (0, 2, 3)
    ) -> T_MeanVarianceNormalization:
        r"""[🌐 MeanVarianceNormalization(13)](https://onnx.ai/onnx/operators/onnx__MeanVarianceNormalization.html#meanvariancenormalization-13 "Online Documentation")


              A MeanVarianceNormalization Function: Perform mean variance normalization
              on the input tensor X using formula: `(X-EX)/sqrt(E(X-EX)^2)`


        Args:
            X: (differentiable) Input tensor

            axes: A list of integers, along which to reduce. The default is to calculate
                along axes [0,2,3] for calculating mean and variance along each channel.
                Two variables with the same C-coordinate are associated with the same
                mean and variance.
        """

        schema = get_schema("MeanVarianceNormalization", 13, "")
        op = Op(self, "MeanVarianceNormalization", schema)
        return op(*self._prepare_inputs(schema, X), axes=axes)

    T_Min = TypeVar(
        "T_Min",
        BFLOAT16,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    def Min(self, *data_0: T_Min) -> T_Min:
        r"""[🌐 Min(13)](https://onnx.ai/onnx/operators/onnx__Min.html#min-13 "Online Documentation")


        Element-wise min of each of the input tensors (with Numpy-style broadcasting support).
        All inputs and outputs must have the same data type.
        This operator supports **multidirectional (i.e., Numpy-style) broadcasting**; for more details please check `Broadcasting in ONNX <https://github.com/onnx/onnx/blob/master/docs/Broadcasting.md>`_.


        Args:
            data_0: (variadic, differentiable) List of tensors for min.
        """

        schema = get_schema("Min", 13, "")
        op = Op(self, "Min", schema)
        return op(*self._prepare_inputs(schema, *data_0))

    T_Mod = TypeVar(
        "T_Mod",
        BFLOAT16,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    def Mod(self, A: T_Mod, B: T_Mod, *, fmod: int = 0) -> T_Mod:
        r"""[🌐 Mod(13)](https://onnx.ai/onnx/operators/onnx__Mod.html#mod-13 "Online Documentation")


        Performs an element-wise binary modulo operation.
        The semantics and supported data types depend on the value of the `fmod` attribute which must be `0` (default), or `1`.

        If the `fmod` attribute is set to `0`, `T` is constrained to integer data types and the semantics follow that of the Python `%`-operator.
        The sign of the result is that of the divisor.

        If `fmod` is set to `1`, the behavior of this operator follows that of the `fmod` function in C and `T` is constrained to floating point data types.
        The result of this operator is the remainder of the division operation `x / y` where `x` and `y` are respective elements of `A` and `B`. The result is exactly the value `x - n * y`, where `n` is `x / y` with its fractional part truncated.
        The returned value has the same sign as `x` (except if `x` is `-0`) and is less or equal to `|y|` in magnitude.
        The following special cases apply when `fmod` is set to `1`:
        - If `x` is `-0` and `y` is greater than zero, either `+0` or `-0` may be returned.
        - If `x` is `±∞` and `y` is not `NaN`, `NaN` is returned.
        - If `y` is `±0` and `x` is not `NaN`, `NaN` should be returned.
        - If `y` is `±∞` and `x` is finite, `x` is returned.
        - If either argument is `NaN`, `NaN` is returned.

        This operator supports **multidirectional (i.e., NumPy-style) broadcasting**; for more details please check `Broadcasting in ONNX <https://github.com/onnx/onnx/blob/master/docs/Broadcasting.md>`_.


        Args:
            A: (differentiable) Dividend tensor

            B: (non-differentiable) Divisor tensor

            fmod: Whether the operator should behave like fmod (default=0 meaning it
                will do integer mods); Set this to 1 to force fmod treatment
        """

        schema = get_schema("Mod", 13, "")
        op = Op(self, "Mod", schema)
        return op(*self._prepare_inputs(schema, A, B), fmod=fmod)

    T_Mul = TypeVar("T_Mul", BFLOAT16, DOUBLE, FLOAT, FLOAT16, INT32, INT64, UINT32, UINT64)

    def Mul(self, A: T_Mul, B: T_Mul) -> T_Mul:
        r"""[🌐 Mul(13)](https://onnx.ai/onnx/operators/onnx__Mul.html#mul-13 "Online Documentation")


        Performs element-wise binary multiplication (with Numpy-style broadcasting support).

        This operator supports **multidirectional (i.e., Numpy-style) broadcasting**; for more details please check `Broadcasting in ONNX <https://github.com/onnx/onnx/blob/master/docs/Broadcasting.md>`_.


        Args:
            A: (differentiable) First operand.

            B: (differentiable) Second operand.
        """

        schema = get_schema("Mul", 13, "")
        op = Op(self, "Mul", schema)
        return op(*self._prepare_inputs(schema, A, B))

    T_Neg = TypeVar("T_Neg", BFLOAT16, DOUBLE, FLOAT, FLOAT16, INT16, INT32, INT64, INT8)

    def Neg(self, X: T_Neg) -> T_Neg:
        r"""[🌐 Neg(13)](https://onnx.ai/onnx/operators/onnx__Neg.html#neg-13 "Online Documentation")


        Neg takes one input data (Tensor<T>) and produces one output data
        (Tensor<T>) where each element flipped sign, y = -x, is applied to
        the tensor elementwise.


        Args:
            X: (differentiable) Input tensor
        """

        schema = get_schema("Neg", 13, "")
        op = Op(self, "Neg", schema)
        return op(*self._prepare_inputs(schema, X))

    T_NegativeLogLikelihoodLoss = TypeVar(
        "T_NegativeLogLikelihoodLoss", DOUBLE, FLOAT, FLOAT16
    )

    Tind_NegativeLogLikelihoodLoss = TypeVar("Tind_NegativeLogLikelihoodLoss", INT32, INT64)

    def NegativeLogLikelihoodLoss(
        self,
        input: T_NegativeLogLikelihoodLoss,
        target: Tind_NegativeLogLikelihoodLoss,
        weight: Optional[T_NegativeLogLikelihoodLoss] = None,
        *,
        ignore_index: Optional[int] = None,
        reduction: str = "mean",
    ) -> T_NegativeLogLikelihoodLoss:
        r"""[🌐 NegativeLogLikelihoodLoss(13)](https://onnx.ai/onnx/operators/onnx__NegativeLogLikelihoodLoss.html#negativeloglikelihoodloss-13 "Online Documentation")


        A NegativeLogLikelihoodLoss operator computes (weighted) negative log likelihood loss.
        Its "input" tensor has the shape of (N, C, d1, d2, ..., dk) where k >= 0.
        The "input" tensor contains log-probabilities for input[n, :, d_1, d_2,..., d_k] being in a class of [0, C).
        The operator's "target" input tensor has the shape of (N, d1, d2, ..., dk). It encodes class labels (one of C classes)
        or it may contain a special value (indicated by an attribute ignore_index) for N x d1 x d2 x ... x dk samples.
        The loss value for input[n, :, d_1, d_2,...d_k] being classified as class c = target[n][d_1][d_2]...[d_k] is computed as:

        ::

            loss[n][d_1][d_2]...[d_k] = -input[n][c][d_1][d_2]...[d_k].



        When an optional "weight" is provided, the sample loss is calculated as:

        ::

            loss[n][d_1][d_2]...[d_k] = -input[n][c][d_1][d_2]...[d_k] * weight[c].



        loss is zero for the case when target-value equals ignore_index.

        ::

            loss[n][d_1][d_2]...[d_k] = 0, when target[n][d_1][d_2]...[d_k] = ignore_index



        If "reduction" attribute is set to "none", the operator's output will be the above loss with shape (N, d1, d2, ..., dk).
        If "reduction" attribute is set to "mean" (the default attribute value), the output loss is (weight) averaged:

        ::

            mean(loss), if "weight" is not provided,



        or if weight is provided,

        ::

            sum(loss) / sum(weight[target[n][d_1][d_2]...[d_k]]]), for all samples.



        If "reduction" attribute is set to "sum", the output is a scalar: `sum(loss)`.

        See also https://pytorch.org/docs/stable/nn.html#torch.nn.NLLLoss.

        Example 1:

        ::

            // negative log likelihood loss, "none" reduction
            N, C, d1 = 2, 3, 2
            input = [[[1.0, 2.0], [2.0, 2.0], [3.0, 2.0]],
                      [[0.0, 1.0], [2.0, 2.0], [1.0, 2]]]
            target = [[2, 1], [0, 2]]

            loss = np.zeros((N, d1))
            for n in range(N):
                for d_1 in range(d1):
                    c = target[n][d_1]
                    loss[n][d_1] = -input[n][c][d_1]

            // print(loss)
            // [[-3. -2.]
            //  [-0. -2.]]



        Example 2:

        ::

            // weighted negative log likelihood loss, sum reduction
            N, C, d1 = 2, 3, 2
            input = [[[1.0, 2.0], [2.0, 2.0], [3.0, 2.0]],
                    [[0.0, 1.0], [2.0, 2.0], [1.0, 2]]]
            target = [[2, 1], [0, 2]]
            weight = [0.2, 0.3, 0.1]
            loss = np.zeros((N, d1))
            for n in range(N):
                for d_1 in range(d1):
                    c = target[n][d_1]
                    loss[n][d_1] = -input[n][c][d_1] * weight[c]

            loss = np.sum(loss)
            // print(loss)
            // -1.1



        Example 3:

        ::

            // weighted negative log likelihood loss, mean reduction
            N, C, d1 = 2, 3, 2
            input = [[[1.0, 2.0], [2.0, 2.0], [3.0, 2.0]],
                    [[0.0, 1.0], [2.0, 2.0], [1.0, 2]]]
            target = [[2, 1], [0, 2]]
            weight = [0.2, 0.3, 0.1]
            loss = np.zeros((N, d1))
            weight_total = 0
            for n in range(N):
                for d_1 in range(d1):
                    c = target[n][d_1]
                    loss[n][d_1] = -input[n][c][d_1] * weight[c]
                    weight_total = weight_total + weight[c]

            loss = np.sum(loss) / weight_total
            // print(loss)
            // -1.57




        Args:
            input: (differentiable) Input tensor of shape (N, C) or (N, C, d1, d2, ...,
                dk).

            target: (non-differentiable) Target tensor of shape (N) or (N, d1, d2, ...,
                dk). Target element value shall be in range of [0, C). If ignore_index
                is specified, it may have a value outside [0, C) and the target values
                should either be in the range [0, C) or have the value ignore_index.

            weight: (optional, non-differentiable) Optional rescaling weight tensor. If
                given, it has to be a tensor of size C. Otherwise, it is treated as if
                having all ones.

            ignore_index: Specifies a target value that is ignored and does not
                contribute to the input gradient. It's an optional value.

            reduction: Type of reduction to apply to loss: none, sum, mean (default).
                'none': the output is the loss for each sample. 'sum': the output will
                be summed. 'mean': the sum of the output will be divided by the sum of
                applied weights.
        """

        schema = get_schema("NegativeLogLikelihoodLoss", 13, "")
        op = Op(self, "NegativeLogLikelihoodLoss", schema)
        return op(
            *self._prepare_inputs(schema, input, target, weight),
            ignore_index=ignore_index,
            reduction=reduction,
        )

    T_NonZero = TypeVar(
        "T_NonZero",
        BFLOAT16,
        BOOL,
        COMPLEX128,
        COMPLEX64,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        STRING,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    def NonZero(self, X: T_NonZero) -> INT64:
        r"""[🌐 NonZero(13)](https://onnx.ai/onnx/operators/onnx__NonZero.html#nonzero-13 "Online Documentation")


            Returns the indices of the elements that are non-zero
            (in row-major order - by dimension).
            NonZero behaves similar to numpy.nonzero:
            https://docs.scipy.org/doc/numpy/reference/generated/numpy.nonzero.html,
            but for scalar input, NonZero produces output shape (0, N) instead of (1, N), which is different from Numpy's behavior.


        Args:
            X: (non-differentiable) input
        """

        schema = get_schema("NonZero", 13, "")
        op = Op(self, "NonZero", schema)
        return op(*self._prepare_inputs(schema, X))

    T_Pad = TypeVar(
        "T_Pad",
        BFLOAT16,
        BOOL,
        COMPLEX128,
        COMPLEX64,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        STRING,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    def Pad(
        self,
        data: T_Pad,
        pads: INT64,
        constant_value: Optional[T_Pad] = None,
        *,
        mode: str = "constant",
    ) -> T_Pad:
        r"""[🌐 Pad(13)](https://onnx.ai/onnx/operators/onnx__Pad.html#pad-13 "Online Documentation")


        Given a tensor containing the data to be padded (`data`), a tensor containing the number of start and end pad values for axis (`pads`), (optionally) a `mode`, and (optionally) `constant_value`,
        a padded tensor (`output`) is generated.

        The three supported `modes` are (similar to corresponding modes supported by `numpy.pad`):

        1) `constant`(default) - pads with a given constant value as specified by `constant_value` (which defaults to 0, empty string, or False)

        2) `reflect` - pads with the reflection of the vector mirrored on the first and last values of the vector along each axis

        3) `edge` - pads with the edge values of array


        Example 1 (`constant` mode):
          Insert 0 pads to the beginning of the second dimension.

          data =
          [
              [1.0, 1.2],
              [2.3, 3.4],
              [4.5, 5.7],
          ]

          pads = [0, 2, 0, 0]

          mode = 'constant'

          constant_value = 0.0

          output =
          [
              [0.0, 0.0, 1.0, 1.2],
              [0.0, 0.0, 2.3, 3.4],
              [0.0, 0.0, 4.5, 5.7],
          ]


        Example 2 (`reflect` mode):
          data =
          [
              [1.0, 1.2],
              [2.3, 3.4],
              [4.5, 5.7],
          ]

          pads = [0, 2, 0, 0]

          mode = 'reflect'

          output =
          [
              [1.0, 1.2, 1.0, 1.2],
              [2.3, 3.4, 2.3, 3.4],
              [4.5, 5.7, 4.5, 5.7],
          ]


        Example 3 (`edge` mode):
          data =
          [
              [1.0, 1.2],
              [2.3, 3.4],
              [4.5, 5.7],
          ]

          pads = [0, 2, 0, 0]

          mode = 'edge'

          output =
          [
              [1.0, 1.0, 1.0, 1.2],
              [2.3, 2.3, 2.3, 3.4],
              [4.5, 4.5, 4.5, 5.7],
          ]



        Args:
            data: (differentiable) Input tensor.

            pads: (non-differentiable) Tensor of integers indicating the number of
                padding elements to add or remove (if negative) at the beginning and end
                of each axis. For 2D input tensor, it is the number of pixels. `pads`
                should be a 1D tensor of shape [2 * input_rank]. `pads` format should
                be: [x1_begin, x2_begin,...,x1_end, x2_end,...], where xi_begin is the
                number of pad values added at the beginning of axis `i` and xi_end, the
                number of pad values added at the end of axis `i`.

            constant_value: (optional, non-differentiable) (Optional) A scalar value to
                be used if the mode chosen is `constant` (by default it is 0, empty
                string or False).

            mode: Supported modes: `constant`(default), `reflect`, `edge`
        """

        schema = get_schema("Pad", 13, "")
        op = Op(self, "Pad", schema)
        return op(*self._prepare_inputs(schema, data, pads, constant_value), mode=mode)

    T_Pow = TypeVar("T_Pow", BFLOAT16, DOUBLE, FLOAT, FLOAT16, INT32, INT64)

    T1_Pow = TypeVar(
        "T1_Pow",
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    def Pow(self, X: T_Pow, Y: T1_Pow) -> T_Pow:
        r"""[🌐 Pow(13)](https://onnx.ai/onnx/operators/onnx__Pow.html#pow-13 "Online Documentation")


        Pow takes input data (Tensor<T>) and exponent Tensor, and
        produces one output data (Tensor<T>) where the function `f(x) = x^exponent`,
        is applied to the data tensor elementwise.
        This operator supports **multidirectional (i.e., Numpy-style) broadcasting**; for more details please check `Broadcasting in ONNX <https://github.com/onnx/onnx/blob/master/docs/Broadcasting.md>`_.

        Args:
            X: (differentiable) First operand, base of the exponent.

            Y: (differentiable) Second operand, power of the exponent.
        """

        schema = get_schema("Pow", 13, "")
        op = Op(self, "Pow", schema)
        return op(*self._prepare_inputs(schema, X, Y))

    T1_QuantizeLinear = TypeVar("T1_QuantizeLinear", FLOAT, INT32)

    T2_QuantizeLinear = TypeVar("T2_QuantizeLinear", INT8, UINT8)

    def QuantizeLinear(
        self,
        x: T1_QuantizeLinear,
        y_scale: FLOAT,
        y_zero_point: Optional[T2_QuantizeLinear] = None,
        *,
        axis: int = 1,
    ) -> T2_QuantizeLinear:
        r"""[🌐 QuantizeLinear(13)](https://onnx.ai/onnx/operators/onnx__QuantizeLinear.html#quantizelinear-13 "Online Documentation")


        The linear quantization operator. It consumes a high precision tensor, a scale, and a zero point to compute the low precision / quantized tensor.
        The scale factor and zero point must have same shape, and can be either a scalar for per-tensor / per layer quantization, or a 1-D tensor for per-axis quantization.
        The quantization formula is y = saturate ((x / y_scale) + y_zero_point).
        For saturation, it saturates to [0, 255] if it's uint8, or [-128, 127] if it's int8.
        For (x / y_scale), it's rounding to the nearest even. Refer to https://en.wikipedia.org/wiki/Rounding for details. 'y_zero_point' and 'y' must have same type.


        Args:
            x: N-D full precision Input tensor to be quantized.

            y_scale: Scale for doing quantization to get 'y'. It can be a scalar, which
                means per-tensor/layer quantization, or a 1-D Tensor for per-axis
                quantization.

            y_zero_point: (optional) Zero point for doing quantization to get 'y'. Shape
                must match y_scale. Default is uint8 with zero point of 0 if it's not
                specified.

            axis: (Optional) The axis of the quantization dimension of the input tensor.
                Ignored for per-tensor quantization. Negative value means counting
                dimensions from the back. Accepted range is [-r, r-1] where r =
                rank(input).
        """

        schema = get_schema("QuantizeLinear", 13, "")
        op = Op(self, "QuantizeLinear", schema)
        return op(*self._prepare_inputs(schema, x, y_scale, y_zero_point), axis=axis)

    T_Reciprocal = TypeVar("T_Reciprocal", BFLOAT16, DOUBLE, FLOAT, FLOAT16)

    def Reciprocal(self, X: T_Reciprocal) -> T_Reciprocal:
        r"""[🌐 Reciprocal(13)](https://onnx.ai/onnx/operators/onnx__Reciprocal.html#reciprocal-13 "Online Documentation")


        Reciprocal takes one input data (Tensor<T>) and produces one output data
        (Tensor<T>) where the reciprocal is, y = 1/x, is applied to
        the tensor elementwise.


        Args:
            X: (differentiable) Input tensor
        """

        schema = get_schema("Reciprocal", 13, "")
        op = Op(self, "Reciprocal", schema)
        return op(*self._prepare_inputs(schema, X))

    T_ReduceL1 = TypeVar(
        "T_ReduceL1", BFLOAT16, DOUBLE, FLOAT, FLOAT16, INT32, INT64, UINT32, UINT64
    )

    def ReduceL1(
        self,
        data: T_ReduceL1,
        *,
        axes: Optional[Sequence[int]] = None,
        keepdims: int = 1,
    ) -> T_ReduceL1:
        r"""[🌐 ReduceL1(13)](https://onnx.ai/onnx/operators/onnx__ReduceL1.html#reducel1-13 "Online Documentation")


        Computes the L1 norm of the input tensor's elements along the provided axes. The resulting
        tensor has the same rank as the input if `keepdims` equals 1. If `keepdims` equals 0, then
        the resulting tensor has the reduced dimension pruned. Input tensors of rank zero are
        valid. Reduction over an empty set of values yields 0.


        The above behavior is similar to numpy, with the exception that numpy defaults `keepdims`
        to `False` instead of `True`.

        Args:
            data: (differentiable) An input tensor.

            axes: A list of integers, along which to reduce. The default is to reduce
                over all the dimensions of the input tensor. Accepted range is [-r, r-1]
                where r = rank(data).

            keepdims: Keep the reduced dimension or not, default 1 means keep reduced
                dimension.
        """

        schema = get_schema("ReduceL1", 13, "")
        op = Op(self, "ReduceL1", schema)
        return op(*self._prepare_inputs(schema, data), axes=axes, keepdims=keepdims)

    T_ReduceL2 = TypeVar(
        "T_ReduceL2", BFLOAT16, DOUBLE, FLOAT, FLOAT16, INT32, INT64, UINT32, UINT64
    )

    def ReduceL2(
        self,
        data: T_ReduceL2,
        *,
        axes: Optional[Sequence[int]] = None,
        keepdims: int = 1,
    ) -> T_ReduceL2:
        r"""[🌐 ReduceL2(13)](https://onnx.ai/onnx/operators/onnx__ReduceL2.html#reducel2-13 "Online Documentation")


        Computes the L2 norm of the input tensor's elements along the provided axes. The resulting
        tensor has the same rank as the input if `keepdims` equals 1. If `keepdims` equals 0, then
        the resulting tensor has the reduced dimension pruned. Input tensors of rank zero are
        valid. Reduction over an empty set of values yields 0.


        The above behavior is similar to numpy, with the exception that numpy defaults `keepdims`
        to `False` instead of `True`.

        Args:
            data: (differentiable) An input tensor.

            axes: A list of integers, along which to reduce. The default is to reduce
                over all the dimensions of the input tensor. Accepted range is [-r, r-1]
                where r = rank(data).

            keepdims: Keep the reduced dimension or not, default 1 means keep reduced
                dimension.
        """

        schema = get_schema("ReduceL2", 13, "")
        op = Op(self, "ReduceL2", schema)
        return op(*self._prepare_inputs(schema, data), axes=axes, keepdims=keepdims)

    T_ReduceLogSum = TypeVar(
        "T_ReduceLogSum", BFLOAT16, DOUBLE, FLOAT, FLOAT16, INT32, INT64, UINT32, UINT64
    )

    def ReduceLogSum(
        self,
        data: T_ReduceLogSum,
        *,
        axes: Optional[Sequence[int]] = None,
        keepdims: int = 1,
    ) -> T_ReduceLogSum:
        r"""[🌐 ReduceLogSum(13)](https://onnx.ai/onnx/operators/onnx__ReduceLogSum.html#reducelogsum-13 "Online Documentation")


        Computes the log sum of the input tensor's elements along the provided axes. The resulting
        tensor has the same rank as the input if `keepdims` equals 1. If `keepdims` equals 0, then
        the resulting tensor has the reduced dimension pruned. Input tensors of rank zero are
        valid. Reduction over an empty set of values yields minus infinity (if supported by the datatype) or undefined otherwise.


        The above behavior is similar to numpy, with the exception that numpy defaults `keepdims`
        to `False` instead of `True`.

        Args:
            data: (differentiable) An input tensor.

            axes: A list of integers, along which to reduce. The default is to reduce
                over all the dimensions of the input tensor. Accepted range is [-r, r-1]
                where r = rank(data).

            keepdims: Keep the reduced dimension or not, default 1 means keep reduced
                dimension.
        """

        schema = get_schema("ReduceLogSum", 13, "")
        op = Op(self, "ReduceLogSum", schema)
        return op(*self._prepare_inputs(schema, data), axes=axes, keepdims=keepdims)

    T_ReduceLogSumExp = TypeVar(
        "T_ReduceLogSumExp",
        BFLOAT16,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT32,
        INT64,
        UINT32,
        UINT64,
    )

    def ReduceLogSumExp(
        self,
        data: T_ReduceLogSumExp,
        *,
        axes: Optional[Sequence[int]] = None,
        keepdims: int = 1,
    ) -> T_ReduceLogSumExp:
        r"""[🌐 ReduceLogSumExp(13)](https://onnx.ai/onnx/operators/onnx__ReduceLogSumExp.html#reducelogsumexp-13 "Online Documentation")


        Computes the log sum exponent of the input tensor's elements along the provided axes. The resulting
        tensor has the same rank as the input if `keepdims` equals 1. If `keepdims` equals 0, then
        the resulting tensor has the reduced dimension pruned. Input tensors of rank zero are
        valid. Reduction over an empty set of values yields minus infinity (if supported by the datatype) or undefined otherwise.


        The above behavior is similar to numpy, with the exception that numpy defaults `keepdims`
        to `False` instead of `True`.

        Args:
            data: (differentiable) An input tensor.

            axes: A list of integers, along which to reduce. The default is to reduce
                over all the dimensions of the input tensor. Accepted range is [-r, r-1]
                where r = rank(data).

            keepdims: Keep the reduced dimension or not, default 1 means keep reduced
                dimension.
        """

        schema = get_schema("ReduceLogSumExp", 13, "")
        op = Op(self, "ReduceLogSumExp", schema)
        return op(*self._prepare_inputs(schema, data), axes=axes, keepdims=keepdims)

    T_ReduceMax = TypeVar(
        "T_ReduceMax",
        BFLOAT16,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT32,
        INT64,
        INT8,
        UINT32,
        UINT64,
        UINT8,
    )

    def ReduceMax(
        self,
        data: T_ReduceMax,
        *,
        axes: Optional[Sequence[int]] = None,
        keepdims: int = 1,
    ) -> T_ReduceMax:
        r"""[🌐 ReduceMax(13)](https://onnx.ai/onnx/operators/onnx__ReduceMax.html#reducemax-13 "Online Documentation")


        Computes the max of the input tensor's elements along the provided axes. The resulting
        tensor has the same rank as the input if `keepdims` equals 1. If `keepdims` equals 0, then
        the resulting tensor has the reduced dimension pruned. Input tensors of rank zero are
        valid. Reduction over an empty set of values yields minus infinity (if supported by the datatype) or the minimum value of the data type otherwise.


        The above behavior is similar to numpy, with the exception that numpy defaults `keepdims`
        to `False` instead of `True`.

        Args:
            data: (differentiable) An input tensor.

            axes: A list of integers, along which to reduce. The default is to reduce
                over all the dimensions of the input tensor. Accepted range is [-r, r-1]
                where r = rank(data).

            keepdims: Keep the reduced dimension or not, default 1 means keep reduced
                dimension.
        """

        schema = get_schema("ReduceMax", 13, "")
        op = Op(self, "ReduceMax", schema)
        return op(*self._prepare_inputs(schema, data), axes=axes, keepdims=keepdims)

    T_ReduceMean = TypeVar(
        "T_ReduceMean", BFLOAT16, DOUBLE, FLOAT, FLOAT16, INT32, INT64, UINT32, UINT64
    )

    def ReduceMean(
        self,
        data: T_ReduceMean,
        *,
        axes: Optional[Sequence[int]] = None,
        keepdims: int = 1,
    ) -> T_ReduceMean:
        r"""[🌐 ReduceMean(13)](https://onnx.ai/onnx/operators/onnx__ReduceMean.html#reducemean-13 "Online Documentation")


        Computes the mean of the input tensor's elements along the provided axes. The resulting
        tensor has the same rank as the input if `keepdims` equals 1. If `keepdims` equals 0, then
        the resulting tensor has the reduced dimension pruned. Input tensors of rank zero are
        valid. Reduction over an empty set of values yields undefined.


        The above behavior is similar to numpy, with the exception that numpy defaults `keepdims`
        to `False` instead of `True`.

        Args:
            data: (differentiable) An input tensor.

            axes: A list of integers, along which to reduce. The default is to reduce
                over all the dimensions of the input tensor. Accepted range is [-r, r-1]
                where r = rank(data).

            keepdims: Keep the reduced dimension or not, default 1 means keep reduced
                dimension.
        """

        schema = get_schema("ReduceMean", 13, "")
        op = Op(self, "ReduceMean", schema)
        return op(*self._prepare_inputs(schema, data), axes=axes, keepdims=keepdims)

    T_ReduceMin = TypeVar(
        "T_ReduceMin",
        BFLOAT16,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT32,
        INT64,
        INT8,
        UINT32,
        UINT64,
        UINT8,
    )

    def ReduceMin(
        self,
        data: T_ReduceMin,
        *,
        axes: Optional[Sequence[int]] = None,
        keepdims: int = 1,
    ) -> T_ReduceMin:
        r"""[🌐 ReduceMin(13)](https://onnx.ai/onnx/operators/onnx__ReduceMin.html#reducemin-13 "Online Documentation")


        Computes the min of the input tensor's elements along the provided axes. The resulting
        tensor has the same rank as the input if `keepdims` equals 1. If `keepdims` equals 0, then
        the resulting tensor has the reduced dimension pruned. Input tensors of rank zero are
        valid. Reduction over an empty set of values yields plus infinity (if supported by the datatype) or the maximum value of the data type otherwise.


        The above behavior is similar to numpy, with the exception that numpy defaults `keepdims`
        to `False` instead of `True`.

        Args:
            data: (differentiable) An input tensor.

            axes: A list of integers, along which to reduce. The default is to reduce
                over all the dimensions of the input tensor. Accepted range is [-r, r-1]
                where r = rank(data).

            keepdims: Keep the reduced dimension or not, default 1 means keep reduced
                dimension.
        """

        schema = get_schema("ReduceMin", 13, "")
        op = Op(self, "ReduceMin", schema)
        return op(*self._prepare_inputs(schema, data), axes=axes, keepdims=keepdims)

    T_ReduceProd = TypeVar(
        "T_ReduceProd", BFLOAT16, DOUBLE, FLOAT, FLOAT16, INT32, INT64, UINT32, UINT64
    )

    def ReduceProd(
        self,
        data: T_ReduceProd,
        *,
        axes: Optional[Sequence[int]] = None,
        keepdims: int = 1,
    ) -> T_ReduceProd:
        r"""[🌐 ReduceProd(13)](https://onnx.ai/onnx/operators/onnx__ReduceProd.html#reduceprod-13 "Online Documentation")


        Computes the product of the input tensor's elements along the provided axes. The resulting
        tensor has the same rank as the input if `keepdims` equals 1. If `keepdims` equals 0, then
        the resulting tensor has the reduced dimension pruned. Input tensors of rank zero are
        valid. Reduction over an empty set of values yields 1.


        The above behavior is similar to numpy, with the exception that numpy defaults `keepdims`
        to `False` instead of `True`.

        Args:
            data: (differentiable) An input tensor.

            axes: A list of integers, along which to reduce. The default is to reduce
                over all the dimensions of the input tensor. Accepted range is [-r, r-1]
                where r = rank(data).

            keepdims: Keep the reduced dimension or not, default 1 means keep reduced
                dimension.
        """

        schema = get_schema("ReduceProd", 13, "")
        op = Op(self, "ReduceProd", schema)
        return op(*self._prepare_inputs(schema, data), axes=axes, keepdims=keepdims)

    T_ReduceSum = TypeVar(
        "T_ReduceSum", BFLOAT16, DOUBLE, FLOAT, FLOAT16, INT32, INT64, UINT32, UINT64
    )

    def ReduceSum(
        self,
        data: T_ReduceSum,
        axes: Optional[INT64] = None,
        *,
        keepdims: int = 1,
        noop_with_empty_axes: int = 0,
    ) -> T_ReduceSum:
        r"""[🌐 ReduceSum(13)](https://onnx.ai/onnx/operators/onnx__ReduceSum.html#reducesum-13 "Online Documentation")


        Computes the sum of the input tensor's elements along the provided axes. The resulting
        tensor has the same rank as the input if `keepdims` equals 1. If `keepdims` equals 0, then
        the resulting tensor has the reduced dimension pruned. Input tensors of rank zero are
        valid. Reduction over an empty set of values yields 0.


        The above behavior is similar to numpy, with the exception that numpy defaults `keepdims`
        to `False` instead of `True`.

        Args:
            data: (differentiable) An input tensor.

            axes: (optional, non-differentiable) Optional input list of integers, along
                which to reduce. The default is to reduce over empty axes. When axes is
                empty (either not provided or explicitly empty), behavior depends on
                'noop_with_empty_axes': reduction over all axes if
                'noop_with_empty_axes' is false, or no reduction is applied if
                'noop_with_empty_axes' is true (but other operations will be performed).
                Accepted range is [-r, r-1] where r = rank(data).

            keepdims: Keep the reduced dimension or not, default 1 means keep reduced
                dimension.

            noop_with_empty_axes: Defines behavior when axes is not provided or is
                empty. If false (default), reduction happens over all axes. If true, no
                reduction is applied, but other operations will be performed. For
                example, ReduceSumSquare acts as a vanilla Square.
        """

        schema = get_schema("ReduceSum", 13, "")
        op = Op(self, "ReduceSum", schema)
        return op(
            *self._prepare_inputs(schema, data, axes),
            keepdims=keepdims,
            noop_with_empty_axes=noop_with_empty_axes,
        )

    T_ReduceSumSquare = TypeVar(
        "T_ReduceSumSquare",
        BFLOAT16,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT32,
        INT64,
        UINT32,
        UINT64,
    )

    def ReduceSumSquare(
        self,
        data: T_ReduceSumSquare,
        *,
        axes: Optional[Sequence[int]] = None,
        keepdims: int = 1,
    ) -> T_ReduceSumSquare:
        r"""[🌐 ReduceSumSquare(13)](https://onnx.ai/onnx/operators/onnx__ReduceSumSquare.html#reducesumsquare-13 "Online Documentation")


        Computes the sum square of the input tensor's elements along the provided axes. The resulting
        tensor has the same rank as the input if `keepdims` equals 1. If `keepdims` equals 0, then
        the resulting tensor has the reduced dimension pruned. Input tensors of rank zero are
        valid. Reduction over an empty set of values yields 0.


        The above behavior is similar to numpy, with the exception that numpy defaults `keepdims`
        to `False` instead of `True`.

        Args:
            data: (differentiable) An input tensor.

            axes: A list of integers, along which to reduce. The default is to reduce
                over all the dimensions of the input tensor. Accepted range is [-r, r-1]
                where r = rank(data).

            keepdims: Keep the reduced dimension or not, default 1 means keep reduced
                dimension.
        """

        schema = get_schema("ReduceSumSquare", 13, "")
        op = Op(self, "ReduceSumSquare", schema)
        return op(*self._prepare_inputs(schema, data), axes=axes, keepdims=keepdims)

    T_Relu = TypeVar("T_Relu", BFLOAT16, DOUBLE, FLOAT, FLOAT16)

    def Relu(self, X: T_Relu) -> T_Relu:
        r"""[🌐 Relu(13)](https://onnx.ai/onnx/operators/onnx__Relu.html#relu-13 "Online Documentation")


        Relu takes one input data (Tensor<T>) and produces one output data
        (Tensor<T>) where the rectified linear function, y = max(0, x), is applied to
        the tensor elementwise.


        Args:
            X: (differentiable) Input tensor
        """

        schema = get_schema("Relu", 13, "")
        op = Op(self, "Relu", schema)
        return op(*self._prepare_inputs(schema, X))

    T_Reshape = TypeVar(
        "T_Reshape",
        BFLOAT16,
        BOOL,
        COMPLEX128,
        COMPLEX64,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        STRING,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    def Reshape(self, data: T_Reshape, shape: INT64) -> T_Reshape:
        r"""[🌐 Reshape(13)](https://onnx.ai/onnx/operators/onnx__Reshape.html#reshape-13 "Online Documentation")


        Reshape the input tensor similar to numpy.reshape.
        First input is the data tensor, second input is a shape tensor which specifies the output shape. It outputs the reshaped tensor.
        At most one dimension of the new shape can be -1. In this case, the value is
        inferred from the size of the tensor and the remaining dimensions. A dimension
        could also be 0, in which case the actual dimension value is unchanged (i.e. taken
        from the input tensor). Shape (second input) could be an empty shape, which means converting to a scalar.
        The input tensor's shape and the output tensor's shape are required to have the same number of elements.

        Args:
            data: (differentiable) An input tensor.

            shape: (non-differentiable) Specified shape for output.
        """

        schema = get_schema("Reshape", 13, "")
        op = Op(self, "Reshape", schema)
        return op(*self._prepare_inputs(schema, data, shape))

    T1_Resize = TypeVar(
        "T1_Resize",
        BFLOAT16,
        BOOL,
        COMPLEX128,
        COMPLEX64,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        STRING,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    T2_Resize = TypeVar("T2_Resize", DOUBLE, FLOAT, FLOAT16)

    def Resize(
        self,
        X: T1_Resize,
        roi: Optional[T2_Resize] = None,
        scales: Optional[FLOAT] = None,
        sizes: Optional[INT64] = None,
        *,
        coordinate_transformation_mode: str = "half_pixel",
        cubic_coeff_a: float = -0.75,
        exclude_outside: int = 0,
        extrapolation_value: float = 0.0,
        mode: str = "nearest",
        nearest_mode: str = "round_prefer_floor",
    ) -> T1_Resize:
        r"""[🌐 Resize(13)](https://onnx.ai/onnx/operators/onnx__Resize.html#resize-13 "Online Documentation")


        Resize the input tensor. In general, it calculates every value in the output tensor as a weighted average of neighborhood (a.k.a. sampling locations) in the input tensor.
        Each dimension value of the output tensor is:
          output_dimension = floor(input_dimension * (roi_end - roi_start) * scale) if input \"sizes\" is not specified.


        Args:
            X: (differentiable) N-D tensor

            roi: (optional, non-differentiable) 1-D tensor given as [start1, ...,
                startN, end1, ..., endN], where N is the rank of X. The RoIs'
                coordinates are normalized in the coordinate system of the input image.
                It only takes effect when coordinate_transformation_mode is
                "tf_crop_and_resize"

            scales: (optional, non-differentiable) The scale array along each dimension.
                It takes value greater than 0. If it's less than 1, it's sampling down,
                otherwise, it's upsampling. The number of elements of 'scales' should be
                the same as the rank of input 'X'. One of 'scales' and 'sizes' MUST be
                specified and it is an error if both are specified. If 'sizes' is
                needed, the user can use an empty string as the name of 'scales' in this
                operator's input list.

            sizes: (optional, non-differentiable) The size of the output tensor. The
                number of elements of 'sizes' should be the same as the rank of input
                'X'. Only one of 'scales' and 'sizes' can be specified.

            coordinate_transformation_mode:
        This attribute describes how to transform
                the coordinate in the resized tensor to the coordinate in the original
                tensor. <br/>

        The coordinate of each dimension is transformed
                individually. Let's describe a case using axis x as an example.
        Denote
                x_resized as the coordinate of axis x in the resized tensor, x_original
                as the coordinate of axis x in the original tensor, length_original as
                the length of the original tensor in axis x, length_resized as the
                length of the resized tensor in axis x, roi_x = (start_x, end_x) of the
                axis x in input "roi", scale = length_resized / length_original, <br/>
                if coordinate_transformation_mode is "half_pixel", <br/>
        x_original =
                (x_resized + 0.5) / scale - 0.5, <br/>

        if
                coordinate_transformation_mode is "pytorch_half_pixel", <br/>
        x_original
                = length_resized > 1 ? (x_resized + 0.5) / scale - 0.5 : 0, <br/>

        if
                coordinate_transformation_mode is "align_corners", <br/>
        x_original =
                x_resized * (length_original - 1) / (length_resized - 1), <br/>

        if
                coordinate_transformation_mode is "asymmetric", <br/>
        x_original =
                x_resized / scale, <br/>

        if coordinate_transformation_mode is
                "tf_crop_and_resize", <br/>
        x_original = length_resized > 1 ? start_x *
                (length_original - 1) + x_resized * (end_x - start_x) * (length_original
                - 1) / (length_resized - 1) : 0.5 * (start_x + end_x) * (length_original
                - 1).

            cubic_coeff_a: The coefficient 'a' used in cubic interpolation. Two common
                choice are -0.5 (in some cases of TensorFlow) and -0.75 (in PyTorch).
                Check out Equation (4) in https://ieeexplore.ieee.org/document/1163711
                for the details. This attribute is valid only if "mode" is "cubic".

            exclude_outside: If set to 1, the weight of sampling locations outside the
                tensor will be set to 0 and the weight will be renormalized so that
                their sum is 1.0. The default value is 0.

            extrapolation_value: When coordinate_transformation_mode is
                "tf_crop_and_resize" and x_original is outside the range [0,
                length_original - 1], this value is used as the corresponding output
                value. Default is 0.0f.

            mode: Three interpolation modes: nearest (default), linear and cubic. The
                "linear" mode includes linear interpolation for 1D tensor and N-linear
                interpolation for N-D tensor (for example, bilinear interpolation for 2D
                tensor). The "cubic" mode includes cubic interpolation for 1D tensor and
                N-cubic interpolation for N-D tensor (for example, bicubic interpolation
                for 2D tensor).

            nearest_mode: Four modes: round_prefer_floor (default, as known as round
                half down), round_prefer_ceil (as known as round half up), floor, ceil.
                Only used by nearest interpolation. It indicates how to get "nearest"
                pixel in input tensor from x_original, so this attribute is valid only
                if "mode" is "nearest".
        """

        schema = get_schema("Resize", 13, "")
        op = Op(self, "Resize", schema)
        return op(
            *self._prepare_inputs(schema, X, roi, scales, sizes),
            coordinate_transformation_mode=coordinate_transformation_mode,
            cubic_coeff_a=cubic_coeff_a,
            exclude_outside=exclude_outside,
            extrapolation_value=extrapolation_value,
            mode=mode,
            nearest_mode=nearest_mode,
        )

    T_ScatterElements = TypeVar(
        "T_ScatterElements",
        BFLOAT16,
        BOOL,
        COMPLEX128,
        COMPLEX64,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        STRING,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    Tind_ScatterElements = TypeVar("Tind_ScatterElements", INT32, INT64)

    def ScatterElements(
        self,
        data: T_ScatterElements,
        indices: Tind_ScatterElements,
        updates: T_ScatterElements,
        *,
        axis: int = 0,
    ) -> T_ScatterElements:
        r"""[🌐 ScatterElements(13)](https://onnx.ai/onnx/operators/onnx__ScatterElements.html#scatterelements-13 "Online Documentation")


        ScatterElements takes three inputs `data`, `updates`, and `indices` of the same
        rank r >= 1 and an optional attribute axis that identifies an axis of `data`
        (by default, the outer-most axis, that is axis 0). The output of the operation
        is produced by creating a copy of the input `data`, and then updating its value
        to values specified by `updates` at specific index positions specified by
        `indices`. Its output shape is the same as the shape of `data`.

        For each entry in `updates`, the target index in `data` is obtained by combining
        the corresponding entry in `indices` with the index of the entry itself: the
        index-value for dimension = axis is obtained from the value of the corresponding
        entry in `indices` and the index-value for dimension != axis is obtained from the
        index of the entry itself.

        For instance, in a 2-D tensor case, the update corresponding to the [i][j] entry
        is performed as below:
        ::

              output[indices[i][j]][j] = updates[i][j] if axis = 0,
              output[i][indices[i][j]] = updates[i][j] if axis = 1,



        This operator is the inverse of GatherElements. It is similar to Torch's Scatter operation.

        Example 1:
        ::

              data = [
                  [0.0, 0.0, 0.0],
                  [0.0, 0.0, 0.0],
                  [0.0, 0.0, 0.0],
              ]
              indices = [
                  [1, 0, 2],
                  [0, 2, 1],
              ]
              updates = [
                  [1.0, 1.1, 1.2],
                  [2.0, 2.1, 2.2],
              ]
              output = [
                  [2.0, 1.1, 0.0]
                  [1.0, 0.0, 2.2]
                  [0.0, 2.1, 1.2]
              ]


        Example 2:
        ::

              data = [[1.0, 2.0, 3.0, 4.0, 5.0]]
              indices = [[1, 3]]
              updates = [[1.1, 2.1]]
              axis = 1
              output = [[1.0, 1.1, 3.0, 2.1, 5.0]]




        Args:
            data: (differentiable) Tensor of rank r >= 1.

            indices: (non-differentiable) Tensor of int32/int64 indices, of r >= 1 (same
                rank as input). All index values are expected to be within bounds [-s,
                s-1] along axis of size s. It is an error if any of the index values are
                out of bounds.

            updates: (differentiable) Tensor of rank r >=1 (same rank and shape as
                indices)

            axis: Which axis to scatter on. Negative value means counting dimensions
                from the back. Accepted range is [-r, r-1] where r = rank(data).
        """

        schema = get_schema("ScatterElements", 13, "")
        op = Op(self, "ScatterElements", schema)
        return op(*self._prepare_inputs(schema, data, indices, updates), axis=axis)

    T_ScatterND = TypeVar(
        "T_ScatterND",
        BFLOAT16,
        BOOL,
        COMPLEX128,
        COMPLEX64,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        STRING,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    def ScatterND(
        self, data: T_ScatterND, indices: INT64, updates: T_ScatterND
    ) -> T_ScatterND:
        r"""[🌐 ScatterND(13)](https://onnx.ai/onnx/operators/onnx__ScatterND.html#scatternd-13 "Online Documentation")


        ScatterND takes three inputs `data` tensor of rank r >= 1, `indices` tensor of rank q >= 1,
        and `updates` tensor of rank q + r - indices.shape[-1] - 1. The output of the operation
        is produced by creating a copy of the input `data`, and then updating its value to values
        specified by `updates` at specific index positions specified by `indices`. Its output shape
        is the same as the shape of `data`. Note that `indices` should not have duplicate entries.
        That is, two or more `updates` for the same index-location is not supported.

        `indices` is an integer tensor. Let k denote indices.shape[-1], the last dimension in the shape of `indices`.
         `indices` is treated as a (q-1)-dimensional tensor of k-tuples, where each k-tuple is a partial-index into `data`.
        Hence, k can be a value at most the rank of `data`. When k equals rank(data), each update entry specifies an
        update to a single element of the tensor. When k is less than rank(data) each update entry specifies an
        update to a slice of the tensor. Index values are allowed to be negative, as per the usual
        convention for counting backwards from the end, but are expected in the valid range.

        `updates` is treated as a (q-1)-dimensional tensor of replacement-slice-values. Thus, the
        first (q-1) dimensions of updates.shape must match the first (q-1) dimensions of indices.shape.
        The remaining dimensions of `updates` correspond to the dimensions of the
        replacement-slice-values. Each replacement-slice-value is a (r-k) dimensional tensor,
        corresponding to the trailing (r-k) dimensions of `data`.  Thus, the shape of `updates`
        must equal indices.shape[0:q-1] ++ data.shape[k:r-1], where ++ denotes the concatenation
        of shapes.

        The `output` is calculated via the following equation:

            output = np.copy(data)
            update_indices = indices.shape[:-1]
            for idx in np.ndindex(update_indices):
                output[indices[idx]] = updates[idx]

        The order of iteration in the above loop is not specified.
        In particular, indices should not have duplicate entries: that is, if idx1 != idx2, then indices[idx1] != indices[idx2].
        This ensures that the output value does not depend on the iteration order.

        This operator is the inverse of GatherND.

        Example 1:
        ::

              data    = [1, 2, 3, 4, 5, 6, 7, 8]
              indices = [[4], [3], [1], [7]]
              updates = [9, 10, 11, 12]
              output  = [1, 11, 3, 10, 9, 6, 7, 12]



        Example 2:
        ::

              data    = [[[1, 2, 3, 4], [5, 6, 7, 8], [8, 7, 6, 5], [4, 3, 2, 1]],
                         [[1, 2, 3, 4], [5, 6, 7, 8], [8, 7, 6, 5], [4, 3, 2, 1]],
                         [[8, 7, 6, 5], [4, 3, 2, 1], [1, 2, 3, 4], [5, 6, 7, 8]],
                         [[8, 7, 6, 5], [4, 3, 2, 1], [1, 2, 3, 4], [5, 6, 7, 8]]]
              indices = [[0], [2]]
              updates = [[[5, 5, 5, 5], [6, 6, 6, 6], [7, 7, 7, 7], [8, 8, 8, 8]],
                         [[1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3], [4, 4, 4, 4]]]
              output  = [[[5, 5, 5, 5], [6, 6, 6, 6], [7, 7, 7, 7], [8, 8, 8, 8]],
                         [[1, 2, 3, 4], [5, 6, 7, 8], [8, 7, 6, 5], [4, 3, 2, 1]],
                         [[1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3], [4, 4, 4, 4]],
                         [[8, 7, 6, 5], [4, 3, 2, 1], [1, 2, 3, 4], [5, 6, 7, 8]]]




        Args:
            data: (differentiable) Tensor of rank r >= 1.

            indices: (non-differentiable) Tensor of rank q >= 1.

            updates: (differentiable) Tensor of rank q + r - indices_shape[-1] - 1.
        """

        schema = get_schema("ScatterND", 13, "")
        op = Op(self, "ScatterND", schema)
        return op(*self._prepare_inputs(schema, data, indices, updates))

    T_Shape = TypeVar(
        "T_Shape",
        BFLOAT16,
        BOOL,
        COMPLEX128,
        COMPLEX64,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        STRING,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    T1_Shape: TypeAlias = INT64

    def Shape(self, data: T_Shape) -> T1_Shape:
        r"""[🌐 Shape(13)](https://onnx.ai/onnx/operators/onnx__Shape.html#shape-13 "Online Documentation")


        Takes a tensor as input and outputs an 1D int64 tensor containing the shape of the input tensor.


        Args:
            data: (non-differentiable) An input tensor.
        """

        schema = get_schema("Shape", 13, "")
        op = Op(self, "Shape", schema)
        return op(*self._prepare_inputs(schema, data))

    T_Sigmoid = TypeVar("T_Sigmoid", BFLOAT16, DOUBLE, FLOAT, FLOAT16)

    def Sigmoid(self, X: T_Sigmoid) -> T_Sigmoid:
        r"""[🌐 Sigmoid(13)](https://onnx.ai/onnx/operators/onnx__Sigmoid.html#sigmoid-13 "Online Documentation")


        Sigmoid takes one input data (Tensor<T>) and produces one output data
        (Tensor<T>) where the sigmoid function, y = 1 / (1 + exp(-x)), is applied to the
        tensor elementwise.


        Args:
            X: (differentiable) Input tensor
        """

        schema = get_schema("Sigmoid", 13, "")
        op = Op(self, "Sigmoid", schema)
        return op(*self._prepare_inputs(schema, X))

    T_Sign = TypeVar(
        "T_Sign",
        BFLOAT16,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    def Sign(self, input: T_Sign) -> T_Sign:
        r"""[🌐 Sign(13)](https://onnx.ai/onnx/operators/onnx__Sign.html#sign-13 "Online Documentation")


        Calculate the sign of the given input tensor element-wise.
        If input > 0, output 1. if input < 0, output -1. if input == 0, output 0.


        Args:
            input: (non-differentiable) Input tensor
        """

        schema = get_schema("Sign", 13, "")
        op = Op(self, "Sign", schema)
        return op(*self._prepare_inputs(schema, input))

    T_Size = TypeVar(
        "T_Size",
        BFLOAT16,
        BOOL,
        COMPLEX128,
        COMPLEX64,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        STRING,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    T1_Size: TypeAlias = INT64

    def Size(self, data: T_Size) -> T1_Size:
        r"""[🌐 Size(13)](https://onnx.ai/onnx/operators/onnx__Size.html#size-13 "Online Documentation")


        Takes a tensor as input and outputs a int64 scalar that equals to the total number of elements of the input tensor.


        Args:
            data: (non-differentiable) An input tensor.
        """

        schema = get_schema("Size", 13, "")
        op = Op(self, "Size", schema)
        return op(*self._prepare_inputs(schema, data))

    T_Slice = TypeVar(
        "T_Slice",
        BFLOAT16,
        BOOL,
        COMPLEX128,
        COMPLEX64,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        STRING,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    Tind_Slice = TypeVar("Tind_Slice", INT32, INT64)

    def Slice(
        self,
        data: T_Slice,
        starts: Tind_Slice,
        ends: Tind_Slice,
        axes: Optional[Tind_Slice] = None,
        steps: Optional[Tind_Slice] = None,
    ) -> T_Slice:
        r"""[🌐 Slice(13)](https://onnx.ai/onnx/operators/onnx__Slice.html#slice-13 "Online Documentation")


        Produces a slice of the input tensor along multiple axes. Similar to numpy:
        https://numpy.org/doc/stable/user/basics.indexing.html?highlight=slice#slicing-and-striding

        Slice uses the `starts`, `ends`, `axes` and `steps` inputs to select a sub-tensor
        of its input `data` tensor.

        An effective `starts[i]`, `ends[i]`, and `steps[i]` must be computed for each `i`
        in `[0, ... r-1]` where `r = rank(input)` as follows:

        If `axes` are omitted, they are set to `[0, ..., r-1]`.
        If `steps` are omitted, they are set to `[1, ..., 1]` of length `len(starts)`

        The effective values are initialized as `start[i] = 0`, `ends[i] = dims[i]` where
        `dims` are the dimensions of `input` and `steps[i] = 1`.

        All negative elements of `axes` are made non-negative by adding `r` to them, where
        `r =rank(input)`.

        All negative values in `starts[i]` and `ends[i]` have `dims[axes[i]]` added to them,
        where `dims` are the dimensions of `input`. Then `start[axes[i]]` is the adjusted
        `starts[i]` is clamped into the range `[0, dims[axes[i]]]` for positive stepping
        and `[0, dims[axes[i]]-1]` for negative stepping.

        The clamping for the adjusted `ends[i]` depends on the sign of `steps[i]` and must
        accommodate copying 0 through `dims[axes[i]]` elements, so for positive stepping
        `ends[axes[i]]` is clamped to `[0, dims[axes[i]]]`, while for negative stepping it
        is clamped to `[-1, dims[axes[i]]-1]`.

        Finally, `steps[axes[i]] = steps[i]`.

        For slicing to the end of a dimension with unknown size, it is recommended to pass
        in `INT_MAX` when slicing forward and 'INT_MIN' when slicing backward.

        Example 1:

        ::

            data = [
                [1, 2, 3, 4],
                [5, 6, 7, 8],
            ]
            axes = [0, 1]
            starts = [1, 0]
            ends = [2, 3]
            steps = [1, 2]
            result = [
                [5, 7],
            ]



        Example 2:

        ::

            data = [
                [1, 2, 3, 4],
                [5, 6, 7, 8],
            ]
            starts = [0, 1]
            ends = [-1, 1000]
            result = [
                [2, 3, 4],
            ]




        Args:
            data: (differentiable) Tensor of data to extract slices from.

            starts: (non-differentiable) 1-D tensor of starting indices of corresponding
                axis in `axes`

            ends: (non-differentiable) 1-D tensor of ending indices (exclusive) of
                corresponding axis in `axes`

            axes: (optional, non-differentiable) 1-D tensor of axes that `starts` and
                `ends` apply to. Negative value means counting dimensions from the back.
                Accepted range is [-r, r-1] where r = rank(data). Behavior is undefined
                if an axis is repeated.

            steps: (optional, non-differentiable) 1-D tensor of slice step of
                corresponding axis in `axes`. Negative value means slicing backward.
                'steps' cannot be 0. Defaults to 1s.
        """

        schema = get_schema("Slice", 13, "")
        op = Op(self, "Slice", schema)
        return op(*self._prepare_inputs(schema, data, starts, ends, axes, steps))

    T_Softmax = TypeVar("T_Softmax", BFLOAT16, DOUBLE, FLOAT, FLOAT16)

    def Softmax(self, input: T_Softmax, *, axis: int = -1) -> T_Softmax:
        r"""[🌐 Softmax(13)](https://onnx.ai/onnx/operators/onnx__Softmax.html#softmax-13 "Online Documentation")


        The operator computes the normalized exponential values for the given input:

         Softmax(input, axis) = Exp(input) / ReduceSum(Exp(input), axis=axis, keepdims=1)

        The "axis" attribute indicates the dimension along which Softmax
        will be performed. The output tensor has the same shape
        and contains the Softmax values of the corresponding input.


        Args:
            input: (differentiable) The input tensor of rank >= axis.

            axis:
        Describes the dimension Softmax will be performed on.
        Negative value
                means counting dimensions
        from the back. Accepted range is [-r, r-1]
                where r = rank(input).
        """

        schema = get_schema("Softmax", 13, "")
        op = Op(self, "Softmax", schema)
        return op(*self._prepare_inputs(schema, input), axis=axis)

    T_SoftmaxCrossEntropyLoss = TypeVar(
        "T_SoftmaxCrossEntropyLoss", BFLOAT16, DOUBLE, FLOAT, FLOAT16
    )

    Tind_SoftmaxCrossEntropyLoss = TypeVar("Tind_SoftmaxCrossEntropyLoss", INT32, INT64)

    def SoftmaxCrossEntropyLoss(
        self,
        scores: T_SoftmaxCrossEntropyLoss,
        labels: Tind_SoftmaxCrossEntropyLoss,
        weights: Optional[T_SoftmaxCrossEntropyLoss] = None,
        *,
        ignore_index: Optional[int] = None,
        reduction: str = "mean",
    ) -> Tuple[T_SoftmaxCrossEntropyLoss, T_SoftmaxCrossEntropyLoss]:
        r"""[🌐 SoftmaxCrossEntropyLoss(13)](https://onnx.ai/onnx/operators/onnx__SoftmaxCrossEntropyLoss.html#softmaxcrossentropyloss-13 "Online Documentation")

        Loss function that measures the softmax cross entropy
        between 'scores' and 'labels'.
        This operator first computes a loss tensor whose shape is identical to the labels input.
        If the input is 2-D with shape (N, C), the loss tensor may be a N-element vector L = (l_1, l_2, ..., l_N).
        If the input is N-D tensor with shape (N, C, D1, D2, ..., Dk),
        the loss tensor L may have (N, D1, D2, ..., Dk) as its shape and L[i,][j_1][j_2]...[j_k] denotes a scalar element in L.
        After L is available, this operator can optionally do a reduction operator.

        * shape(scores): (N, C) where C is the number of classes, or (N, C, D1, D2,..., Dk),
          with K >= 1 in case of K-dimensional loss.
        * shape(labels): (N) where each value is 0 <= labels[i] <= C-1, or (N, D1, D2,..., Dk),
          with K >= 1 in case of K-dimensional loss.

        The loss for one sample, l_i, can calculated as follows:
        ::

            l[i][d1][d2]...[dk] = -y[i][c][d1][d2]..[dk], where i is the index of classes.


        or
        ::

            l[i][d1][d2]...[dk] = -y[i][c][d1][d2]..[dk] * weights[c], if 'weights' is provided.



        loss is zero for the case when label-value equals ignore_index.
        ::

            l[i][d1][d2]...[dk]  = 0, when labels[n][d1][d2]...[dk] = ignore_index



        where:
        ::

            p = Softmax(scores)
            y = Log(p)
            c = labels[i][d1][d2]...[dk]



        Finally, L is optionally reduced:

        * If reduction = 'none', the output is L with shape (N, D1, D2, ..., Dk).
        * If reduction = 'sum', the output is scalar: Sum(L).
        * If reduction = 'mean', the output is scalar: ReduceMean(L), or if weight is provided: `ReduceSum(L) / ReduceSum(W)`,
          where tensor W is of shape `(N, D1, D2, ..., Dk)` and `W[n][d1][d2]...[dk] = weights[labels[i][d1][d2]...[dk]]`.


        Args:
            scores: (differentiable) The predicted outputs with shape [batch_size,
                class_size], or [batch_size, class_size, D1, D2 , ..., Dk], where K is
                the number of dimensions.

            labels: (non-differentiable) The ground truth output tensor, with shape
                [batch_size], or [batch_size, D1, D2, ..., Dk], where K is the number of
                dimensions. Labels element value shall be in range of [0, C). If
                ignore_index is specified, it may have a value outside [0, C) and the
                label values should either be in the range [0, C) or have the value
                ignore_index.

            weights: (optional, non-differentiable) A manual rescaling weight given to
                each class. If given, it has to be a 1D Tensor assigning weight to each
                of the classes. Otherwise, it is treated as if having all ones.

            ignore_index: Specifies a target value that is ignored and does not
                contribute to the input gradient. It's an optional value.

            reduction: Type of reduction to apply to loss: none, sum, mean(default).
                'none': no reduction will be applied, 'sum': the output will be summed.
                'mean': the sum of the output will be divided by the number of elements
                in the output.
        """

        schema = get_schema("SoftmaxCrossEntropyLoss", 13, "")
        op = Op(self, "SoftmaxCrossEntropyLoss", schema)
        return op(
            *self._prepare_inputs(schema, scores, labels, weights),
            ignore_index=ignore_index,
            reduction=reduction,
        )

    T_SpaceToDepth = TypeVar(
        "T_SpaceToDepth",
        BFLOAT16,
        BOOL,
        COMPLEX128,
        COMPLEX64,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        STRING,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    def SpaceToDepth(self, input: T_SpaceToDepth, *, blocksize: int) -> T_SpaceToDepth:
        r"""[🌐 SpaceToDepth(13)](https://onnx.ai/onnx/operators/onnx__SpaceToDepth.html#spacetodepth-13 "Online Documentation")

        SpaceToDepth rearranges blocks of spatial data into depth. More specifically,
        this op outputs a copy of the input tensor where values from the height and width dimensions
        are moved to the depth dimension.


        Args:
            input: (differentiable) Input tensor of [N,C,H,W], where N is the batch
                axis, C is the channel or depth, H is the height and W is the width.

            blocksize: Blocks of [blocksize, blocksize] are moved.
        """

        schema = get_schema("SpaceToDepth", 13, "")
        op = Op(self, "SpaceToDepth", schema)
        return op(*self._prepare_inputs(schema, input), blocksize=blocksize)

    T_Split = TypeVar(
        "T_Split",
        BFLOAT16,
        BOOL,
        COMPLEX128,
        COMPLEX64,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        STRING,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    def Split(
        self, input: T_Split, split: Optional[INT64] = None, *, axis: int = 0
    ) -> T_Split:
        r"""[🌐 Split(13)](https://onnx.ai/onnx/operators/onnx__Split.html#split-13 "Online Documentation")

        Split a tensor into a list of tensors, along the specified
        'axis'. Lengths of the parts can be specified using input 'split'.
        Otherwise, the tensor is split to equal sized parts.


        Args:
            input: (differentiable) The tensor to split

            split: (optional, non-differentiable) Optional length of each output. Values
                should be >= 0.Sum of the values must be equal to the dim value at
                'axis' specified.

            axis: Which axis to split on. A negative value means counting dimensions
                from the back. Accepted range is [-rank, rank-1] where r = rank(input).
        """

        schema = get_schema("Split", 13, "")
        op = Op(self, "Split", schema)
        return op(*self._prepare_inputs(schema, input, split), axis=axis)

    T_Sqrt = TypeVar("T_Sqrt", BFLOAT16, DOUBLE, FLOAT, FLOAT16)

    def Sqrt(self, X: T_Sqrt) -> T_Sqrt:
        r"""[🌐 Sqrt(13)](https://onnx.ai/onnx/operators/onnx__Sqrt.html#sqrt-13 "Online Documentation")


        Square root takes one input data (Tensor<T>) and produces one output data
        (Tensor<T>) where the square root is, y = x^0.5, is applied to
        the tensor elementwise. If x is negative, then it will return NaN.


        Args:
            X: (differentiable) Input tensor
        """

        schema = get_schema("Sqrt", 13, "")
        op = Op(self, "Sqrt", schema)
        return op(*self._prepare_inputs(schema, X))

    T_Squeeze = TypeVar(
        "T_Squeeze",
        BFLOAT16,
        BOOL,
        COMPLEX128,
        COMPLEX64,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        STRING,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    def Squeeze(self, data: T_Squeeze, axes: Optional[INT64] = None) -> T_Squeeze:
        r"""[🌐 Squeeze(13)](https://onnx.ai/onnx/operators/onnx__Squeeze.html#squeeze-13 "Online Documentation")


        Remove single-dimensional entries from the shape of a tensor.
        Takes an input `axes` with a list of axes to squeeze.
        If `axes` is not provided, all the single dimensions will be removed from
        the shape. If an axis is selected with shape entry not equal to one, an error is raised.


        Args:
            data: (differentiable) Tensors with at least max(dims) dimensions.

            axes: (optional, non-differentiable) List of integers indicating the
                dimensions to squeeze. Negative value means counting dimensions from the
                back. Accepted range is [-r, r-1] where r = rank(data).
        """

        schema = get_schema("Squeeze", 13, "")
        op = Op(self, "Squeeze", schema)
        return op(*self._prepare_inputs(schema, data, axes))

    T_Sub = TypeVar("T_Sub", BFLOAT16, DOUBLE, FLOAT, FLOAT16, INT32, INT64, UINT32, UINT64)

    def Sub(self, A: T_Sub, B: T_Sub) -> T_Sub:
        r"""[🌐 Sub(13)](https://onnx.ai/onnx/operators/onnx__Sub.html#sub-13 "Online Documentation")


        Performs element-wise binary subtraction (with Numpy-style broadcasting support).

        This operator supports **multidirectional (i.e., Numpy-style) broadcasting**; for more details please check `Broadcasting in ONNX <https://github.com/onnx/onnx/blob/master/docs/Broadcasting.md>`_.


        Args:
            A: (differentiable) First operand.

            B: (differentiable) Second operand.
        """

        schema = get_schema("Sub", 13, "")
        op = Op(self, "Sub", schema)
        return op(*self._prepare_inputs(schema, A, B))

    T_Sum = TypeVar("T_Sum", BFLOAT16, DOUBLE, FLOAT, FLOAT16)

    def Sum(self, *data_0: T_Sum) -> T_Sum:
        r"""[🌐 Sum(13)](https://onnx.ai/onnx/operators/onnx__Sum.html#sum-13 "Online Documentation")


        Element-wise sum of each of the input tensors (with Numpy-style broadcasting support).
        All inputs and outputs must have the same data type.
        This operator supports **multidirectional (i.e., Numpy-style) broadcasting**; for more details please check `Broadcasting in ONNX <https://github.com/onnx/onnx/blob/master/docs/Broadcasting.md>`_.


        Args:
            data_0: (variadic, differentiable) List of tensors for sum.
        """

        schema = get_schema("Sum", 13, "")
        op = Op(self, "Sum", schema)
        return op(*self._prepare_inputs(schema, *data_0))

    T_Tanh = TypeVar("T_Tanh", BFLOAT16, DOUBLE, FLOAT, FLOAT16)

    def Tanh(self, input: T_Tanh) -> T_Tanh:
        r"""[🌐 Tanh(13)](https://onnx.ai/onnx/operators/onnx__Tanh.html#tanh-13 "Online Documentation")


        Calculates the hyperbolic tangent of the given input tensor element-wise.


        Args:
            input: (differentiable) Input tensor
        """

        schema = get_schema("Tanh", 13, "")
        op = Op(self, "Tanh", schema)
        return op(*self._prepare_inputs(schema, input))

    T_Tile = TypeVar(
        "T_Tile",
        BFLOAT16,
        BOOL,
        COMPLEX128,
        COMPLEX64,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        STRING,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    T1_Tile: TypeAlias = INT64

    def Tile(self, input: T_Tile, repeats: T1_Tile) -> T_Tile:
        r"""[🌐 Tile(13)](https://onnx.ai/onnx/operators/onnx__Tile.html#tile-13 "Online Documentation")

        Constructs a tensor by tiling a given tensor.
        This is the same as function `tile` in Numpy, but no broadcast.
        For example A = [[1, 2], [3, 4]], B = [1, 2], tile(A, B) = [[1, 2, 1, 2], [3, 4, 3, 4]]


        Args:
            input: (differentiable) Input tensor of any shape.

            repeats: (non-differentiable) 1D int64 tensor of the same length as input's
                dimension number, includes numbers of repeated copies along input's
                dimensions.
        """

        schema = get_schema("Tile", 13, "")
        op = Op(self, "Tile", schema)
        return op(*self._prepare_inputs(schema, input, repeats))

    T_Transpose = TypeVar(
        "T_Transpose",
        BFLOAT16,
        BOOL,
        COMPLEX128,
        COMPLEX64,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        STRING,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    def Transpose(
        self, data: T_Transpose, *, perm: Optional[Sequence[int]] = None
    ) -> T_Transpose:
        r"""[🌐 Transpose(13)](https://onnx.ai/onnx/operators/onnx__Transpose.html#transpose-13 "Online Documentation")


        Transpose the input tensor similar to numpy.transpose. For example, when
        perm=(1, 0, 2), given an input tensor of shape (1, 2, 3), the output shape
        will be (2, 1, 3).


        Args:
            data: (differentiable) An input tensor.

            perm: A list of integers. By default, reverse the dimensions, otherwise
                permute the axes according to the values given.
        """

        schema = get_schema("Transpose", 13, "")
        op = Op(self, "Transpose", schema)
        return op(*self._prepare_inputs(schema, data), perm=perm)

    T_Unsqueeze = TypeVar(
        "T_Unsqueeze",
        BFLOAT16,
        BOOL,
        COMPLEX128,
        COMPLEX64,
        DOUBLE,
        FLOAT,
        FLOAT16,
        INT16,
        INT32,
        INT64,
        INT8,
        STRING,
        UINT16,
        UINT32,
        UINT64,
        UINT8,
    )

    def Unsqueeze(self, data: T_Unsqueeze, axes: INT64) -> T_Unsqueeze:
        r"""[🌐 Unsqueeze(13)](https://onnx.ai/onnx/operators/onnx__Unsqueeze.html#unsqueeze-13 "Online Documentation")


        Insert single-dimensional entries to the shape of an input tensor (`data`).
        Takes one required input `axes` - which contains a list of dimension indices and this operator will insert a dimension of value `1` into the corresponding index of the output tensor (`expanded`).

        For example, given an input tensor (`data`) of shape [3, 4, 5], then
        Unsqueeze(data, axes=[0, 4]) outputs a tensor (`expanded`) containing same data as `data` but with shape [1, 3, 4, 5, 1].

        The input `axes` should not contain any duplicate entries. It is an error if it contains duplicates.
        The rank of the output tensor (`output_rank`) is the rank of the input tensor (`data`) plus the number of values in `axes`.
        Each value in `axes` should be within the (inclusive) range [-output_rank , output_rank - 1].
        The order of values in `axes` does not matter and can come in any order.


        Args:
            data: (differentiable) Original tensor

            axes: (non-differentiable) List of integers indicating the dimensions to be
                inserted. Negative value means counting dimensions from the back.
                Accepted range is [-r, r-1] where r = rank(expanded).
        """

        schema = get_schema("Unsqueeze", 13, "")
        op = Op(self, "Unsqueeze", schema)
        return op(*self._prepare_inputs(schema, data, axes))
