# Source code for mindspore.ops.operations.array_ops

# coding: utf-8

# Copyright 2020 Huawei Technologies Co., Ltd
#
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#
# Unless required by applicable law or agreed to in writing, software
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and

# ============================================================================

"""Operators for array."""

import copy
import functools
import numbers
import numpy as np

from ..._checkparam import ParamValidator as validator
from ..._checkparam import Rel
from ...common import dtype as mstype
from ...common.tensor import Tensor
from ..operations.math_ops import _check_infer_attr_reduce, _infer_shape_reduce
from ..primitive import Primitive, PrimitiveWithInfer, prim_attr_register

[docs]class ExpandDims(PrimitiveWithInfer):
"""

Note:
If the specified axis is a negative number, the index is counted
backward from the end and starts at 1.

Raises:
ValueError: If axis is not an integer or not in the valid range.

Inputs:
- **input_x** (Tensor) - The shape of tensor is :math:(x_1, x_2, ..., x_R).
- **axis** (int) - Specifies the dimension index at which to expand
the shape of input_x. The value of axis must be in the range
[-input_x.dim()-1, input_x.dim()]. Only constant value is allowed.

Outputs:
Tensor, the shape of tensor is :math:(1, x_1, x_2, ..., x_R) if the
value of axis is 0.

Examples:
>>> input_tensor = Tensor(np.array([[2, 2], [2, 2]]), mindspore.float32)
>>> expand_dims = ExpandDims()
>>> output = expand_dims(input_tensor, 0)
"""

@prim_attr_register
def __init__(self):
"""init ExpandDims"""
self.__setattr_flag__ = True
self.init_prim_io_names(inputs=['x', 'axis'], outputs=['output'])

def __infer__(self, x, axis):
validator.check_subclass("input_x", x['dtype'], mstype.tensor)
x_shape = list(x['shape'])
axis_v = axis['value']
rank = len(x_shape)
validator.check_const_input('axis', axis_v)
validator.check_type("axis", axis_v, [int])
validator.check_int_range('axis', axis_v, -rank - 1, rank, Rel.INC_BOTH)
if axis_v < 0:
axis_v = rank + 1 + axis_v
x_shape.insert(axis_v, 1)
out = {'shape': x_shape,
'dtype': x['dtype'],
'value': None}
return out

[docs]class DType(PrimitiveWithInfer):
"""
Returns the data type of input tensor as mindspore.dtype.

Inputs:
- **input_x** (Tensor) - The shape of tensor is :math:(x_1, x_2, ..., x_R).

Outputs:
mindspore.dtype, the data type of a tensor.

Examples:
>>> input_tensor = Tensor(np.array([[2, 2], [2, 2]]), mindspore.float32)
>>> type = DType()(input_tensor)
"""

@prim_attr_register
def __init__(self):
"""init DType"""

def __infer__(self, x):
validator.check_subclass("input_x", x['dtype'], mstype.tensor)
out = {'shape': (),
'dtype': mstype.type_type,
'value': x['dtype'].element_type()}
return out

[docs]class SameTypeShape(PrimitiveWithInfer):
"""
Checks whether data type and shape of two tensors are the same.

Raises:
ValueError: If not the same.

Inputs:
- **input_x** (Tensor) - The shape of tensor is :math:(x_1, x_2, ..., x_R).
- **input_y** (Tensor) - The shape of tensor is :math:(x_1, x_2, ..., x_S).

Outputs:
Tensor, the shape of tensor is :math:(x_1, x_2, ..., x_R),
if data type and shape of input_x and input_y are the same.

Examples:
>>> input_x = Tensor(np.array([[2, 2], [2, 2]]), mindspore.float32)
>>> input_y = Tensor(np.array([[2, 2], [2, 2]]), mindspore.float32)
>>> out = SameTypeShape()(input_x, input_y)
"""

@prim_attr_register
def __init__(self):
"""init Same"""

def __call__(self, x, y):
"""run in PyNative mode"""
if x.dtype() != y.dtype():
raise TypeError(f"The {x} and {y} should be same dtype.")
if x.shape() != y.shape():
raise TypeError(f"The {x} and {y} should have same shape.")
return x

def __infer__(self, x, y):
if x['dtype'] != y['dtype']:
raise TypeError(f"The {x} and {y} should be same dtype,"
f" but got {x['dtype']} {y['dtype']}.")
if x['shape'] != y['shape']:
raise ValueError(f"The {x} and {y} should be same shape,"
f" but got {x['shape']} {y['shape']}.")
return x

[docs]class Cast(PrimitiveWithInfer):
"""
Returns a tensor with the new specified data type.

Inputs:
- **input_x** (Union[Tensor, Number]) - The shape of tensor is :math:(x_1, x_2, ..., x_R).
The tensor to be casted.
- **type** (dtype.Number) - The valid data type of the output tensor. Only constant value is allowed.

Outputs:
Tensor, the shape of tensor is :math:(x_1, x_2, ..., x_R), same as input_x.

Examples:
>>> input_np = np.random.randn(2, 3, 4, 5).astype(np.float32)
>>> input_x = Tensor(input_np)
>>> type_dst = mindspore.int32
>>> cast = Cast()
>>> result = cast(input_x, type_dst)
>>> expect = input_np.astype(type_dst)
"""

@prim_attr_register
def __init__(self):
# if primitive need setattr in __infer__ need add this flag
"""init Cast"""
self.init_prim_io_names(inputs=['x', 'dst_type'], outputs=['output'])
self.__setattr_flag__ = True

def __infer__(self, x, t):
src_type = x['dtype']
dst_type = t['value']

validator.check_subclass("input_x", src_type, [mstype.tensor, mstype.number])
validator.check_subclass("type", dst_type, mstype.number, with_type_of=False)

if isinstance(src_type, type(mstype.tensor)):
src_type = x['dtype'].element_type()
if isinstance(dst_type, type(mstype.tensor)):
dst_type = dst_type.element_type()

value = None
if x['value'] is not None:
np_dst_type = mstype.dtype_to_nptype(dst_type)
if isinstance(x['value'], (int, float)):
value = Tensor(np.array(x['value']).astype(np_dst_type))
else:
value = Tensor(x['value'].asnumpy().astype(np_dst_type))

out = {'shape': x['shape'],
'dtype': mstype.tensor_type(t['value']),
'value': value}
return out

[docs]class IsSubClass(PrimitiveWithInfer):
"""
Check whether one type is sub class of another type.

Inputs:
- **sub_type** (mindspore.dtype) - The type to be check. Only constant value is allowed.
- **type_** (mindspore.dtype) - The target type. Only constant value is allowed.

Outputs:
bool, the check result.

Examples:
>>> result = IsSubClass()(mindspore.int32,  mindspore.intc)
"""

@prim_attr_register
def __init__(self):
pass

def __infer__(self, sub_type, type_):
sub_type_t = sub_type['value']
type_v = type_['value']

validator.check_type("sub_type", sub_type_t, [mstype.Type])
validator.check_type("type_", type_v, [mstype.Type])

value = mstype.issubclass_(sub_type_t, type_v)

out = {'shape': (),
'dtype': mstype.type_type,
'value': value}
return out

[docs]class IsInstance(PrimitiveWithInfer):
"""
Check whether an object is an instance of a target type.

Inputs:
- **inst** (Any Object) - The instance to be check. Only constant value is allowed.
- **type_** (mindspore.dtype) - The target type. Only constant value is allowed.

Outputs:
bool, the check result.

Examples:
>>> a = 1
>>> result = IsInstance()(a, mindspore.int32)
"""

@prim_attr_register
def __init__(self):
pass

def __infer__(self, inst, type_):
sub_type_t = inst['dtype']
type_v = type_['value']

validator.check_const_input("inst", inst['value'])
validator.check_type("type_", type_v, [mstype.Type])

value = mstype.issubclass_(sub_type_t, type_v)

out = {'shape': (),
'dtype': mstype.type_type,
'value': value}
return out

[docs]class Reshape(PrimitiveWithInfer):
"""
Reshapes input tensor with the same values based on a given shape tuple.

Raises:
ValueError: Given a shape tuple, if it has more than one -1; or if the product
of its elements is less than or equal to 0 or cannot be divided by the product
of the input tensor shape; or if it does not match the input's array size.

Inputs:
- **input_x** (Tensor) - The shape of tensor is :math:(x_1, x_2, ..., x_R).
- **input_shape** (tuple[int]) - The input tuple is constructed by multiple
integers, i.e., :math:(y_1, y_2, ..., y_S). Only constant value is allowed.

Outputs:
Tensor, the shape of tensor is :math:(y_1, y_2, ..., y_S).

Examples:
>>> input_tensor = Tensor(np.array([[-0.1, 0.3, 3.6], [0.4, 0.5, -3.2]]), mindspore.float32)
>>> reshape = Reshape()
>>> output = reshape(input_tensor, (3, 2))
"""

