Remove obsoleted v0::Broadcast and BroadcastLike operators (#2779)
[platform/upstream/dldt.git] / ngraph / core / builder / include / ngraph / builder / autobroadcast.hpp
1 //*****************************************************************************
2 // Copyright 2017-2020 Intel Corporation
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 #pragma once
18
19 #include <memory>
20 #include <utility>
21
22 #include "ngraph/except.hpp"
23 #include "ngraph/node.hpp"
24 #include "ngraph/op/broadcast.hpp"
25 #include "ngraph/op/constant.hpp"
26
27 namespace ngraph
28 {
29     namespace builder
30     {
31         class numpy_autobroadcast_incompatible_shapes : public ngraph::ngraph_error
32         {
33         public:
34             numpy_autobroadcast_incompatible_shapes(const ngraph::Shape& shape1,
35                                                     const ngraph::Shape& shape2);
36
37         private:
38             const ngraph::Shape m_shape1;
39             const ngraph::Shape m_shape2;
40
41             static std::string error_str(const ngraph::Shape& shape1, const ngraph::Shape& shape2);
42         };
43
44         ///
45         /// \brief      Broadcast all values, if necessary, to obtain equal shapes according
46         ///             to NumPy's auto-broadcasting scheme.
47         ///
48         /// \note       There are some shape combinations which the autobroadcast algoritm cannot
49         ///             handle. An exception is thrown when such combinations are provided to this
50         ///             function.
51         ///
52         /// \param      values  Vector of output values.
53         ///
54         /// \exception  ngraph::builder::numpy_autobroadcast_incompatible_shapes
55         ///
56         /// \return     Vector of broadcasted values.
57         ///
58         OutputVector numpy_broadcast_outputs(const OutputVector& values);
59
60         ///
61         /// \brief      Broadcast input value to provided shape using NumPy's auto-broadcasting
62         ///             rules.
63         ///
64         /// \param      value  Input value
65         /// \param      shape  Requested output shape
66         ///
67         /// \return     Node producing values with requested shape.
68         ///
69         std::shared_ptr<Node> numpy_broadcast(const Output<Node>& value, const Shape& shape);
70
71         /// \brief Wrap two graph values, if necessary, to obtain values with identical shapes,
72         /// using NumPy's auto-broadcast rules.
73         ///
74         /// The elements in the std::pair returned by this function correspond to those supplied
75         /// in the std::pair provided via \p args.
76         ///
77         /// If \p args.first and \p args.second produce identical shapes, then the returned
78         /// std::pair will have the same value as \p args.
79         ///
80         /// If \p args.first and \p args.second produce different shapes, then this function creates
81         /// new ngraph::op::Reshape and/or ngraph::op::Broadcast nodes, as needed, to wrap
82         /// \p args.first and/or \p args.second in a manner that yields values with the same shape.
83         ///
84         /// There are some shape combinations which the autobroadcast algoritm cannot handle.
85         /// An exception is thrown when such combinations are provided to this function.
86         ///
87         /// \pre
88         /// - \p args.first is not null
89         /// - \p args.second is not null
90         ///
91         /// \post
92         /// - The ngraph::Node objects pointed to by \p args.first and \p args.second have not been
93         ///   altered by this function, except by possibly having added consumers of their values.
94         ///
95         /// - If an exception was not thrown, then the return value's \p first and \p second
96         ///   elements point to ngraph::Node objects whose output values have the same shape.
97         ///
98         /// \exception ngraph::builder::numpy_autobroadcast_incompatible_shapes
99         std::pair<std::shared_ptr<Node>, std::shared_ptr<Node>>
100             numpy_broadcast(const std::pair<Output<Node>, Output<Node>>& args);
101
102         /// \brief      Broadcast shape of two nodes to make them compatible for a matrix
103         ///             multiplication.
104         ///
105         /// \note       This function is reflecting broadcasting behaviour of NumPy's `matmul`
106         ///             operation.
107         ///             (https://docs.scipy.org/doc/numpy/reference/generated/numpy.matmul.html)
108         ///             This mean that only \"stack of matrices\" axes are bidirectionally
109         ///             broadcasted. The last two dimension are left untouched.
110         ///
111         /// \param[in]  left   The Node providing data for the left-hand side of matrix
112         ///                    multiplication.
113         /// \param[in]  right  The Node providing data for the right-hand side of matrix
114         ///                    multiplication.
115         ///
116         /// \return     The vector containing both outputs broadcasted.
117         ///
118         OutputVector numpy_broadcast_for_matmul_operation(const Output<Node>& left,
119                                                           const Output<Node>& right);
120
121         /// \brief Cast shape of all input nodes for an element-wise operation that requires
122         ///        shape-compatibility
123         ///
124         /// \param inputs Original list of inputs
125         /// \param axis Index starting to align
126         ///
127         /// \return pdpd-style broadcasted list of nodes.
128         OutputVector pdpd_broadcast(const OutputVector& inputs, int64_t axis);
129
130         /// \brief Generate a list of broadcast axes.
131         ///
132         /// \details Informally, a broadcast "adds" axes to the input tensor, replicating
133         ///          elements from the input tensor as needed to fill the new dimensions.
134         ///          Function calculate which of the output axes are added in this way.
135         ///
136         /// \param output_shape      The new shape for the output tensor.
137         /// \param input_shape       The shape of input tensor.
138         /// \param start_match_axis  The axis along which we want to replicate elements.
139         ///                          The starting axis position (0-based) int the output
140         ///                          shape from which the current shape of the tensor
141         ///                          matches the desired new shape.
142         ///
143         /// \return The indices of added axes.
144         std::shared_ptr<Node> calculate_broadcast_axes(const Shape& output_shape,
145                                                        const Shape& input_shape,
146                                                        std::size_t start_match_axis);
147
148         ///
149         /// \brief      Calculate the output shape of numpy-style broadcast operation for all input
150         ///             shapes.
151         ///
152         ///             This function finds the maximum tensor shape that will be the result of
153         ///             element-wise operation that will be applied to the input shapes vector.
154         ///             The function also prepares the shape of each input for the element-wise
155         ///             operation by left-padding those shapes so that their rank is equal to the
156         ///             left_shape's rank.
157         ///
158         /// \param      input_shapes  A vector of input shapes for which a common shape should be
159         ///                           found
160         ///
161         /// \return     A pair that contains the target shape as its first object and a vector of
162         ///             padded input shapes ready to be broadcasted as the second object
163         ///
164         std::pair<Shape, std::vector<Shape>>
165             get_numpy_broadcast_shapes(const std::vector<Shape>& input_shapes);
166
167         inline std::shared_ptr<Node> make_broadcast_node(const Output<Node>& value,
168                                                          const Shape& new_shape,
169                                                          std::size_t start_match_axis)
170         {
171             auto shape_const =
172                 op::Constant::create(element::u64, Shape{new_shape.size()}, new_shape);
173             return std::make_shared<op::v1::Broadcast>(
174                 value,
175                 shape_const,
176                 calculate_broadcast_axes(new_shape, value.get_shape(), start_match_axis));
177         }
178
179         namespace opset1
180         {
181             ///
182             /// \brief      Broadcast right node to left node's shape using legacy scheme.
183             ///
184             /// \param[in]  left              The left hand side node of binary operation.
185             /// \param[in]  right             The right hand side node of binary operation. The one
186             ///                               to be broadcasted.
187             /// \param[in]  start_match_axis  The axis index starting mutually equal shapes
188             ///                               of both nodes.
189             ///
190             /// \return     The Output object connected to node producing broadcasted right node.
191             ///
192             Output<Node> legacy_broadcast_for_binary_operation(const Output<Node>& left,
193                                                                const Output<Node>& right,
194                                                                size_t start_match_axis);
195
196             ///
197             /// \brief      Reconstructs axes mapping vector for Broadcast:v1 operation.
198             ///
199             /// \param[in]  output_shape    The output shape of Broadcast operation.
200             /// \param[in]  broadcast_axes  The broadcast axes used for Broadcast:v0 operator.
201             ///
202             /// \return     The vector with axes indexes mapping .
203             ///
204             std::vector<std::size_t> get_axes_mapping(const Shape& output_shape,
205                                                       const AxisSet& broadcast_axes);
206
207             ///
208             /// \brief      Creates Node returning the axes mapping for Broadcast:v1 operation.
209             ///
210             /// \param[in]  output_shape      The output shape of Broadcast operation.
211             /// \param[in]  input_shape       The input shape.
212             /// \param[in]  start_match_axis  The axis index at which input shape starts to be
213             ///                               identical as the output shape.
214             ///
215             /// \return     Returns the Output object pointing to node with the axes mapping.
216             ///
217             Output<Node> get_axes_mapping_output(const Shape& output_shape,
218                                                  const Shape& input_shape,
219                                                  std::size_t start_match_axis);
220
221             ///
222             /// \brief      Creates Node returning the axes mapping for Broadcast:v1 operation.
223             ///
224             /// \param[in]  output_shape    The output shape of Broadcast operation.
225             /// \param[in]  broadcast_axes  The broadcast axes used for Broadcast:v0 operator.
226             ///
227             /// \return     The Output object with Node returning axes mapping.
228             ///
229             Output<Node> get_axes_mapping_output(const Shape& output_shape,
230                                                  const AxisSet& broadcast_axes);
231
232             Output<Node> make_broadcast(const Output<Node>& node,
233                                         const Shape& target_shape,
234                                         const AxisSet& broadcast_axes);
235
236             Output<Node> make_broadcast(const Output<Node>& node,
237                                         const Shape& target_shape,
238                                         std::size_t start_match_axis);
239
240         } // namespace opset1
241     }     // namespace builder
242 } // namespace ngraph