Imported Upstream version 1.12.0
[platform/core/ml/nnfw.git] / compiler / luci / service / src / CircleShapeSignatureInferenceHelper.cpp
1 /*
2  * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
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 "luci/Service/CircleShapeSignatureInferenceHelper.h"
18
19 #include <loco.h>
20
21 #include <luci/Log.h>
22
23 #include <oops/InternalExn.h>
24
25 namespace luci
26 {
27
28 namespace ssinf
29 {
30
31 luci::ShapeSignature legalized_signature(const luci::ShapeSignature &signature)
32 {
33   // If shape signature has at least one -1, it is not static.
34   for (uint32_t i = 0; i < signature.rank(); ++i)
35     if (signature.dim(i) == -1)
36       return signature;
37
38   // If all dimensions are static, return empty shape signature.
39   return luci::ShapeSignature();
40 }
41
42 ShapeSignature reduced_signature(const loco::Node *node, const loco::Node *indices, bool keep_dims)
43 {
44   LOGGER(l);
45
46   ShapeSignature input_signature;
47   ShapeSignature output_signature;
48
49   auto circle_node = loco::must_cast<const luci::CircleNode *>(node);
50   if (circle_node->shape_signature().rank() > 0)
51     input_signature = circle_node->shape_signature();
52   else
53   {
54     input_signature.rank(circle_node->rank());
55     for (uint32_t i = 0; i < circle_node->rank(); ++i)
56       input_signature.dim(i) = circle_node->dim(i).value();
57   }
58
59   // If input rank is 0, it means that one of following case is occurred.
60   // - Input is scalar : result is always scalar
61   // - Input shape signature is not inferenced : cannot infer output shape signauture
62   // Therefore, when input signature rank is 0, always return empty signature.
63   if (input_signature.rank() == 0)
64     return output_signature;
65
66   // When reduction_indices is not constant
67   auto reduction_indices = dynamic_cast<const luci::CircleConst *>(indices);
68   if (reduction_indices == nullptr)
69   {
70     if (keep_dims)
71     {
72       // If keep_dims is true, rank is not changed.
73       output_signature.rank(input_signature.rank());
74       for (uint32_t i = 0; i < output_signature.rank(); ++i)
75         output_signature.dim(i) = -1;
76     }
77     else
78     {
79       // There is no way to inference for this case.
80       // Do nothing to return empty signature.
81       INFO(l) << "[CircleShapeSignatureInferenceHelper] " << circle_node->name() << std::endl;
82       INFO(l) << " reduced_signature : cannot infer because of non-constant node" << std::endl;
83     }
84
85     return output_signature;
86   }
87
88   std::vector<int32_t> reduction_values;
89   if (reduction_indices->dtype() == loco::DataType::S32)
90   {
91     auto reduction_size = reduction_indices->size<loco::DataType::S32>();
92     for (uint32_t i = 0; i < reduction_size; ++i)
93     {
94       int32_t axis = reduction_indices->at<loco::DataType::S32>(i);
95       if (axis < 0)
96         axis += input_signature.rank();
97
98       if (!(0 <= axis && axis < static_cast<int32_t>(input_signature.rank())))
99         INTERNAL_EXN_V("Invalid reduction axis for REDUCER", oops::to_uint32(axis));
100
101       reduction_values.push_back(axis);
102     }
103   }
104   else if (reduction_indices->dtype() == loco::DataType::S64)
105   {
106     auto reduction_size = reduction_indices->size<loco::DataType::S64>();
107     for (uint32_t i = 0; i < reduction_size; ++i)
108     {
109       int32_t axis = static_cast<int32_t>(reduction_indices->at<loco::DataType::S64>(i));
110       if (axis < 0)
111         axis += input_signature.rank();
112
113       if (!(0 <= axis && axis < static_cast<int32_t>(input_signature.rank())))
114         INTERNAL_EXN_V("Invalid reduction axis for REDUCER", oops::to_uint32(axis));
115
116       reduction_values.push_back(axis);
117     }
118   }
119   else
120   {
121     INTERNAL_EXN("Wrong reduction axis type, Only INT32, INT64 supported.");
122   }
123
124   if (keep_dims)
125   {
126     output_signature.rank(input_signature.rank());
127     for (uint32_t i = 0; i < input_signature.rank(); ++i)
128       output_signature.dim(i) = input_signature.dim(i);
129     for (uint32_t i = 0; i < reduction_values.size(); ++i)
130       output_signature.dim(reduction_values.at(i)) = 1;
131   }
132   else
133   {
134     std::vector<bool> check_reduce(input_signature.rank(), false);
135     for (uint32_t i = 0; i < reduction_values.size(); ++i)
136       check_reduce.at(reduction_values.at(i)) = true;
137
138     uint32_t reduce_cnt = 0;
139     for (uint32_t i = 0; i < check_reduce.size(); ++i)
140       if (check_reduce.at(i))
141         ++reduce_cnt;
142
143     output_signature.rank(input_signature.rank() - reduce_cnt);
144     for (uint32_t i = 0, j = 0; i < check_reduce.size(); ++i)
145       if (check_reduce.at(i) == false)
146         output_signature.dim(j++) = input_signature.dim(i);
147   }
148
149   return output_signature;
150 }
151
152 ShapeSignature input_arg_signature(const luci::CircleNode *node, uint32_t index)
153 {
154   auto circle_input = loco::must_cast<luci::CircleNode *>(node->arg(index));
155   return circle_input->shape_signature();
156 }
157
158 } // namespace ssinf
159
160 } // namespace luci