@prim_attr_register
def __init__(self):
"""init Reshape"""
self.init_prim_io_names(inputs=['tensor', 'shape'], outputs=['output'])
self.__setattr_flag__ = True

def __infer__(self, x, shape):
shape_v = shape['value']
x_shp = x['shape']
validator.check_subclass("x", x['dtype'], mstype.tensor)
validator.check_const_input("shape", shape_v)
validator.check_type("shape", shape_v, [tuple])
shape_v = list(shape_v)
neg_index = -1
dim_prod = 1
for i, shp_i in enumerate(shape_v):
validator.check_type("shape[%d]" % i, shp_i, [int])
if shp_i == -1:
if neg_index != -1:
raise ValueError(f'The shape can only has one -1 at most, but {shape_v}.')
neg_index = i
else:
dim_prod *= shp_i
arr_prod = np.prod(x_shp)
if dim_prod <= 0 or arr_prod % dim_prod != 0:
raise ValueError(f'The product of shape should > 0 and'
f' can be divided by prod of input {arr_prod},'
f' but shape {shape}, product of shape {dim_prod}.')

if neg_index != -1:
shape_v[neg_index] = int(arr_prod / dim_prod)
dim_prod *= shape_v[neg_index]
if dim_prod != arr_prod:
raise ValueError(f'The shape arg for reshape must match array''s size'
f' input shape {arr_prod}, shape {dim_prod}.')

value = None
if x['value'] is not None:
value = Tensor(x['value'].asnumpy().reshape(shape_v))

out = {'shape': tuple(shape_v),
'dtype': x['dtype'],
'value': value}
return out

[docs]class Shape(Primitive):
"""
Returns the shape of input tensor.

Inputs:
- **input_x** (Tensor) - The shape of tensor is :math:(x_1, x_2, ..., x_R).

Outputs:
tuple[int], the output tuple is constructed by multiple integers,
:math:(x_1, x_2, ..., x_R).

Examples:
>>> input_tensor = Tensor(np.ones(shape=[3, 2, 1]), mindspore.float32)
>>> shape = Shape()
>>> output = shape(input_tensor)
"""

@prim_attr_register
def __init__(self):
"""init Shape"""

[docs]class Squeeze(PrimitiveWithInfer):
"""
Returns a tensor with the same type but dimensions of 1 being removed based on axis.

Note:
The dimension index starts at 0 and must be in the range [-input.dim(), input.dim()).

Raises:
ValueError: If the corresponding dimension of the specified axis does not equal to 1.

Args:
axis (int): Specifies the dimension indexes of shape to be removed, which will remove
all the dimensions that are equal to 1. If specified, it must be int32 or int64.
Default: (), an empty tuple.

Inputs:
- **input_x** (Tensor) - The shape of tensor is :math:(x_1, x_2, ..., x_R).

Outputs:
Tensor, the shape of tensor is :math:(x_1, x_2, ..., x_S).

Examples:
>>> input_tensor = Tensor(np.ones(shape=[3, 2, 1]), mindspore.float32)
>>> squeeze = Squeeze(2)
>>> output = squeeze(input_tensor)
"""

@prim_attr_register
def __init__(self, axis=()):
"""init Squeeze"""
self.init_prim_io_names(inputs=['x'], outputs=['output'])
validator.check_type('axis', axis, [int, tuple])
if isinstance(axis, tuple):
for item in axis:
validator.check_type("item", item, [int])
else:
self.axis = (axis,)

def infer_shape(self, x_shape):
axis = self.axis
x_shape = list(x_shape)
ndim = len(x_shape)
if not axis:
ret = [d for d in x_shape if d != 1]
else:
for a in axis:
validator.check_int_range('axis or its elements', a, -ndim, ndim - 1, Rel.INC_BOTH)
if x_shape[a] != 1:
raise ValueError('Cannot select an axis to squeeze out which has size not equal to one.')
ret = [x_shape[i] for i in range(ndim) if not (i in axis or (i - ndim) in axis)]
return ret

def infer_dtype(self, x_dtype):
validator.check_subclass("x", x_dtype, mstype.tensor)
return x_dtype

[docs]class Transpose(PrimitiveWithInfer):
"""
Permutes the dimensions of input tensor according to input perm.

Inputs:
- **input_x** (Tensor) - The shape of tensor is :math:(x_1, x_2, ..., x_R).
- **input_perm** (tuple[int]) - The permutation to be converted. The input tuple is constructed by multiple
indexes. The length of input_perm and the shape of input_x should be the same. Only constant value is
allowed.

Outputs:
Tensor, the type of output tensor is same as input_x and the shape of output tensor is decided by the
shape of input_x and the value of input_perm.

Examples:
>>> input_tensor = Tensor(np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]]), mindspore.float32)
>>> perm = (0, 2, 1)
>>> expect = np.array([[[1, 4], [2, 5], [3, 6]], [[7, 10], [8, 11], [9, 12]]])
>>> transpose = Transpose()
>>> output = transpose(input_tensor, perm)
"""

@prim_attr_register
def __init__(self):
"""init Transpose"""
self.__setattr_flag__ = True
self.init_prim_io_names(inputs=['x', 'perm'], outputs=['output'])

def __infer__(self, x, perm):
x_shape = x['shape']
p_value = perm['value']
x_type = x['dtype']
if len(x_shape) != len(p_value):
raise ValueError('The dimension of x and perm must be equal.')

validator.check_const_input("perm", p_value)
validator.check_type("p_value", p_value, [tuple])
validator.check_subclass("x_type", x_type, mstype.tensor)

tmp = list(p_value)
for i, dim in enumerate(p_value):
validator.check_integer("perm[%d]" % i, dim, 0, Rel.GE)
validator.check_integer("perm[%d]" % i, dim, len(p_value), Rel.LT)
tmp.remove(dim)
if dim in tmp:
raise ValueError('The value of perm is wrong.')

out_shapes = []
for i in p_value:
out_shapes.append(x_shape[i])
out = {'shape': tuple(out_shapes),
'dtype': x['dtype'],
'value': None}
return out

[docs]class GatherV2(PrimitiveWithInfer):
"""
Returns a slice of input tensor based on the specified indices and axis.

Inputs:
- **input_params** (Tensor) - The shape of tensor is :math:(x_1, x_2, ..., x_R).
The original Tensor.
- **input_indices** (Tensor) - The shape of tensor is :math:(y_1, y_2, ..., y_S).
Specifies the indices of elements of the original Tensor. Must be in the range
[0, input_param.shape()[axis]).
- **axis** (int) - Specifies the dimension index to gather indices.

Outputs:
Tensor, the shape of tensor is :math:(z_1, z_2, ..., z_N).

Examples:
>>> params = Tensor(np.array([[1, 2, 7, 42], [3, 4, 54, 22], [2, 2, 55, 3]]), mindspore.float32)
>>> indices = Tensor(np.array([1, 2]), mindspore.int32)
>>> axis = 1
>>> out = GatherV2()(params, indices, axis)
"""

@prim_attr_register
def __init__(self):
"""init index_select"""
self.__setattr_flag__ = True
self.init_prim_io_names(inputs=['params', 'indices', 'axis'], outputs=['output'])

def __infer__(self, params, indices, axis):
validator.check_subclass("params", params['dtype'], mstype.tensor)
validator.check_subclass("indices", indices['dtype'], mstype.tensor)
validator.check_subclass("axis", axis['dtype'], mstype.int_)
validator.check_typename("element of indices", indices['dtype'], mstype.int_type)
validator.check_const_input("axis", axis['value'])
axis_v = axis['value']
params_shp = params['shape']
rank = len(params_shp)
validator.check_int_range("axis", axis_v, -rank, rank, Rel.INC_LEFT)
if axis_v < 0:
axis_v += rank
out_shape = params_shp[:axis_v] + indices['shape'] + params_shp[axis_v + 1:]
out = {'shape': out_shape,
'dtype': params['dtype'],
'value': None}
return out

