# --------------------------------------------------------------------------
# ⚠️ 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: E741, D402
# --------------------------------------------------------------------------

from __future__ import annotations

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

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

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


class Opset9(Opset8):
    def __new__(cls):
        return Opset.__new__(cls, "", 9)

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

    def Acosh(self, input: T_Acosh) -> T_Acosh:
        r"""[🌐 Acosh(9)](https://onnx.ai/onnx/operators/onnx__Acosh.html#acosh-9 "Online Documentation")


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


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

        schema = get_schema("Acosh", 9, "")
        op = Op(self, "Acosh", schema)
        return op(*self._prepare_inputs(schema, input))

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

    def Asinh(self, input: T_Asinh) -> T_Asinh:
        r"""[🌐 Asinh(9)](https://onnx.ai/onnx/operators/onnx__Asinh.html#asinh-9 "Online Documentation")


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


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

        schema = get_schema("Asinh", 9, "")
        op = Op(self, "Asinh", schema)
        return op(*self._prepare_inputs(schema, input))

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

    def Atanh(self, input: T_Atanh) -> T_Atanh:
        r"""[🌐 Atanh(9)](https://onnx.ai/onnx/operators/onnx__Atanh.html#atanh-9 "Online Documentation")


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


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

        schema = get_schema("Atanh", 9, "")
        op = Op(self, "Atanh", schema)
        return op(*self._prepare_inputs(schema, input))

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

    def BatchNormalization(
        self,
        X: T_BatchNormalization,
        scale: T_BatchNormalization,
        B: T_BatchNormalization,
        mean: T_BatchNormalization,
        var: T_BatchNormalization,
        *,
        epsilon: float = 9.999999747378752e-06,
        momentum: float = 0.8999999761581421,
    ) -> Tuple[
        T_BatchNormalization,
        T_BatchNormalization,
        T_BatchNormalization,
        T_BatchNormalization,
        T_BatchNormalization,
    ]:
        r"""[🌐 BatchNormalization(9)](https://onnx.ai/onnx/operators/onnx__BatchNormalization.html#batchnormalization-9 "Online Documentation")


        Carries out batch normalization as described in the paper
        https://arxiv.org/abs/1502.03167. Depending on the mode it is being run,
        there are multiple cases for the number of outputs, which we list below:

        Output case #1: Y, mean, var, saved_mean, saved_var (training mode)
        Output case #2: Y (test mode)

        For previous (depreciated) non-spatial cases, implementors are suggested
        to flatten the input shape to (N x C*D1*D2 ..*Dn) before a BatchNormalization Op.
        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:
            X: (differentiable) Input data tensor from the previous operator; dimensions
                are in the form of (N x C x D1 x D2 ... Dn), where N is the batch size,
                C is the number of channels. Statistics are computed for every channel
                of C over N and D1 to Dn dimensions. For image data, input dimensions
                become (N x C x H x W). The op also accepts single dimension input of
                size N in which case C is assumed to be 1

            scale: (differentiable) Scale tensor of shape (C).

            B: (differentiable) Bias tensor of shape (C).

            mean: (differentiable) running (training) or estimated (testing) mean tensor
                of shape (C).

            var: (differentiable) running (training) or estimated (testing) variance
                tensor of shape (C).

            epsilon: The epsilon value to use to avoid division by zero.

            momentum: Factor used in computing the running mean and variance.e.g.,
                running_mean = running_mean * momentum + mean * (1 - momentum).
        """

        schema = get_schema("BatchNormalization", 9, "")
        op = Op(self, "BatchNormalization", schema)
        return op(
            *self._prepare_inputs(schema, X, scale, B, mean, var),
            epsilon=epsilon,
            momentum=momentum,
        )

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

    T2_Cast: TypeAlias = Union[
        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(9)](https://onnx.ai/onnx/operators/onnx__Cast.html#cast-9 "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.


        Args:
            input: 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", 9, "")
        op = Op(self, "Cast", schema)
        return op(*self._prepare_inputs(schema, input), to=to)

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

    T1_Compress: TypeAlias = BOOL

    def Compress(
        self, input: T_Compress, condition: T1_Compress, *, axis: Optional[int] = None
    ) -> T_Compress:
        r"""[🌐 Compress(9)](https://onnx.ai/onnx/operators/onnx__Compress.html#compress-9 "Online Documentation")


            Selects slices from an input tensor along a given axis where condition evaluates to True for each axis index.
            In case axis is not provided, input is flattened before elements are selected.
            Compress behaves like numpy.compress: https://docs.scipy.org/doc/numpy/reference/generated/numpy.compress.html


        Args:
            input: Tensor of rank r >= 1.

            condition: Rank 1 tensor of booleans to indicate which slices or data
                elements to be selected. Its length can be less than the input length
                alone the axis or the flattened input size if axis is not specified. In
                such cases data slices or elements exceeding the condition length are
                discarded.

            axis: (Optional) Axis along which to take slices. If not specified, input is
                flattened before elements being selected.
        """

        schema = get_schema("Compress", 9, "")
        op = Op(self, "Compress", schema)
        return op(*self._prepare_inputs(schema, input, condition), axis=axis)

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

    def Constant(self, *, value: TensorProto) -> T_Constant:
        r"""[🌐 Constant(9)](https://onnx.ai/onnx/operators/onnx__Constant.html#constant-9 "Online Documentation")

        A constant tensor.

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

        schema = get_schema("Constant", 9, "")
        op = Op(self, "Constant", schema)
        return op(value=value)

    T1_ConstantOfShape: TypeAlias = INT64

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

    def ConstantOfShape(
        self, input: T1_ConstantOfShape, *, value: Optional[TensorProto] = None
    ) -> T2_ConstantOfShape:
        r"""[🌐 ConstantOfShape(9)](https://onnx.ai/onnx/operators/onnx__ConstantOfShape.html#constantofshape-9 "Online Documentation")


        Generate a tensor with given value and shape.


        Args:
            input: 1D tensor. The shape of the expected output tensor. If empty tensor
                is given, the output would be a scalar. All values must be >= 0.

            value: (Optional) The value of the output elements.Should be a one-element
                tensor. If not specified, it defaults to a tensor of value 0 and
                datatype float32
        """

        schema = get_schema("ConstantOfShape", 9, "")
        op = Op(self, "ConstantOfShape", schema)
        return op(*self._prepare_inputs(schema, input), value=value)

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

    def Cosh(self, input: T_Cosh) -> T_Cosh:
        r"""[🌐 Cosh(9)](https://onnx.ai/onnx/operators/onnx__Cosh.html#cosh-9 "Online Documentation")


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


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

        schema = get_schema("Cosh", 9, "")
        op = Op(self, "Cosh", schema)
        return op(*self._prepare_inputs(schema, input))

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

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


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


        Args:
            input: Input tensor
        """

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

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

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

    def EyeLike(
        self, input: T1_EyeLike, *, dtype: Optional[int] = None, k: int = 0
    ) -> T2_EyeLike:
        r"""[🌐 EyeLike(9)](https://onnx.ai/onnx/operators/onnx__EyeLike.html#eyelike-9 "Online Documentation")


        Generate a 2D tensor (matrix) with ones on the diagonal and zeros everywhere else. Only 2D
        tensors are supported, i.e. input T1 must be of rank 2. The shape of the output tensor is the
        same as the input tensor. The data type can be specified by the 'dtype' argument. If
        'dtype' is not specified, then the type of input tensor is used. By default, the main diagonal
        is populated with ones, but attribute 'k' can be used to populate upper or lower diagonals.
        The 'dtype' argument must be one of the data types specified in the 'DataType' enum field in the
        TensorProto message and be valid as an output type.


        Args:
            input: 2D input tensor to copy shape, and optionally, type information from.

            dtype: (Optional) The data type for the elements of the output tensor. If
                not specified,the data type of the input tensor T1 is used. If input
                tensor T1 is also notspecified, then type defaults to 'float'.

            k: (Optional) Index of the diagonal to be populated with ones. Default is 0.
                If T2 is the output, this op sets T2[i, i+k] = 1. k = 0 populates the
                main diagonal, k > 0 populates an upper diagonal,  and k < 0 populates a
                lower diagonal.
        """

        schema = get_schema("EyeLike", 9, "")
        op = Op(self, "EyeLike", schema)
        return op(*self._prepare_inputs(schema, input), dtype=dtype, k=k)

    T_Flatten = TypeVar(
        "T_Flatten",
        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(9)](https://onnx.ai/onnx/operators/onnx__Flatten.html#flatten-9 "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: 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 [0, R], where R is the rank of the input tensor. 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", 9, "")
        op = Op(self, "Flatten", schema)
        return op(*self._prepare_inputs(schema, input), axis=axis)

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

    def Gemm(
        self,
        A: T_Gemm,
        B: T_Gemm,
        C: T_Gemm,
        *,
        alpha: float = 1.0,
        beta: float = 1.0,
        transA: int = 0,
        transB: int = 0,
    ) -> T_Gemm:
        r"""[🌐 Gemm(9)](https://onnx.ai/onnx/operators/onnx__Gemm.html#gemm-9 "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>`_.

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

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

            C: Input tensor C. 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", 9, "")
        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",
        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(9)](https://onnx.ai/onnx/operators/onnx__Greater.html#greater-9 "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: First input operand for the logical operator.

            B: Second input operand for the logical operator.
        """

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

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

    T2_IsNaN: TypeAlias = BOOL

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

        Returns which elements of the input are NaN.

        Args:
            X: input
        """

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

    T_Less = TypeVar(
        "T_Less",
        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(9)](https://onnx.ai/onnx/operators/onnx__Less.html#less-9 "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: First input operand for the logical operator.

            B: Second input operand for the logical operator.
        """

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

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

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


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


        Args:
            A: N-dimensional matrix A

            B: N-dimensional matrix B
        """

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

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

    T2_MaxUnpool: TypeAlias = INT64

    def MaxUnpool(
        self,
        X: T1_MaxUnpool,
        I: T2_MaxUnpool,
        output_shape: Optional[T2_MaxUnpool] = None,
        *,
        kernel_shape: Sequence[int],
        pads: Optional[Sequence[int]] = None,
        strides: Optional[Sequence[int]] = None,
    ) -> T1_MaxUnpool:
        r"""[🌐 MaxUnpool(9)](https://onnx.ai/onnx/operators/onnx__MaxUnpool.html#maxunpool-9 "Online Documentation")


        MaxUnpool essentially computes the partial inverse of the MaxPool op.
         The input information to this op is typically the output information from a MaxPool op. The first
         input tensor X is the tensor that needs to be unpooled, which is typically the pooled tensor (first output)
         from MaxPool. The second input tensor, I, contains the indices to the (locally maximal) elements corresponding
         to the elements in the first input tensor X. Input tensor I is typically the second output of the MaxPool op.
         The third (optional) input is a tensor that specifies the output size of the unpooling operation.

        MaxUnpool is intended to do 'partial' inverse of the MaxPool op. 'Partial' because all the non-maximal
         values from the original input to MaxPool are set to zero in the output of the MaxUnpool op. Pooling
         the result of an unpooling operation should give back the original input to the unpooling op.

        MaxUnpool can produce the same output size for several input sizes, which makes unpooling op ambiguous.
         The third input argument, output_size, is meant to disambiguate the op and produce output tensor of
         known/predictable size.

        In addition to the inputs, MaxUnpool takes three attributes, namely kernel_shape, strides, and pads,
         which define the exact unpooling op. The attributes typically have the same values as the corresponding
         pooling op that the unpooling op is trying to invert.


        Args:
            X: Input data tensor that has to be unpooled. This tensor is typically the
                first output of the MaxPool op.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
                ...].

            I: Input data tensor containing the indices corresponding to elements in the
                first input tensor X.This tensor is typically the second output of the
                MaxPool op.Dimensions must be the same as input tensor X. The indices
                are linear, i.e. computed considering the tensor as flattened 1-D
                tensor, assuming row-major storage. Also, the linear indices should not
                consider padding. So the values in indices are in the range [0, N x C x
                D1 x ... x Dn).

            output_shape: (optional) The shape of the output can be explicitly set which
                will cause pads values to be auto generated. If 'output_shape' is
                specified, 'pads' values are ignored.

            kernel_shape: The size of the kernel along each axis.

            pads: Padding for the beginning and ending along each spatial axis, it can
                take any value greater than or equal to 0. The value represent the
                number of pixels added to the beginning and end part of the
                corresponding axis. `pads` format should be as follow [x1_begin,
                x2_begin...x1_end, x2_end,...], where xi_begin the number of pixels
                added at the beginning of axis `i` and xi_end, the number of pixels
                added at the end of axis `i`. This attribute cannot be used
                simultaneously with auto_pad attribute. If not present, the padding
                defaults to 0 along start and end of each spatial axis.

            strides: Stride along each spatial axis.
        """

        schema = get_schema("MaxUnpool", 9, "")
        op = Op(self, "MaxUnpool", schema)
        return op(
            *self._prepare_inputs(schema, X, I, output_shape),
            kernel_shape=kernel_shape,
            pads=pads,
            strides=strides,
        )

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

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


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


        Args:
            X: 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", 9, "")
        op = Op(self, "MeanVarianceNormalization", schema)
        return op(*self._prepare_inputs(schema, X), axes=axes)

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

    def NonZero(self, X: T_NonZero) -> INT64:
        r"""[🌐 NonZero(9)](https://onnx.ai/onnx/operators/onnx__NonZero.html#nonzero-9 "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: input
        """

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

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

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

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

    def OneHot(
        self, indices: T1_OneHot, depth: T2_OneHot, values: T3_OneHot, *, axis: int = -1
    ) -> T3_OneHot:
        r"""[🌐 OneHot(9)](https://onnx.ai/onnx/operators/onnx__OneHot.html#onehot-9 "Online Documentation")


            Produces a one-hot tensor based on inputs.
            The locations represented by the index values in the 'indices' input tensor will have 'on_value'
            and the other locations will have 'off_value' in the output tensor, where 'on_value' and 'off_value'
            are specified as part of required input argument 'values', which is a two-element tensor of format
            [off_value, on_value]. The rank of the output tensor will be one greater than the rank of the
            input tensor. The additional dimension is for one-hot representation. The additional dimension will
            be inserted at the position specified by 'axis'. If 'axis' is not specified then then additional
            dimension will be inserted as the innermost dimension, i.e. axis=-1. The size of the additional
            dimension is specified by required scalar input 'depth'. The type of the output tensor is the same
            as the type of the 'values' input. Any entries in the 'indices' input tensor with values outside
            the range [0, depth) will result in one-hot representation with all 'off_value' values in the
            output tensor.


        Args:
            indices: Input tensor containing indices. The values must be non-negative
                integers. Any entries in the 'indices' input tensor with values outside
                the range [0, depth) will result in one-hot representation with all
                'off_value' values in the output tensor.In case 'indices' is of
                non-integer type, the values will be casted to int64 before use.

            depth: Scalar or rank 1 tensor containing exactly one element, specifying
                the number of classes in one-hot tensor. This is also the size of the
                one-hot dimension (specified by 'axis' attribute) added on in the output
                tensor. The values in the 'indices' input tensor are expected to be in
                the range [0, depth). In case 'depth' is of non-integer type, it will be
                casted to int64 before use.

            values: Rank 1 tensor containing exactly two elements, in the format
                [off_value, on_value], where 'on_value' is the value used for filling
                locations specified in 'indices' input tensor, and 'off_value' is the
                value used for filling locations other than those specified in 'indices'
                input tensor.

            axis: (Optional) Axis along which one-hot representation in added. Default:
                axis=-1. axis=-1 means that the additional dimension will be inserted as
                the innermost/last dimension in the output tensor.
        """

        schema = get_schema("OneHot", 9, "")
        op = Op(self, "OneHot", schema)
        return op(*self._prepare_inputs(schema, indices, depth, values), axis=axis)

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

    def PRelu(self, X: T_PRelu, slope: T_PRelu) -> T_PRelu:
        r"""[🌐 PRelu(9)](https://onnx.ai/onnx/operators/onnx__PRelu.html#prelu-9 "Online Documentation")


        PRelu takes input data (Tensor<T>) and slope tensor as input, and produces one
        output data (Tensor<T>) where the function `f(x) = slope * x for x < 0`,
        `f(x) = x for x >= 0`., is applied to the data tensor elementwise.
        This operator supports **unidirectional broadcasting** (tensor slope should be unidirectional broadcastable to input tensor X); for more details please check `Broadcasting in ONNX <https://github.com/onnx/onnx/blob/master/docs/Broadcasting.md>`_.

        Args:
            X: (differentiable) Input tensor

            slope: (differentiable) Slope tensor. The shape of slope can be smaller than
                first input X; if so, its shape must be unidirectional broadcastable to
                X
        """

        schema = get_schema("PRelu", 9, "")
        op = Op(self, "PRelu", schema)
        return op(*self._prepare_inputs(schema, X, slope))

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

    def Scan(
        self,
        *initial_state_and_scan_inputs: V_Scan,
        body: GraphProto,
        num_scan_inputs: int,
        scan_input_axes: Optional[Sequence[int]] = None,
        scan_input_directions: Optional[Sequence[int]] = None,
        scan_output_axes: Optional[Sequence[int]] = None,
        scan_output_directions: Optional[Sequence[int]] = None,
    ) -> V_Scan:
        r"""[🌐 Scan(9)](https://onnx.ai/onnx/operators/onnx__Scan.html#scan-9 "Online Documentation")


        Scan can be used to iterate over one or more scan_input tensors,
        constructing zero or more scan_output tensors. It combines ideas from general recurrences,
        functional programming constructs such as scan, fold, map, and zip, and is intended to enable
        generalizations of RNN-like constructs for sequence-to-sequence processing.
        Other tensors (referred to as state_variables here) can be used to carry a state
        when iterating from one element to another (similar to hidden-state in RNNs, also referred
        to as loop-carried dependences in the context of loops).
        Many common usages involve a single scan_input tensor (where functionality
        similar to scan, fold and map can be obtained). When more than one scan_input is used,
        a behavior similar to zip is obtained.

        The attribute body must be a graph, specifying the computation to be performed in
        every iteration. It takes as input the current values of the state_variables and
        the current iterated element of the scan_inputs. It must return the (updated) values
        of the state_variables and zero or more scan_output_element tensors. The values of the
        scan_output_element tensors are concatenated over all the iterations to produce the
        scan_output values of the scan construct (similar to the concatenated intermediate
        hidden-state values of RNN-like constructs). All the output tensors (state_variables as
        well as scan_output_element tensors) are required to have the same shape in each iteration
        of the loop (a restriction imposed to enable efficient memory allocation).

        Note that the iterated element passed to the body subgraph does not have a sequence
        axis. It will have a rank one less than the rank of the corresponding scan_input.

        The scan operation returns the final values of the state_variables as well as the
        scan_outputs.

        The optional attribute scan_input_directions specifies the direction (forward or backward)
        for each scan input. If this attribute is omitted, all sequences are scanned in the forward
        direction. A bidirectional scan may be performed by specifying the same tensor input twice
        in the scan_inputs, once with a forward direction, and once with a backward direction.

        The scan_output of the operation is produced by concatenating the scan_output_element
        values produced by the body in each iteration.  The optional attribute scan_output_directions
        specifies the direction in which scan_output is constructed (by appending or prepending the
        scan_output_element to scan_output in each iteration) for each scan_output. If this attribute
        is omitted, the scan_output_element is appended to the scan_output in each iteration.

        The optional attribute scan_input_axes specifies the axis to be scanned for each scan_input.
        If omitted, every scan_input will be scanned in axis 0. For example, if axis 0 is the
        batch axis and axis 1 is the time axis (to be scanned), specify an axis value of 1.
        Note that scanning a non-zero axis may be less efficient than scanning axis zero.

        The optional attribute scan_output_axes specifies the axis along which the scan_outputs
        are accumulated for each scan_output. For example, if axis 1 is the time axis (to be
        scanned) for both inputs and outputs, specify a scan_input axis and scan_output axis
        value of 1.

        Note that because of the ONNX restriction that only the last parameter of an operator can
        be variadic, the initial-states and scan-inputs are listed together as one input parameter.
        Similarly, the final-states and scan-outputs are listed together as one output parameter.
        The attribute num_scan_inputs indicates the number M of scan-inputs.

        The behavior of

            Scan <
                num_scan_inputs = m,
                body = loop-body,
                scan_input_axes = [axis_1, ..., axis_m]
            > (init_1, ..., init_n, scan_1, ..., scan_m)

        is equivalent to the following pseudo-code:

            // scan_i.shape[axis_i] denotes the (max) sequence-length of scan_i
            // scan_i.shape[axis_i] is required to be equal to scan_j.shape[axis_j] for all i,j.
            sequence_length = scan_1.shape[axis_1];

            // initialize state-variables
            st_1 = init_1; ... st_n = init_n;
            // initialize scan-output variables: [] denotes an empty tensor
            scan_out_1 = []; ...; scan_out_k = [];
            // identify number of iterations:

            // execute loop
            for (int t = 0; t < sequence_length; ++t) {
                // generate the scan-input elements: the notation T<axis=k>[t] indicates the sub-tensor
                // of rank one less than T obtained by indexing T at position t along axis k.
                si_1 = scan_1<axis=axis_1>[t];
                ... ;
                si_m = scan_m<axis=axis_m>[t];
                // execute loop-body
                st_1, ..., st_n, so_1, ..., so_k = loop-body(st_1, ..., st_n, si_1, ..., si_m)
                // accumulate the scan-output elements
                scan_out_1 = Concat<axis=0>(scan_out_1, so_1); ... ; scan_out_k = Concat<axis=0>(scan_out_k, so_k);
            }

            return st_1, ..., st_n, scan_out_1, ..., scan_out_k;

        *Sample usage: Encoding RNN using a Scan*

        The following example shows how a simple RNN over an input tensor %X, with weight tensor %Wi,
        recurrence weight tensor %Ri, bias tensors %Wbi and %Rbi, and initial hidden-state %H_0 can
        be encoded as a ScanLoop. Note that the loop-body is a nested graph, and it directly computes
        %Wi, %Ri, %Wbi, and %Rbi (typically constants or initializers in the body graph). If these
        values are computed in the outer graph, they need to be passed in as extra state_variables.

            graph rnn-encoding {
              %H_0 = ...
              %X = ...
              %Y_h, %Y = Scan[body = <graph rnn-cell-1>, num_scan_inputs=1](%H_0, %X)
              return %Y, %Y_h
            }

            graph rnn-cell-1 (
              %H_tminus1[FLOAT, tensor]
              %X_t[FLOAT, tensor]
            ) {
              %Wi = ...
              %Ri = ...
              %Wbi = ...
              %Rbi = ...
              %t1 = X_t * (Wi^T)
              %t2 = H_tminus1*(Ri^T)
              %t3 = Add(%t1, %t2)
              %t4 = Add(%t3, %Wbi)
              %t5 = Add(%t4, %Rbi)
              %Ht = Tanh(%t5)
              %Accumulate = Identity(%Ht)
              return %Ht, %Accumulate
            }



        Args:
            initial_state_and_scan_inputs: (variadic, heterogeneous) Initial values of
                the loop's N state variables followed by M scan_inputs

            body: The graph run each iteration. It has N+M inputs: (loop state
                variables..., scan_input_elts...). It has N+K outputs: (loop state
                variables..., scan_output_elts...). Each scan_output is created by
                concatenating the value of the specified scan_output_elt value at the
                end of each iteration of the loop. It is an error if the dimensions of
                these values change across loop iterations.

            num_scan_inputs: An attribute specifying the number of scan_inputs M.

            scan_input_axes: An optional list of M flags. The i-th element of the list
                specifies the axis to be scanned (the sequence axis) for the i-th
                scan_input. If omitted, 0 will be used as the scan axis for every
                scan_input.

            scan_input_directions: An optional list of M flags. The i-th element of the
                list specifies the direction to be scanned for the i-th scan_input
                tensor: 0 indicates forward direction and 1 indicates reverse direction.
                If omitted, all scan_input tensors will be scanned in the forward
                direction.

            scan_output_axes: An optional list of K flags. The i-th element of the list
                specifies the axis for the i-th scan_output. The scan outputs are
                accumulated along the specified axis. If omitted, 0 will be used as the
                scan axis for every scan_output.

            scan_output_directions: An optional list of K flags, one for each
                scan_output. The i-th element of the list specifies whether the i-th
                scan_output should be constructed by appending or prepending a new value
                in each iteration: 0 indicates appending and 1 indicates prepending. If
                omitted, all scan_output tensors will be produced by appending a value
                in each iteration.
        """

        schema = get_schema("Scan", 9, "")
        op = Op(self, "Scan", schema)
        return op(
            *self._prepare_inputs(schema, *initial_state_and_scan_inputs),
            body=body,
            num_scan_inputs=num_scan_inputs,
            scan_input_axes=scan_input_axes,
            scan_input_directions=scan_input_directions,
            scan_output_axes=scan_output_axes,
            scan_output_directions=scan_output_directions,
        )

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

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

    def Scatter(
        self,
        data: T_Scatter,
        indices: Tind_Scatter,
        updates: T_Scatter,
        *,
        axis: int = 0,
    ) -> T_Scatter:
        r"""[🌐 Scatter(9)](https://onnx.ai/onnx/operators/onnx__Scatter.html#scatter-9 "Online Documentation")


        Given `data`, `updates` and `indices` input tensors of rank r >= 1, write the values provided by `updates`
        into the first input, `data`, along `axis` dimension of `data` (by default outer-most one as axis=0) at corresponding `indices`.
        For each entry in `updates`, the target index in `data` is specified by corresponding entry in `indices`
        for dimension = axis, and index in source for dimension != axis. For instance, in a 2-D tensor case,
        data[indices[i][j]][j] = updates[i][j] if axis = 0, or data[i][indices[i][j]] = updates[i][j] if axis = 1,
        where i and j are loop counters from 0 up to the respective size in `updates` - 1.
        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: Tensor of rank r >= 1.

            indices: Tensor of int32/int64 indices, of r >= 1 (same rank as input).

            updates: 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]
        """

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

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

    def Shrink(self, input: T_Shrink, *, bias: float = 0.0, lambd: float = 0.5) -> T_Shrink:
        r"""[🌐 Shrink(9)](https://onnx.ai/onnx/operators/onnx__Shrink.html#shrink-9 "Online Documentation")


        Shrink takes one input data (Tensor<numeric>) and produces one Tensor output,
        having same datatype and shape with input. It has two attributes, lambd and
        bias. The formula of this operator is: If x < -lambd, y = x + bias;
        If x > lambd, y = x - bias; Otherwise, y = 0.


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

            bias: The bias value added to output. Default is 0.

            lambd: The lambd value for the Shrink formulation. Default is 0.5.
        """

        schema = get_schema("Shrink", 9, "")
        op = Op(self, "Shrink", schema)
        return op(*self._prepare_inputs(schema, input), bias=bias, lambd=lambd)

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

    def Sign(self, input: T_Sign) -> T_Sign:
        r"""[🌐 Sign(9)](https://onnx.ai/onnx/operators/onnx__Sign.html#sign-9 "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: Input tensor
        """

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

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

    def Sinh(self, input: T_Sinh) -> T_Sinh:
        r"""[🌐 Sinh(9)](https://onnx.ai/onnx/operators/onnx__Sinh.html#sinh-9 "Online Documentation")


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


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

        schema = get_schema("Sinh", 9, "")
        op = Op(self, "Sinh", schema)
        return op(*self._prepare_inputs(schema, input))

    T_TfIdfVectorizer = TypeVar("T_TfIdfVectorizer", INT32, INT64, STRING)

    T1_TfIdfVectorizer: TypeAlias = FLOAT

    def TfIdfVectorizer(
        self,
        X: T_TfIdfVectorizer,
        *,
        max_gram_length: int,
        max_skip_count: int,
        min_gram_length: int,
        mode: str,
        ngram_counts: Sequence[int],
        ngram_indexes: Sequence[int],
        pool_int64s: Optional[Sequence[int]] = None,
        pool_strings: Optional[Sequence[str]] = None,
        weights: Optional[Sequence[float]] = None,
    ) -> T1_TfIdfVectorizer:
        r"""[🌐 TfIdfVectorizer(9)](https://onnx.ai/onnx/operators/onnx__TfIdfVectorizer.html#tfidfvectorizer-9 "Online Documentation")


        This transform extracts n-grams from the input sequence and save them as a vector. Input can
        be either a 1-D or 2-D tensor. For 1-D input, output is the n-gram representation of that input.
        For 2-D input, the output is also a  2-D tensor whose i-th row is the n-gram representation of the i-th input row.
        More specifically, if input shape is [C], the corresponding output shape would be [max(ngram_indexes) + 1].
        If input shape is [N, C], this operator produces a [N, max(ngram_indexes) + 1]-tensor.

        In contrast to standard n-gram extraction, here, the indexes of extracting an n-gram from the original
        sequence are not necessarily consecutive numbers. The discontinuity between indexes are controlled by the number of skips.
        If the number of skips is 2, we should skip two tokens when scanning through the original sequence.
        Let's consider an example. Assume that input sequence is [94, 17, 36, 12, 28] and the number of skips is 2.
        The associated 2-grams are [94, 12] and [17, 28] respectively indexed by [0, 3] and [1, 4].
        If the number of skips becomes 0, the 2-grams generated are [94, 17], [17, 36], [36, 12], [12, 28]
        indexed by [0, 1], [1, 2], [2, 3], [3, 4], respectively.

        The output vector (denoted by Y) stores the count of each n-gram;
        Y[ngram_indexes[i]] indicates the times that the i-th n-gram is found. The attribute ngram_indexes is used to determine the mapping
        between index i and the corresponding n-gram's output coordinate. If pool_int64s is [94, 17, 17, 36], ngram_indexes is [1, 0],
        ngram_counts=[0, 0], then the Y[0] (first element in Y) and Y[1] (second element in Y) are the counts of [17, 36] and [94, 17],
        respectively. An n-gram which cannot be found in pool_strings/pool_int64s should be ignored and has no effect on the output.
        Note that we may consider all skips up to S when generating the n-grams.

        The examples used above are true if mode is "TF". If mode is "IDF", all the counts larger than 1 would be truncated to 1 and
        the i-th element in weights would be used to scale (by multiplication) the count of the i-th n-gram in pool. If mode is "TFIDF",
        this operator first computes the counts of all n-grams and then scale them by the associated values in the weights attribute.

        Only one of pool_strings and pool_int64s can be set. If pool_int64s is set, the input should be an integer tensor.
        If pool_strings is set, the input must be a string tensor.


        Args:
            X: (non-differentiable) Input for n-gram extraction

            max_gram_length: Maximum n-gram length. If this value is 3, 3-grams will be
                used to generate the output.

            max_skip_count: Maximum number of items (integers/strings) to be skipped
                when constructing an n-gram from X. If max_skip_count=1,
                min_gram_length=2, max_gram_length=3, this operator may generate 2-grams
                with skip_count=0 and skip_count=1, and 3-grams with skip_count=0 and
                skip_count=1

            min_gram_length: Minimum n-gram length. If this value is 2 and
                max_gram_length is 3, output may contain counts of 2-grams and 3-grams.

            mode: The weighting criteria. It can be one of "TF" (term frequency), "IDF"
                (inverse document frequency), and "TFIDF" (the combination of TF and
                IDF)

            ngram_counts: The starting indexes of 1-grams, 2-grams, and so on in pool.
                It is useful when determining the boundary between two consecutive
                collections of n-grams. For example, if ngram_counts is [0, 17, 36], the
                first index (zero-based) of 1-gram/2-gram/3-gram in pool are 0/17/36.
                This format is essentially identical to CSR (or CSC) sparse matrix
                format, and we choose to use this due to its popularity.

            ngram_indexes: list of int64s (type: AttributeProto::INTS). This list is
                parallel to the specified 'pool_*' attribute. The i-th element in
                ngram_indexes indicate the coordinate of the i-th n-gram in the output
                tensor.

            pool_int64s: List of int64 n-grams learned from the training set. Either
                this or pool_strings attributes must be present but not both. It's an
                1-D tensor starting with the collections of all 1-grams and ending with
                the collections of n-grams. The i-th element in pool stores the n-gram
                that should be mapped to coordinate ngram_indexes[i] in the output
                vector.

            pool_strings: List of strings n-grams learned from the training set. Either
                this or pool_int64s attributes must be present but not both. It's an 1-D
                tensor starting with the collections of all 1-grams and ending with the
                collections of n-grams. The i-th element in pool stores the n-gram that
                should be mapped to coordinate ngram_indexes[i] in the output vector.

            weights: list of floats. This attribute stores the weight of each n-gram in
                pool. The i-th element in weights is the weight of the i-th n-gram in
                pool. Its length equals to the size of ngram_indexes. By default,
                weights is an all-one tensor.This attribute is used when mode is "IDF"
                or "TFIDF" to scale the associated word counts.
        """

        schema = get_schema("TfIdfVectorizer", 9, "")
        op = Op(self, "TfIdfVectorizer", schema)
        return op(
            *self._prepare_inputs(schema, X),
            max_gram_length=max_gram_length,
            max_skip_count=max_skip_count,
            min_gram_length=min_gram_length,
            mode=mode,
            ngram_counts=ngram_counts,
            ngram_indexes=ngram_indexes,
            pool_int64s=pool_int64s,
            pool_strings=pool_strings,
            weights=weights,
        )

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

    def Upsample(self, X: T_Upsample, scales: FLOAT, *, mode: str = "nearest") -> T_Upsample:
        r"""[🌐 Upsample(9)](https://onnx.ai/onnx/operators/onnx__Upsample.html#upsample-9 "Online Documentation")


        Upsample the input tensor.
        Each dimension value of the output tensor is:
          output_dimension = floor(input_dimension * scale).


        Args:
            X: N-D tensor

            scales: The scale array along each dimension. It takes value greater than or
                equal to 1. The number of elements of 'scales' should be the same as the
                rank of input 'X'.

            mode: Two interpolation modes: nearest (default), and linear (including
                bilinear, trilinear, etc)
        """

        schema = get_schema("Upsample", 9, "")
        op = Op(self, "Upsample", schema)
        return op(*self._prepare_inputs(schema, X, scales), mode=mode)

    B_Where: TypeAlias = BOOL

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

    def Where(self, condition: B_Where, X: T_Where, Y: T_Where) -> T_Where:
        r"""[🌐 Where(9)](https://onnx.ai/onnx/operators/onnx__Where.html#where-9 "Online Documentation")


        Return elements, either from X or Y, depending on condition.
        Where behaves like
        [numpy.where](https://docs.scipy.org/doc/numpy/reference/generated/numpy.where.html)
        with three parameters.

        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:
            condition: (non-differentiable) When True (nonzero), yield X, otherwise
                yield Y

            X: (differentiable) values selected at indices where condition is True

            Y: (differentiable) values selected at indices where condition is False
        """

        schema = get_schema("Where", 9, "")
        op = Op(self, "Where", schema)
        return op(*self._prepare_inputs(schema, condition, X, Y))
