1 /**
2 * Copyright 2023 Huawei Technologies Co., Ltd
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "ops/ops_func_impl/tile.h"
18
19 #include <algorithm>
20 #include <memory>
21 #include "ir/functor.h"
22 #include "mindapi/base/shape_vector.h"
23 #include "ops/op_utils.h"
24 #include "ops/op_name.h"
25 #include "plugin/device/cpu/kernel/nnacl/op_base.h"
26 #include "utils/check_convert_utils.h"
27 #include "utils/convert_utils_base.h"
28 #include "utils/shape_utils.h"
29 #include "utils/log_adapter.h"
30 #include "ir/primitive.h"
31 #include "abstract/dshape.h"
32 #include "base/base.h"
33 #include "ir/dtype/number.h"
34
35 namespace mindspore::ops {
36 namespace {
ToMultiplesVector(const ArrayValue<int64_t> & array_value)37 ShapeVector ToMultiplesVector(const ArrayValue<int64_t> &array_value) {
38 auto len = array_value.size();
39 ShapeVector multiples_vec;
40 multiples_vec.reserve(len);
41 for (size_t i = 0; i < len; ++i) {
42 if (array_value.IsValueUnknown(i)) {
43 multiples_vec.push_back(abstract::Shape::kShapeDimAny);
44 continue;
45 }
46
47 if (array_value[i] < 0) {
48 MS_EXCEPTION(ValueError) << "For 'Tile', 'dims' cannot contain negative integer numbers, but got "
49 << array_value[i] << " in " << i << "th.";
50 }
51 multiples_vec.push_back(array_value[i]);
52 }
53
54 return multiples_vec;
55 }
56 } // namespace
AdaptShapeAndMultipies(ShapeVector * shape,ShapeVector * dims)57 void AdaptShapeAndMultipies(ShapeVector *shape, ShapeVector *dims) {
58 MS_EXCEPTION_IF_NULL(shape);
59 if (MS_UNLIKELY(IsDynamicRank(*shape))) {
60 MS_LOG(INTERNAL_EXCEPTION) << "Shape should not be dynamic rank!";
61 }
62 MS_EXCEPTION_IF_NULL(dims);
63
64 auto rank = shape->size();
65 auto len = dims->size();
66 if (len == rank) {
67 return;
68 }
69
70 auto expect_len = std::max(rank, len);
71 auto ExpandInHeadIfNeed = [](ShapeVector *vec, size_t length) -> void {
72 if (vec->size() == length) {
73 return;
74 }
75
76 auto offset = length - vec->size();
77 ShapeVector res;
78 vec->reserve(length);
79 vec->insert(vec->begin(), offset, 1);
80 };
81
82 ExpandInHeadIfNeed(shape, expect_len);
83 ExpandInHeadIfNeed(dims, expect_len);
84 }
85
InferShape(const PrimitivePtr & primitive,const std::vector<AbstractBasePtr> & input_args) const86 BaseShapePtr TileFuncImpl::InferShape(const PrimitivePtr &primitive,
87 const std::vector<AbstractBasePtr> &input_args) const {
88 // The output rank is determined by data's rank and dims's length.
89 auto x_base_shape = input_args[kInputIndex0]->GetShape();
90 auto x_shape = x_base_shape->GetShapeVector();
91 if (MS_UNLIKELY(IsDynamicRank(x_shape))) {
92 return std::make_shared<abstract::TensorShape>(ShapeVector{abstract::TensorShape::kShapeRankAny});
93 }
94
95 auto dims_base_shape = input_args[kInputIndex1]->GetShape();
96 if (MS_UNLIKELY(dims_base_shape->isa<abstract::DynamicSequenceShape>())) {
97 return std::make_shared<abstract::TensorShape>(ShapeVector{abstract::TensorShape::kShapeRankAny});
98 }
99
100 auto dims_array_opt = GetArrayValue<int64_t>(input_args[kInputIndex1]);
101 MS_CHECK_VALUE(dims_array_opt.has_value(),
102 CheckAndConvertUtils::FormatCommMsg("For primitive[Tile], the dims must has value here."));
103 auto dims_array = dims_array_opt.value();
104 auto dims = ToMultiplesVector(dims_array);
105
106 AdaptShapeAndMultipies(&x_shape, &dims);
107 auto adapted_rank = x_shape.size();
108 ShapeVector inferred_shape;
109 inferred_shape.reserve(adapted_rank);
110 for (size_t i = 0; i < adapted_rank; ++i) {
111 if (x_shape[i] == abstract::Shape::kShapeDimAny || dims[i] == abstract::Shape::kShapeDimAny) {
112 inferred_shape.push_back(abstract::Shape::kShapeDimAny);
113 continue;
114 }
115
116 inferred_shape.push_back(dims[i] * x_shape[i]);
117 }
118 return std::make_shared<abstract::TensorShape>(inferred_shape);
119 }
120
InferType(const PrimitivePtr & primitive,const std::vector<AbstractBasePtr> & input_args) const121 TypePtr TileFuncImpl::InferType(const PrimitivePtr &primitive, const std::vector<AbstractBasePtr> &input_args) const {
122 auto input_type = input_args[kInputIndex0]->GetType();
123 return input_type->Clone();
124 }
125 } // namespace mindspore::ops
126