[docs]class Split(PrimitiveWithInfer):
"""
Splits input tensor into output_num of tensors along the given axis and output numbers.

Args:
axis (int): Index of the split position. Default: 0.
output_num (int): The number of output tensors. Default: 1.

Raises:
ValueError: If axis is out of the range [-len(input_x.shape()), len(input_x.shape())),
or if the output_num is less than or equal to 0, or if the
dimension which to split cannot be evenly divided by output_num.

Inputs:
- **input_x** (Tensor) - The shape of tensor is :math:(x_1, x_2, ..., x_R).

Outputs:
tuple[Tensor], the shape of each output tensor is same, which is
:math:(y_1, y_2, ..., y_S).

Examples:
>>> split = Split(1, 2)
>>> x = Tensor(np.array([[1, 1, 1, 1], [2, 2, 2, 2]]))
>>> output = split(x)
"""

@prim_attr_register
def __init__(self, axis=0, output_num=1):
"""init Split"""
validator.check_type("axis", axis, [int])
validator.check_type("output_num", output_num, [int])
self.axis = axis
self.output_num = output_num

def __infer__(self, x):
validator.check_subclass("x", x['dtype'], mstype.tensor)
x_shape = list(x['shape'])
dim = len(x_shape)
validator.check_int_range('axis value', self.axis, -dim, dim, Rel.INC_LEFT)
validator.check_integer("output_num", self.output_num, 0, Rel.GT)
output_valid_check = x_shape[self.axis] % self.output_num
validator.check_integer("the dimension which to split divides output_num", output_valid_check, 0, Rel.EQ)
x_shape[self.axis] = int(x_shape[self.axis] / self.output_num)
out_shapes = []
out_dtypes = []
for _ in range(self.output_num):
out_shapes.append(tuple(x_shape))
out_dtypes.append(x['dtype'])
out_shapes = tuple(out_shapes)
out_dtypes = tuple(out_dtypes)
out = {'shape': out_shapes,
'dtype': out_dtypes,
'value': None}
return out

[docs]class Rank(PrimitiveWithInfer):
"""
Returns the rank of a tensor.

Returns a 0-D int32 Tensor representing the rank of input; the rank of a tensor
is the number of indices required to uniquely select each element of the tensor.

Inputs:
- **input_x** (Tensor) - The shape of tensor is :math:(x_1, x_2, ..., x_R).

Outputs:
Tensor. 0-D int32 Tensor representing the rank of input, i.e., :math:R.

Examples:
>>> input_tensor = Tensor(np.array([[2, 2], [2, 2]]), mindspore.float32)
>>> rank = Rank()
>>> rank(input_tensor)
"""

@prim_attr_register
def __init__(self):
"""init Rank"""

def __infer__(self, x):
validator.check_subclass("x", x['dtype'], mstype.tensor)
out = {'shape': None,
'dtype': None,
'value': len(x['shape'])}
return out

[docs]class TruncatedNormal(PrimitiveWithInfer):
"""
Returns a tensor of the specified shape filled with truncated normal values.

The generated values follow a normal distribution.

Args:
seed (int): A int number used to create random seed. Default: 0.
dtype (:class:mindspore.dtype): Data type. Default: mindspore.float32.

Inputs:
- **shape** (Tensor) - Shape of output tensor. The shape is a 1-D tensor, and type is int.

Outputs:
Tensor, type of output tensor is same as attribute dtype.

Examples:
>>> input_shape = Tensor(np.array([1, 2, 3]))
>>> truncated_normal = TruncatedNormal()
>>> output = truncated_normal(input_shape)
"""

@prim_attr_register
def __init__(self, seed=0, dtype=mstype.float32):
"""init TruncatedNormal"""
validator.check_type('seed', seed, [int])
validator.check_typename('dtype', dtype, mstype.number_type)

def __infer__(self, shape):
shape_t = shape['value']
validator.check_subclass("shape", shape['dtype'], mstype.tensor)
shape_n = shape_t.asnumpy()
if shape_n.ndim != 1:
raise ValueError('The rank of input shape must be 1.')
if shape_n.dtype not in (np.int32, np.int64):
raise TypeError('The type of input shape must be int32 or int64.')
for i, item in enumerate(shape_n):
validator.check_integer(f"shape[{i}]", item.item(), 0, Rel.GT)
out = {'shape': tuple(shape_n),
'dtype': mstype.tensor_type(self.dtype),
'value': None}
return out

[docs]class Size(PrimitiveWithInfer):
r"""
Returns the elements count size of a tensor.

Returns an int scalar representing the elements size of input, the total number of elements in the tensor.

Inputs:
- **input_x** (Tensor) - The shape of tensor is :math:(x_1, x_2, ..., x_R).

Outputs:
int, a scalar representing the elements size of input_x, tensor is the number of elements
in a tensor, :math:size=x_1*x_2*...x_R.

Examples:
>>> input_tensor = Tensor(np.array([[2, 2], [2, 2]]), mindspore.float32)
>>> size = Size()
>>> output = size(input_tensor)
"""

@prim_attr_register
def __init__(self):
"""init Size"""

def __infer__(self, x):
size = 1
validator.check_subclass("x", x['dtype'], mstype.tensor)
shp = x['shape']
if not shp:
size = 0
else:
size = functools.reduce(lambda x, y: x * y, x['shape'])
out = {'shape': None,
'dtype': mstype.int32,
'value': size}
return out

[docs]class Fill(PrimitiveWithInfer):
"""
Creates a tensor filled with a scalar value.

Creates a tensor with shape described by the first argument and fills it with values in the second argument.

Inputs:
- **type** (mindspore.dtype) - The specified type of output tensor. Only constant value is allowed.
- **shape** (tuple) - The specified shape of output tensor. Only constant value is allowed.
- **value** (scalar) - Value to fill the returned tensor. Only constant value is allowed.

Outputs:
Tensor, has the same type and shape as input value.

Examples:
>>> fill = P.Fill()
>>> fill(P.DType()(x), (2, 2), 1)
"""

@prim_attr_register
def __init__(self):
"""init Fill"""

def __infer__(self, dtype, dims, x):
validator.check_const_input("type", dtype['value'])
validator.check_const_input("shape", dims['value'])
validator.check_const_input("value", x['value'])
validator.check_type("shape", dims['value'], [tuple])
validator.check_type("value", x['value'], [numbers.Number, bool])
for item in dims['value']:
validator.check_type("item", item, [int])
validator.check_integer("item", item, 0, Rel.GT)
x_dtype = dtype['value']
valid_types = [mstype.bool_, mstype.int8, mstype.int32, mstype.int64,
mstype.uint8, mstype.uint32, mstype.uint64,
mstype.float16, mstype.float32, mstype.float64]
validator.check_typename("value", x_dtype, valid_types)
x_nptype = mstype.dtype_to_nptype(x_dtype)
ret = np.full(dims['value'], x['value'], x_nptype)
out = {
'value': Tensor(ret),
'shape': dims['value'],
'dtype': x_nptype,
}
return out

[docs]class OnesLike(PrimitiveWithInfer):
"""
Creates a new tensor. All elements' value are 1.

Returns a tensor of ones with the same shape and type as the input.

Inputs:
- **input_x** (Tensor) - Input tensor.

Outputs:
Tensor, has the same shape and type as input_x but filled with ones.

Examples:
>>> oneslike = P.OnesLike()
>>> x = Tensor(np.array([[0, 1], [2, 1]]).astype(np.int32))
>>> output = oneslike(x)
"""

@prim_attr_register
def __init__(self):
"""Init OnesLike"""

def infer_shape(self, x_shape):
return x_shape

def infer_dtype(self, x_dtype):
validator.check_subclass("x", x_dtype, mstype.tensor)
validator.check_typename('x_dtype', x_dtype, mstype.number_type + (mstype.bool_,))
return x_dtype

[docs]class ZerosLike(PrimitiveWithInfer):
"""
Creates a new tensor. All elements value are 0.

Returns a tensor of zeros with the same shape and type as the input tensor.

Inputs:
- **input_x** (Tensor) - Input tensor.

Outputs:
Tensor, has the same shape and type as input_x but filled with zeros.

Examples:
>>> zeroslike = P.ZerosLike()
>>> x = Tensor(np.array([[0, 1], [2, 1]]).astype(np.int32))
>>> output = zeroslike(x)
"""

@prim_attr_register
def __init__(self):
"""Init ZerosLike"""
self.init_prim_io_names(inputs=['x'], outputs=['y'])

def infer_shape(self, x_shape):
return x_shape

def infer_dtype(self, x_dtype):
validator.check_subclass("x", x_dtype, mstype.tensor)
validator.check_typename('x_dtype', x_dtype, mstype.number_type + (mstype.bool_,))
return x_dtype

[docs]class TupleToArray(PrimitiveWithInfer):
"""
Converts a tuple to tensor.

If the first number type of tuple is int, the output tensor type is int. Else, the output tensor type is float.

Inputs:
- **input_x** (tuple) - A tuple of numbers. These numbers have the same type. Only constant value is allowed.

Outputs:
Tensor, if the input tuple contain N numbers, then the output tensor shape is (N,).

Examples:
>>> type = TupleToArray()((1,2,3))
"""

@prim_attr_register
def __init__(self):
"""init TupleToArray"""

def infer_value(self, x):
validator.check_const_input("x", x)
validator.check_type("x", x, [tuple])
validator.check("size of x", len(x), '', 0, Rel.GT)
dtype = type(x[0])
for i, item in enumerate(x):
validator.check_type(f"x[{i}]", item, [numbers.Number])
if not all(isinstance(item, dtype) for item in x):
raise TypeError("All elements of input x must be have same type.")
if isinstance(x[0], int):
ret = np.array(x, np.int32)
else:
ret = np.array(x, np.float32)

return Tensor(ret)

[docs]class ScalarToArray(PrimitiveWithInfer):
"""
Converts scalar to Tensor.

Inputs:
- **input_x** (Union[int, float]) - The input is a scalar. Only constant value is allowed.

Outputs:
Tensor. 0-D Tensor and the content is the input.

Examples:
>>> op = ScalarToArray()
>>> data = 1.0
>>> output = op(data)
"""

@prim_attr_register
def __init__(self):
pass

def infer_value(self, x):
validator.check_const_input("x", x)
validator.check_type("x", x, [int, float])
if isinstance(x, int):
ret = np.array(x, np.int32)
else:
ret = np.array(x, np.float32)
return Tensor(ret)

[docs]class ScalarToTensor(PrimitiveWithInfer):
"""
Converts scalar to Tensor, and convert data type to specified type.

Inputs:
- **input_x** (Union[int, float]) - The input is a scalar. Only constant value is allowed.
- **dtype** (mindspore.dtype) - The target data type. Default: mindspore.float32. Only
constant value is allowed.

Outputs:
Tensor. 0-D Tensor and the content is the input.

Examples:
>>> op = ScalarToTensor()
>>> data = 1
>>> output = op(data, mindspore.float32)
"""

@prim_attr_register
def __init__(self):
pass

def infer_value(self, x, dtype=mstype.float32):
validator.check_const_input("x", x)
validator.check_type("x", x, [int, float])
validator.check_subclass("dtype", dtype, mstype.number, with_type_of=False)
data_type = mstype.dtype_to_nptype(dtype)
return Tensor(np.array(x, data_type))

[docs]class InvertPermutation(PrimitiveWithInfer):
r"""
Computes the inverse of an index permutation.

Given a tuple input, this operation inserts a dimension of 1 at the dimension
This operation calculates the inverse of the index replacement. It requires a
1-dimensional tuple x, which represents the array starting at zero,
and swaps each value with its index position. In other words, for the output
tuple y and the input tuple x, this operation calculates the following:
:math:y[x[i]] = i, \quad i \in [0, 1, \ldots, \text{len}(x)-1].

Note:
These values must include 0. There must be no duplicate values and the
values can not be negative.

Inputs:
- **input_x** (tuple[int]) - The input tuple is constructed by multiple
integers, i.e., :math:(y_1, y_2, ..., y_S) representing the indices.
The values must include 0. There can be no duplicate values or negative values.

Outputs:
tuple[int]. the lenth is same as input.

Examples:
>>> invert = InvertPermutation()
>>> input_data = (3, 4, 0, 2, 1)
>>> output = invert(input_data)
>>> output == (2, 4, 3, 0, 1)
"""

@prim_attr_register
def __init__(self):
"""init InvertPermutation"""

def __infer__(self, x):
x_shp = x['shape']
x_value = x['value']
validator.check_const_input("shape", x_shp)
validator.check_type("shape", x_shp, [tuple])
z = [x_value[i] for i in range(len(x_value))]
z.sort()

y = [None]*len(x_value)
for i, value in enumerate(x_value):
validator.check_type("input[%d]" % i, value, [int])
validator.check(f'value', z[i], f'index', i)
y[value] = i
z.append(value)
return {'shape': x_shp,
'dtype': x['dtype'],
'value': tuple(y)}

[docs]class Argmax(PrimitiveWithInfer):
"""
Returns the indices of the max value of a tensor across the axis.

If the shape of input tensor is :math:(x_1, ..., x_N), the output tensor shape is
:math:(x_1, ..., x_{axis-1}, x_{axis+1}, ..., x_N).

Args:
axis (int): Axis on which Argmax operation applies. Default: -1.
output_type (:class:mindspore.dtype): An optional data type of mindspore.dtype.int32 and
mindspore.dtype.int64. Default: mindspore.dtype.int64.

Inputs:
- **input_x** (Tensor) - Input tensor.

Outputs:
Tensor, indices of the max value of input tensor across the axis.

Examples:
>>> input = Tensor(np.array([2.0, 3.1, 1.2]))
>>> index = Argmax()(input)
>>> assert index == Tensor(1, mindspore.int64)
"""

@prim_attr_register
def __init__(self, axis=-1, output_type=mstype.int64):
"""init Argmax"""
self.init_prim_io_names(inputs=['x'], outputs=['output'])
validator.check_type("axis", axis, [int])
validator.check_typename('output_type', output_type, [mstype.int32, mstype.int64])
self.axis = axis

def infer_shape(self, x_shape):
axis = self.axis
if axis is None:
axis = 0
x_rank = len(x_shape)
validator.check_int_range("axis", axis, -x_rank, x_rank, Rel.INC_LEFT)
axis = axis + x_rank if axis < 0 else axis
ouput_shape = [x_shape[i] for i in range(x_rank) if i != axis]
return ouput_shape

def infer_dtype(self, x_dtype):
validator.check_subclass("input_x", x_dtype, mstype.tensor)
return mstype.tensor_type(self.output_type)

[docs]class Argmin(PrimitiveWithInfer):
"""
Returns the indices of the min value of a tensor across the axis.

If the shape of input tensor is :math:(x_1, ..., x_N), the output tensor shape is
:math:(x_1, ..., x_{axis-1}, x_{axis+1}, ..., x_N).

Args:
axis (int): Axis on which Argmin operation applies. Default: -1.
output_type (:class:mindspore.dtype): An optional data type from: mindspore.dtype.int32,
mindspore.dtype.int64. Default: mindspore.dtype.int64.

Inputs:
- **input_x** (Tensor) - Input tensor.

Outputs:
Tensor, indices of the min value of input tensor across the axis.

Examples:
>>> input = Tensor(np.array([2.0, 3.1, 1.2]))
>>> index = Argmin()(input)
>>> assert index == Tensor(2, mindspore.int64)
"""

@prim_attr_register
def __init__(self, axis=-1, output_type=mstype.int64):
"""init Argmin"""
self.init_prim_io_names(inputs=['x'], outputs=['output'])
validator.check_type("axis", axis, [int])
self.axis = axis

def infer_shape(self, x_shape):
axis = self.axis
if axis is None:
axis = 0
x_rank = len(x_shape)
validator.check_int_range("axis", axis, -x_rank, x_rank, Rel.INC_LEFT)
axis = axis + x_rank if axis < 0 else axis
ouput_shape = [x_shape[i] for i in range(x_rank) if i != axis]
return ouput_shape

def infer_dtype(self, x_dtype):
validator.check_subclass("input_x", x_dtype, mstype.tensor)
return mstype.tensor_type(self.output_type)

[docs]class ArgMaxWithValue(PrimitiveWithInfer):
"""
Calculates maximum value with corresponding index.

Calculates maximum value along with given axis for the input tensor. Returns the maximum values and indices.

Note:
In auto_parallel and semi_auto_parallel mode, the first output index can not be used.

Args:
axis (int): The dimension to reduce. Default: 0.
keep_dims (bool): Whether to reduce dimension, if true the output will keep same dimension with the input,
the output will reduce dimension if false. Default: False.

Inputs:
- **input_x** (Tensor) - The input tensor, can be any dimension. Set the shape of input tensor as
:math:(x_1, x_2, ..., x_N).

Outputs:
Tensor, corresponding index and maximum value of input tensor. If keep_dims is true, the output tensors shape
is :math:(x_1, x_2, ..., x_{axis-1}, 1, x_{axis+1}, ..., x_N). Else, the shape is
:math:(x_1, x_2, ..., x_{axis-1}, x_{axis+1}, ..., x_N).

Examples:
>>> input = Tensor(np.random.rand(5))
>>> index, output = ArgMaxWithValue()(input)
"""

@prim_attr_register
def __init__(self, axis=0, keep_dims=False):
"""init ArgMaxWithValue"""
self.axis = axis
self.keep_dims = keep_dims
_check_infer_attr_reduce(axis, keep_dims)

def infer_shape(self, x_shape):
axis = self.axis
x_rank = len(x_shape)
validator.check_int_range("axis", axis, -x_rank, x_rank, Rel.INC_LEFT)
ouput_shape = _infer_shape_reduce(x_shape, self.axis, self.keep_dims)
return ouput_shape, ouput_shape

def infer_dtype(self, x_dtype):
validator.check_subclass("input_x", x_dtype, mstype.tensor)
return mstype.tensor_type(mstype.int32), x_dtype

[docs]class ArgMinWithValue(PrimitiveWithInfer):
"""
Calculates minimum value with corresponding index, return indices and values.

Calculates minimum value along with given axis for the input tensor. Returns the minimum values and indices.

Note:
In auto_parallel and semi_auto_parallel mode, the first output index can not be used.

Args:
axis (int): The dimension to reduce. Default: 0.
keep_dims (bool): Whether to reduce dimension, if true the output will keep same dimension as the input,
the output will reduce dimension if false. Default: False.

Inputs:
- **input_x** (Tensor) - The input tensor, can be any dimension. Set the shape of input tensor as
:math:(x_1, x_2, ..., x_N).

Outputs:
Tensor, corresponding index and minimum value of input tensor. If keep_dims is true, the output tensors shape
is :math:(x_1, x_2, ..., x_{axis-1}, 1, x_{axis+1}, ..., x_N). Else, the shape is
:math:(x_1, x_2, ..., x_{axis-1}, x_{axis+1}, ..., x_N).

Examples:
>>> input = Tensor(np.random.rand(5))
>>> index, output = ArgMinWithValue()(input)
"""
@prim_attr_register
def __init__(self, axis=0, keep_dims=False):
"""init ArgMinWithValue"""
self.axis = axis
self.keep_dims = keep_dims
_check_infer_attr_reduce(axis, keep_dims)

def infer_shape(self, x_shape):
axis = self.axis
x_rank = len(x_shape)
validator.check_int_range("axis", axis, -x_rank, x_rank, Rel.INC_LEFT)
ouput_shape = _infer_shape_reduce(x_shape, self.axis, self.keep_dims)
return ouput_shape, ouput_shape

def infer_dtype(self, x_dtype):
validator.check_subclass("input_x", x_dtype, mstype.tensor)
return mstype.tensor_type(mstype.int32), x_dtype

[docs]class Tile(PrimitiveWithInfer):
r"""
Replicates a tensor with given multiples times.

Creates a new tensor by replicating input multiples times. The dimension of
output tensor is the larger of the dimension length of input and the length of multiples.

Inputs:
- **input_x** (Tensor) - 1-D or higher Tensor. Set the shape of input tensor as
:math:(x_1, x_2, ..., x_S).

- **multiples** (tuple[int]) - The input tuple is constructed by multiple
integers, i.e., :math:(y_1, y_2, ..., y_S). The length of multiples
can't be smaller than the length of shape in input_x.

Outputs:
Tensor, has the same type as the input_x.

- If the length of multiples is the same as the length of shape in input_x,
then the shape of their corresponding positions can be multiplied, and
the shape of Outputs is :math:(x_1*y_1, x_2*y_2, ..., x_S*y_R).
- If the length of multiples is larger than the length of shape in input_x,
fill in multiple 1 in front of the shape in input_x until their lengths are consistent.
Such as set the shape of input_x as :math:(1, ..., x_1, x_2, ..., x_S),
then the shape of their corresponding positions can be multiplied, and
the shape of Outputs is :math:(1*y_1, ..., x_S*y_R).
"""

@prim_attr_register
def __init__(self):
"""init Tile"""
self.init_prim_io_names(inputs=['x', 'multiples'], outputs=['output'])

def __infer__(self, x, multiples):
multiples_v = multiples['value']
x_shp = x['shape']
validator.check_const_input("shape", multiples_v)
validator.check_type("shape", multiples_v, [tuple])
for i, multiple in enumerate(multiples_v):
validator.check_type("multiples[%d]" % i, multiple, [int])
validator.check_typename('x', x['dtype'],
[mstype.int16, mstype.int32, mstype.bool_,
mstype.float16, mstype.float32])
len_sub = len(multiples_v) - len(x_shp)
multiples_w = None
if len_sub == 0:
multiples_w = multiples_v
if len_sub > 0:
for i in range(0, len_sub):
x_shp.insert(0, 1)
multiples_w = multiples_v
elif len_sub < 0:
raise ValueError("The length of multiples can not be smaller than the length of dimension in input_x.")
for i, a in enumerate(multiples_w):
x_shp[i] *= a
value = None
if x['value'] is not None:
value = Tensor(np.tile(x['value'].asnumpy(), multiples_w))
return {'shape': x_shp,
'dtype': x['dtype'],
'value': value}

[docs]class UnsortedSegmentSum(PrimitiveWithInfer):
r"""
Computes the sum along segments of a tensor.

Calculates a tensor such that :math:\text{output}[i] = \sum_{segment\_ids[j] == i} \text{data}[j, \ldots], where
:math:j is a tuple describing the index of element in data.  segment_ids selects which elements in data to sum
up. Segment_ids does not need to be sorted, and it does not need to cover all values in the entire valid value
range.

If the sum of the given segment_ids :math:i is empty, then :math:\text{output}[i] = 0. If the given segment_ids
is negative, the value will be ignored. 'num_segments' should be equal to the number of different segment_ids.

Inputs:
- **input_x** (Tensor) - The shape is :math:(x_1, x_2, ..., x_R).
- **segment_ids** (Tensor) - Set the shape as :math:(x_1, x_2, ..., x_N), where 0 < N <= R. Type must be int.
- **num_segments** (int) - Set :math:z as num_segments.

Outputs:
Tensor, the shape is :math:(z, x_{N+1}, ..., x_R).

Examples:
>>> input_x = [1, 2, 3, 4]
>>> segment_ids = [0, 0, 1, 2]
>>> num_segments = 4
>>> type = P.UnsortedSegmentSum()(input_x, segment_ids, num_segments)
"""

@prim_attr_register
def __init__(self):
"""init UnsortedSegmentSum"""
self.init_prim_io_names(inputs=['x', 'segment_ids', 'num_segments'], outputs=['y'])

def __infer__(self, x, segment_ids, num_segments):
x_type = x['dtype']
x_shp = x['shape']
validator.check_subclass("input_x", x_type, mstype.tensor)
validator.check_type("x_shape", x_shp, [list])
x_shp_len = len(x_shp)
validator.check_integer("rank of input_x", x_shp_len, 0, Rel.GT)
segment_ids_shp = segment_ids['shape']
segment_ids_type = segment_ids['dtype']
validator.check_subclass("segment_ids", segment_ids_type, mstype.tensor)
validator.check_type("segment_ids", segment_ids_shp, [list])
segment_ids_shp_len = len(segment_ids_shp)
validator.check_integer("rank of segment_ids", segment_ids_shp_len, 0, Rel.GT)
validator.check(f'rank of input_x', len(x_shp),
'rank of segments_id', len(segment_ids_shp), Rel.GE)
for i, value in enumerate(segment_ids_shp):
validator.check("ids[%d]" % i, value, 'input[%d]' % i, x_shp[i])
num_segments_v = num_segments['value']
validator.check_type('num_segments', num_segments_v, [int])
validator.check_integer("num_segments", num_segments_v, 0, Rel.GT)
shp = [num_segments_v]
shp += x_shp[segment_ids_shp_len:]
out = {'shape': shp,
'dtype': mstype.tensor_type(x_type.element_type()),
'value': None}
return out

def _get_concat_offset(x_shp, x_type, axis):
"""for concat and concatoffset check args and compute offset"""
validator.check_type("shape", x_shp, [tuple])
validator.check_integer("len of input_x shape", len(x_shp), 0, Rel.GT)
validator.check_subclass("shape0", x_type[0], mstype.tensor)
validator.check_integer("len of input_x0 shape", len(x_shp[0]), 0, Rel.GT)
rank_base = len(x_shp[0])
validator.check_int_range('axis', axis, -rank_base - 1, rank_base, Rel.INC_BOTH)
if axis < 0:
axis = axis + rank_base
all_shp = x_shp[0][axis]
offset = [0,]
for i in range(1, len(x_shp)):
v = x_shp[i]
validator.check('len of x_shp[%d]' % i, len(v), 'len of base', len(x_shp[0]))
validator.check('x_type[%d]' % i, x_type[i], 'base', x_type[0])
for j in range(rank_base):
if j != axis and v[j] != x_shp[0][j]:
raise ValueError("Concat evaluator element %d shape in input can not concat with first element" % i)
offset.append(all_shp)
all_shp += v[axis]
return offset, all_shp, axis

[docs]class Concat(PrimitiveWithInfer):
r"""
Concat tensor in specified axis.

Concat input tensors along with the given axis.

Note:
The input data is a tuple of tensors. These tensors have the same rank R. Set the given axis as m, and
:math:0 \le m < N. Set the number of input tensors as N. For the :math:i-th tensor :math:t_i has
the shape :math:(x_1, x_2, ..., x_{mi}, ..., x_R). :math:x_{mi} is the :math:m-th dimension of the
:math:i-th tensor. Then, the output tensor shape is

.. math::
(x_1, x_2, ..., \sum_{i=1}^Nx_{mi}, ..., x_R)

Args:
axis (int): The specified axis. Default: 0.

Inputs:
- **input_x** (tuple, list) - Tuple or list of input tensors.

Outputs:
Tensor, the shape is :math:(x_1, x_2, ..., \sum_{i=1}^Nx_{mi}, ..., x_R).

Examples:
>>> data1 = Tensor(np.array([[0, 1], [2, 1]]).astype(np.int32))
>>> data2 = Tensor(np.array([[0, 1], [2, 1]]).astype(np.int32))
>>> op = Concat()
>>> output = op((data1, data2))
"""

@prim_attr_register
def __init__(self, axis=0):
"""init Tile"""
self.__setattr_flag__ = True
validator.check_type("axis", axis, [int])

def __infer__(self, input_x):
axis = self.axis
x_shp = input_x['shape']
x_type = input_x['dtype']
_, all_shp, _ = _get_concat_offset(x_shp, x_type, axis)
ret_shp = x_shp[0].copy()
ret_shp[axis] = all_shp
out = {'shape': ret_shp,
'dtype': x_type[0],
'value': None}
return out

[docs]class Slice(PrimitiveWithInfer):
"""
Slice a tensor in specified shape.

Args:
x (Tensor): The target tensor.
begin (tuple): The beginning of the slice. Only constant value is allowed.
size (tuple): The size of the slice. Only constant value is allowed.

Returns:
Tensor.

Examples:
>>> data = Tensor(np.array([3,2,3]).astype(np.int32))
>>> type = P.Slice()(data, (1, 0, 0), (1, 1, 3))
"""

@prim_attr_register
def __init__(self):
"""init slice"""
self.init_prim_io_names(inputs=['x', 'begin', 'size'], outputs=['output'])

def __infer__(self, x, begin, size):
x_shape = x['shape']
x_shp_len = len(x_shape)
validator.check_const_input('begin', begin['value'])
validator.check_const_input('size', size['value'])
begin_v, size_v = begin['value'], size['value']
if begin_v is None or size_v is None:
return {'shape': None,
'dtype': x['dtype'],
'value': None}
for key, value in zip(('begin', 'size'), (begin_v, size_v)):
validator.check(f'len of {key}', len(value),
'len x\'s dim', x_shp_len)
for i in range(x_shp_len):
if x_shape[i] < begin_v[i] + size_v[i]:
y = begin_v[i] + size_v[i]
raise ValueError("Slice shape can not bigger than orign shape %d, %d." % (x_shape[i], y))
return {'shape': size_v,
'dtype': x['dtype'],
'value': None}

[docs]class ConcatOffset(PrimitiveWithInfer):

@prim_attr_register
def __init__(self, N=2, axis=0):
"""init ConcatOffset"""

def __infer__(self, input_x):
axis = self.axis
x_shp = input_x['shape']
x_type = input_x['dtype']
offset, _, axis = _get_concat_offset(x_shp, x_type, axis)
offset_values = []
for i in range(len(x_shp)):
values = []
for j in range(len(x_shp[0])):
value = 0
if j == axis:
value = offset[i]
values.append(value)
offset_values.append(tuple(values))
out = {'shape': None,
'dtype': None,
'value': tuple(offset_values)}
return out

[docs]class Select(PrimitiveWithInfer):
r"""

Return the selected elements, either from input :math:x or input :math:y, depending on the condition.

Given a tensor as input, this operation inserts a dimension of 1 at the dimension,
if both :math:x and :math:y are none, the operation returns the coordinates of the true
element in the condition, the coordinates are returned as a two-dimensional
tensor, where the first dimension (row) represents the number of true elements
and the second dimension (columns) represents the coordinates of the true
elements. Keep in mind that the shape of the output tensor can vary depending
on how much of the true value is in the input. Indexes are output in row-first
order.

If neither is None, :math:x and :math:y must have the same shape. If :math:x and :math:y are
scalars, the conditional tensor must be a scalar. If :math:x and :math:y are
higher-demensional vectors, the condition must be a vector whose size matches the
first dimension of :math:x, or must have the same shape as :math:y.

The conditional tensor acts as an optional compensation (mask), which
determines whether the corresponding element / row in the output should be
selected from :math:x (if true) or :math:y (if false) based on the value of each
element.

If condition is a vector, then :math:x and :math:y are higher-demensional matrices, then it
chooses to copy that row (external dimensions) from :math:x and :math:y. If condition has
the same shape as :math:x and :math:y, you can choose to copy these elements from :math:x
and :math:y.

Inputs:
- **input_x** (Tensor[bool]) - The shape is :math:(x_1, x_2, ..., x_N).
The condition tensor, decides whose element is chosen.
- **input_y** (Tensor) - The shape is :math:(x_1, x_2, ..., x_N, ..., x_R).
The first input tensor.
- **input_z** (Tensor) - The shape is :math:(x_1, x_2, ..., x_N, ..., x_R).
The second input tensor.

Outputs:
Tensor, has the same shape as input_y. The shape is :math:(x_1, x_2, ..., x_N, ..., x_R).

Examples:
>>> select = Select()
>>> input_x = Tensor([True, False])
>>> input_y = Tensor([2,3], mindspore.float32)
>>> input_z = Tensor([1,2], mindspore.float32)
>>> select(input_x, input_y, input_z)
"""

@prim_attr_register
def __init__(self):
"""init"""
self.__setattr_flag__ = True

def infer_shape(self, cond_shape, x_shape, y_shape):
if cond_shape != x_shape or x_shape != y_shape:
raise ValueError('The x_shape and y_shape must be the same as cond_shape.')
return x_shape

def infer_dtype(self, cond_type, x_type, y_type):
validator.check_subclass("x_type", x_type, mstype.tensor)
validator.check_subclass("y_type", y_type, mstype.tensor)
validator.check_typename("cond_type", cond_type, [mstype.bool_])
if x_type != y_type:
raise TypeError('The x_type %s must be the same as y_type %s.' % (x_type, y_type))
return x_type

[docs]class StridedSlice(PrimitiveWithInfer):
r"""

Extracts a strided slice of a tensor.

Given an input tensor, this operation inserts a dimension of length 1 at the dimension.
This operation extracts a fragment of size (end-begin)/stride from the given
'input_tensor'. Starting from the position specified by the begin, the fragment
continues adding stride to the index until all dimensions are not less than end.

Note:
The stride may be negative value, which causes reverse slicing.
The shape of begin, end and strides should be the same.

Args:
begin_mask (int): Starting index of the slice. Default: 0.
end_mask (int): Ending index of the slice. Default: 0.

Inputs:
- **input_x** (Tensor) - The input Tensor.
- **begin** (tuple[int]) - A tuple which represents the location where to start. Only
constant value is allowed.
- **end** (tuple[int]) - A tuple or which represents the maximum location where to stop.
Only constant value is allowed.
- **strides** (tuple[int]) - A tuple which represents the stride continuously added
before reach the maximum location. Only constant value is allowed.

Outputs:
Tensor.
Explain with the following example.
- In the 0th dim, begin is 1, end is 2, and strides is 1,
because :math:1+1=2\geq2, the interval is :math:[1,2).
Thus, return the element with :math:index = 1 in 0th dim, i.e., [[3, 3, 3], [4, 4, 4]].
- In the 1st dim, similarly, the interval is :math:[0,1).
Based on the return value of the 0th dim, return the element with :math:index = 0,
i.e., [3, 3, 3].
- In the 2nd dim, similarly, the interval is :math:[0,3).
Based on the return value of the 1st dim, return the element with :math:index = 0,1,2,
i.e., [3, 3, 3].
- Finally, the output is [3, 3, 3].

Examples
>>> input_x = Tensor([[[1, 1, 1], [2, 2, 2]], [[3, 3, 3], [4, 4, 4]], [[5, 5, 5], [6, 6, 6]]])
>>> slice = StridedSlice()
>>> output = slice(input_x, (1, 0, 0), (2, 1, 3), (1, 1, 1))
>>> output.shape()
(1, 1, 3)
>>> output
[[[3, 3, 3]]]
"""

@prim_attr_register
def __init__(self,
"""init StrideSlice"""
self.init_prim_io_names(inputs=['x', 'begin', 'end', 'strides'], outputs=['output'])

def __infer__(self, x, begin, end, strides):
begin_shape, end_shape, strides_shape = begin['shape'], end['shape'], strides['shape']
if begin_shape != strides_shape or end_shape != strides_shape:
raise ValueError("The shape of begin, end and strides in 'StridedSlice' must be equal.")

validator.check_const_input("begin", begin['value'])
validator.check_const_input("end", end['value'])
validator.check_const_input("strides", strides['value'])
validator.check_type("begin", begin['value'], [tuple])
validator.check_type("end", end['value'], [tuple])
validator.check_type("strides", strides['value'], [tuple])

x_shape = x['shape']
x_shp_len = len(x_shape)
begin_v, end_v, strides_v = begin['value'], end['value'], strides['value']
ret_shape = []
append_dimensions = []
for i in range(x_shp_len):
# After the integer is converted to binary, it is a str and the first two chars are the flag char '0b'
if i < (len(new_pos) - 2) and new_pos[i] == '1':
ret_shape.append(1)
append_dimensions.append(x_shape[x_shp_len - 1 - len(append_dimensions)])
continue
if i < (len(shrink_pos) - 2) and shrink_pos[i] == '1':
validator.check_integer(f'begin[{i}]', begin_v[i], -x_shape[i], Rel.GE)
validator.check_integer(f'begin[{i}]', begin_v[i], x_shape[i], Rel.LT)
continue

begin_idx = begin_v[i]
end_idx = end_v[i]
strides_idx = strides_v[i]
begin_idx = 0
end_idx = x_shape[i]
validator.check_integer(f'begin[{i}]', begin_idx, x_shape[i], Rel.LE)
validator.check_integer(f'end[{i}]', end_idx, x_shape[i], Rel.LE)
validator.check_integer(f'strides[{i}]', strides_idx, 0, Rel.NE)
if strides_idx > 0:
# If sliced forward , end_idx >= begin_idx
validator.check(f'begin[{i}]', begin_idx, f'end[{i}]', end_idx, Rel.LE)
if begin_idx < 0 < end_idx:
# Turn negative begin_idx into positive values
begin_idx = x_shape[i] + begin_idx
num_elems = (end_idx - begin_idx + strides_idx - 1) // strides_idx
else:
# If sliced backwards, end_idx <= begin_idx
validator.check(f'begin[{i}]', begin_idx, f'end[{i}]', end_idx, Rel.GE)
if end_idx < 0 < begin_idx:
# Turn negative end_idx into positive values
end_idx = x_shape[i] + end_idx
num_elems = (end_idx - begin_idx + strides_idx + 1) // strides_idx

ret_shape.append(num_elems)
if append_dimensions:
ret_shape += append_dimensions[::-1]
return {'shape': ret_shape,
'dtype': x['dtype'],
'value': None}

[docs]class Diag(PrimitiveWithInfer):
r"""

Construct a diagonal tensor with a given diagonal values.

Assume input_x has dimensions :math:[D_1,... D_k], the output is a tensor of
rank 2k with dimensions :math:[D_1,..., D_k, D_1,..., D_k] where:
:math:output[i_1,..., i_k, i_1,..., i_k] = input_x[i_1,..., i_k] and 0 everywhere else.

Inputs:
- **input_x** (Tensor) - The input tensor.

Outputs:
Tensor.

Examples:
>>> input_x = Tensor([1, 2, 3, 4])
>>> diag = P.Diag()
>>> diag(x)
[[1, 0, 0, 0],
[0, 2, 0, 0],
[0, 0, 3, 0],
[0, 0, 0, 4]]
"""

@prim_attr_register
def __init__(self):
"""init Diag"""

def infer_dtype(self, x_type):
validator.check_subclass('input_x', x_type, mstype.tensor)
return x_type

def infer_shape(self, x_shape):
validator.check("x rank", len(x_shape), "", 1, Rel.GE)
ret_shape = copy.deepcopy(x_shape)
ret_shape = ret_shape + ret_shape
return ret_shape

def infer_value(self, x):
if x is None:
return None
validator.check("input x rank", len(x.shape()), "", 1)
ret = np.diag(x.asnumpy())
return Tensor(ret)

[docs]class DiagPart(PrimitiveWithInfer):
r"""

Extract the diagonal part from given tensor.

Assume input has dimensions :math:[D_1,..., D_k, D_1,..., D_k], the output is a tensor
of rank k with dimensions :math:[D_1,..., D_k] where:
:math:output[i_1,..., i_k] = input[i_1,..., i_k, i_1,..., i_k].

Inputs:
- **input_x** (Tensor) - The input Tensor.

Outputs:
Tensor.

Examples
>>> input_x = Tensor([[1, 0, 0, 0],
>>>                   [0, 2, 0, 0],
>>>                   [0, 0, 3, 0],
>>>                   [0, 0, 0, 4]])
>>> diag_part = P.DiagPart()
>>> diag_part(x)
[1, 2, 3, 4]
"""

@prim_attr_register
def __init__(self):
"""init DiagPart"""

def infer_dtype(self, x_type):
validator.check_subclass('input_x', x_type, mstype.tensor)
return x_type

def infer_shape(self, x_shape):
if len(x_shape)%2 !=0 or \
not x_shape:
raise ValueError(f"DiagPart input rank must be non-zero and even, but got rank {len(x_shape)}, "
f"with shapes {x_shape}")
length = len(x_shape) // 2
ret_shape = x_shape[0:length]
return ret_shape

def infer_value(self, x):
if x is None:
return None
validator.check("x rank", len(x.shape()), "", 2)
ret = np.diag(x.asnumpy())
return Tensor(ret)

[docs]class Eye(PrimitiveWithInfer):
"""

Creates a tensor with ones on the diagonal and zeros elsewhere.

Inputs:
- **n** (int) - Number of rows of returned tensor
- **m** (int) - Number of columns of returned tensor
- **t** (mindspore.dtype) - Mindspore's dtype, The data type of the returned tensor.

Outputs:
Tensor, a tensor with ones on the diagonal and zeros elsewhere.

Examples:
>>> eye = P.Eye()
>>> out_tensor = eye(2, 2, mindspore.int32)
"""

@prim_attr_register
def __init__(self):
"""init Eye"""

def infer_value(self, n, m, t):
validator.check_type("n", n, [int])
validator.check_integer("n", n, 0, Rel.GT)
validator.check_type("m", m, [int])
validator.check_integer("m", m, 0, Rel.GT)
args = {"dtype": t}
validator.check_type_same(args, mstype.number_type + (mstype.bool_,))
np_type = mstype.dtype_to_nptype(t)
ret = np.eye(n, m, dtype=np_type)
return Tensor(ret)

[docs]class ScatterNd(PrimitiveWithInfer):
"""
Scatters a tensor into a new tensor depending on the specified indices.

Creates an empty tensor, and set values by scattering the update tensor depending on indices.

Inputs:
- **indices** (Tensor) - The index of scattering in the new tensor.
- **update** (Tensor) - The source Tensor to be scattered.
- **shape** (tuple[int]) - Define the shape of the output tensor. Has the same type as indices.

Outputs:
Tensor, the new tensor, has the same type as update and the same shape as shape.

Examples:
>>> op = ScatterNd()
>>> update = Tensor(np.array([3.2, 1.1]), mindspore.float32)
>>> indices = Tensor(np.array([[0, 1], [1, 1]]), mindspore.int32)
>>> shape = (3, 3)
>>> output = op(indices, update, shape)
"""

@prim_attr_register
def __init__(self):
"""Init ScatterNd"""
self.init_prim_io_names(inputs=['indices', 'update', 'shape'], outputs=['output'])

def __infer__(self, indices, update, shape):
shp = shape['value']
validator.check_subclass("indices_dtype", indices['dtype'], mstype.tensor)
validator.check_subclass("update_dtype", update['dtype'], mstype.tensor)
validator.check_typename("indices_dtype", indices['dtype'], mstype.int_type)
validator.check_type("shape", shp, [tuple])
for i, x in enumerate(shp):
validator.check_integer("shape[%d]" % i, x, 0, Rel.GT)

indices_shape, update_shape = indices["shape"], update["shape"]
if indices_shape[0] != update_shape[0]:
raise ValueError('The indices_shape[0] and update_shape[0] must be equal.')

return {'shape': shp,
'dtype': update['dtype'],
'value': None}

[docs]class ResizeNearestNeighbor(PrimitiveWithInfer):
"""
Resize the input tensor by using nearest neighbor algorithm.

Resize input tensor to given size by using nearest neighbor algorithm. The nearest
neighbor algorithm selects the value of the nearest point and does not consider the
values of neighboring points at all, yielding a piecewise-constant interpolant.

Args:
size (Union[tuple, list]): The target size. The dimension of size must be 2.
align_corners (bool): Whether the centers of the 4 corner pixels of the input
and output tensors are aligned. Default: False.

Inputs:
- **input_x** (Tensor) - The input tensor. The shape of the tensor is :math:(N, C, H, W).

Outputs:
Tensor, the shape of the output tensor is :math:(N, NEW_C, NEW_H, W).

Examples:
>>> input_tensor = Tensor(np.array([[-0.1, 0.3, 3.6], [0.4, 0.5, -3.2]]), mindspore.float32)
>>> resize = ResizeNearestNeighbor((2, 2))
>>> output = resize(input_tensor)
"""

@prim_attr_register
def __init__(self, size, align_corners=False):
"""Init ResizeNearestNeighbor"""
self.init_prim_io_names(inputs=['image_in'], outputs=['image_out'])

def infer_shape(self, x):
validator.check('the dimension of input_x', len(x), '', 2, Rel.GE)
return tuple(x)[:-2] + tuple(self.size)

def infer_dtype(self, x):
return x

[docs]class GatherNd(PrimitiveWithInfer):
"""
Gathers slices from a tensor by indices.

Using given indices to gather slices from a tensor with a specified shape.

Inputs:
- **input_x** (Tensor) - The target tensor to gather values.
- **indices** (Tensor) - The index tensor.

Outputs:
Tensor, has the same type as input_x and the shape is indices_shape[:-1] + x_shape[indices_shape[-1]:].

Examples:
>>> input_x = Tensor(np.array([[-0.1, 0.3, 3.6], [0.4, 0.5, -3.2]]), mindspore.float32)
>>> indices = Tensor(np.array([[0, 0], [1, 1]]), mindspore.int32)
>>> op = GatherNd()
>>> output = op(input_x, indices)
"""

@prim_attr_register
def __init__(self):
"""Init GatherNd"""
self.init_prim_io_names(inputs=['input_x', 'indices'], outputs=['y'])

def infer_shape(self, x_shape, indices_shape):
validator.check('the dimension of x', len(x_shape),
'the dimension of indices', indices_shape[-1], Rel.GE)
return indices_shape[:-1] + x_shape[indices_shape[-1]:]

def infer_dtype(self, x_dtype, indices_dtype):
validator.check_subclass("x_dtype", x_dtype, mstype.tensor)
validator.check_subclass("indices_dtype", indices_dtype, mstype.tensor)
validator.check_typename("indices_dtype", indices_dtype, mstype.int_type)
return x_dtype

[docs]class ScatterNdUpdate(PrimitiveWithInfer):
"""
Update tensor value by using input indices and value.

Using given values to update tensor value, along with the input indices.

Args:
use_locking (bool): Whether protect the assignment by a lock. Defaule: True.

Inputs:
- **input_x** (Tensor) - The target tensor.
- **indices** (Tensor) - The index of input tensor.
- **update** (Tensor) - The tensor to add to the input tensor, has the same type as input.

Outputs:
Tensor, has the same shape and type as input_x.

Examples:
>>> input_x = Tensor(np.array([[-0.1, 0.3, 3.6], [0.4, 0.5, -3.2]]), mindspore.float32)
>>> indices = Tensor(np.array([[0, 0], [1, 1]]), mindspore.int32)
>>> update = Tensor(np.array([1.0, 2.2]), mindspore.float32)
>>> op = ScatterNdUpdate()
>>> output = op(input_x, indices, update)
"""

@prim_attr_register
def __init__(self, use_locking=True):
"""Init ScatterNdUpdate"""
self.init_prim_io_names(inputs=['x', 'indices', 'value'], outputs=['y'])

def infer_shape(self, x_shape, indices_shape, value_shape):
validator.check('the dimension of x', len(x_shape),
'the dimension of indices', indices_shape[-1], Rel.GE)
if indices_shape[:-1] + x_shape[indices_shape[-1]:] != value_shape:
raise ValueError('Input value are not match with input indices.')
return x_shape

def infer_dtype(self, x_dtype, indices_dtype, value_dtype):
validator.check_subclass("x_dtype", x_dtype, mstype.tensor)
validator.check_subclass("indices_dtype", indices_dtype, mstype.tensor)
validator.check_subclass("value_dtype", value_dtype, mstype.tensor)
validator.check_typename('indices_dtype', indices_dtype, mstype.int_type)
args = {"x_dtype": x_dtype, "value_dtype": value_dtype}
validator.check_type_same(args, (mstype.bool_,) + mstype.number_type)
return x_dtype

[docs]class SpaceToDepth(PrimitiveWithInfer):
r"""
Rearrange blocks of spatial data into depth.

The output tensor's height dimension is :math:height / block\_size.

The output tensor's weight dimension is :math:weight / block\_size.

The depth of output tensor is :math:block\_size * block\_size * input\_depth.

The input tensor's height and width must be divisible by block_size.
The data format is "NCHW".

Args:
block_size (int): The block size used to divide spatial data. It must be >= 2.

Inputs:
- **x** (Tensor) - The target tensor.

Outputs:
Tensor, the same type as x.

Examples:
>>> x = Tensor(np.random.rand(1,3,2,2), mindspore.float32)
>>> block_size = 2
>>> op = SpaceToDepth(block_size)
>>> output = op(x)
>>> output.asnumpy().shape == (1,12,1,1)
"""

@prim_attr_register
def __init__(self, block_size):
"""Init SpaceToDepth"""
self.init_prim_io_names(inputs=['x'], outputs=['y'])
validator.check_type('block_size', block_size, [int])
validator.check('block_size', block_size, '', 2, Rel.GE)
self.block_size = block_size

def infer_shape(self, x_shape):
validator.check('x dimension', len(x_shape), '', 4, Rel.EQ)
out_shape = copy.deepcopy(x_shape)
for i in range(2):
if out_shape[i+2] % self.block_size != 0:
raise ValueError(f'SpaceToDepth input shape[{i+2}] {out_shape[i+2]} should be '
f'fully divided by block_size {self.block_size}')
out_shape[i+2] //= self.block_size

out_shape[1] *= self.block_size * self.block_size
return out_shape

def infer_dtype(self, x_dtype):
validator.check_subclass("x_dtype", x_dtype, mstype.tensor)
return x_dtype

[docs]class DepthToSpace(PrimitiveWithInfer):
r"""
Rearrange blocks of depth data into spatial dimensions.

This is the reverse operation of SpaceToDepth.

The output tensor's height dimension is :math:height * block\_size.

The output tensor's weight dimension is :math:weight * block\_size.

The depth of output tensor is :math:input\_depth / (block\_size * block\_size).

The input tensor's depth must be divisible by block_size * block_size.
The data format is "NCHW".

Args:
block_size (int): The block size used to divide depth data. It must be >= 2.

Inputs:
- **x** (Tensor) - The target tensor.

Outputs:
Tensor, the same type as x.

Examples:
>>> x = Tensor(np.random.rand(1,12,1,1), mindspore.float32)
>>> block_size = 2
>>> op = DepthToSpace(block_size)
>>> output = op(x)
>>> output.asnumpy().shape == (1,3,2,2)
"""

@prim_attr_register
def __init__(self, block_size):
"""Init DepthToSpace"""
self.init_prim_io_names(inputs=['x'], outputs=['y'])
validator.check_type('block_size', block_size, [int])
validator.check('block_size', block_size, '', 2, Rel.GE)
self.block_size = block_size

def infer_shape(self, x_shape):
validator.check('x dimension', len(x_shape), '', 4, Rel.EQ)
out_shape = copy.deepcopy(x_shape)
for i in range(2):
out_shape[i+2] *= self.block_size

validator.check('x_shape[1] % (block_size*block_size)', x_shape[1] % (self.block_size*self.block_size), '', 0)
out_shape[1] //= self.block_size * self.block_size
return out_shape

def infer_dtype(self, x_dtype):
validator.check_subclass("x_dtype", x_dtype, mstype.tensor)
return x_dtype