Remove obsoleted v0::Broadcast and BroadcastLike operators (#2779)
[platform/upstream/dldt.git] / ngraph / test / builder_autobroadcast.cpp
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 #include "gtest/gtest.h"
18
19 #include "ngraph/builder/autobroadcast.hpp"
20 #include "ngraph/ngraph.hpp"
21
22 NGRAPH_SUPPRESS_DEPRECATED_START
23
24 using namespace std;
25 using namespace ngraph;
26
27 shared_ptr<op::Parameter> getParamFromShape(const Shape& shape)
28 {
29     return make_shared<op::Parameter>(element::f32, shape);
30 }
31
32 inline const Shape& getShapeFromParam(const shared_ptr<Node>& node)
33 {
34     return node->get_shape();
35 }
36
37 // input shapes are equal so AutoBroadcast does nothing
38 TEST(autobroadcast, no_broadcast_equal)
39 {
40     Shape s2345{2, 3, 4, 5};
41     auto lhs = getParamFromShape(s2345);
42     auto rhs = getParamFromShape(s2345);
43
44     auto shaped = builder::numpy_broadcast({lhs, rhs});
45     const shared_ptr<Node>& ab_lhs = shaped.first;
46     const shared_ptr<Node>& ab_rhs = shaped.second;
47
48     EXPECT_EQ(ab_lhs, lhs); // no change
49     EXPECT_EQ(getShapeFromParam(ab_lhs), s2345);
50
51     EXPECT_EQ(ab_rhs, rhs); // no change
52     EXPECT_EQ(getShapeFromParam(ab_rhs), s2345);
53 }
54
55 // input shapes are incompatable
56 TEST(autobroadcast, no_broadcast_incompatable)
57 {
58     Shape s2345{2, 3, 4, 5};
59     Shape s6789{6, 7, 8, 9};
60     auto lhs = getParamFromShape(s2345);
61     auto rhs = getParamFromShape(s6789);
62
63     EXPECT_THROW(builder::numpy_broadcast({lhs, rhs}),
64                  builder::numpy_autobroadcast_incompatible_shapes);
65 }
66
67 // basic broadcast test
68 // 1D to 2D
69 // lhs broadcast to 2,3
70 TEST(autobroadcast, normal_broadcast_2d)
71 {
72     Shape s3{3};
73     Shape s23{2, 3};
74     auto lhs = getParamFromShape(s3);
75     auto rhs = getParamFromShape(s23);
76
77     auto shaped = builder::numpy_broadcast({lhs, rhs});
78     const shared_ptr<Node>& ab_lhs = shaped.first;
79     const shared_ptr<Node>& ab_rhs = shaped.second;
80
81     EXPECT_NE(ab_lhs, lhs);
82     EXPECT_EQ(getShapeFromParam(ab_lhs), s23);
83
84     EXPECT_EQ(ab_rhs, rhs); // no change
85     EXPECT_EQ(getShapeFromParam(ab_rhs), s23);
86 }
87
88 // basic broadcast test
89 // 2D to 3D
90 // lhs broadcast to 2,3,4
91 TEST(autobroadcast, normal_broadcast_3d)
92 {
93     Shape s34{3, 4};
94     Shape s234{2, 3, 4};
95     auto lhs = getParamFromShape(s34);
96     auto rhs = getParamFromShape(s234);
97
98     auto shaped = builder::numpy_broadcast({lhs, rhs});
99     const shared_ptr<Node>& ab_lhs = shaped.first;
100     const shared_ptr<Node>& ab_rhs = shaped.second;
101
102     EXPECT_NE(ab_lhs, lhs);
103     EXPECT_EQ(getShapeFromParam(ab_lhs), s234);
104
105     EXPECT_EQ(ab_rhs, rhs); // no change
106     EXPECT_EQ(getShapeFromParam(ab_rhs), s234);
107 }
108
109 // basic broadcast test
110 // 3D to 4D
111 // lhs broadcast to 2,3,4,5
112 TEST(autobroadcast, normal_broadcast_4d)
113 {
114     Shape s345{3, 4, 5};
115     Shape s2345{2, 3, 4, 5};
116     auto lhs = getParamFromShape(s345);
117     auto rhs = getParamFromShape(s2345);
118
119     auto shaped = builder::numpy_broadcast({lhs, rhs});
120     const shared_ptr<Node>& ab_lhs = shaped.first;
121     const shared_ptr<Node>& ab_rhs = shaped.second;
122
123     EXPECT_NE(ab_lhs, lhs);
124     EXPECT_EQ(getShapeFromParam(ab_lhs), s2345);
125
126     EXPECT_EQ(ab_rhs, rhs); // no change
127     EXPECT_EQ(getShapeFromParam(ab_rhs), s2345);
128 }
129
130 // basic reshape and broadcast test
131 // rhs reshape to 2,3,4 then
132 // rhs broadcast to 2,3,4,5
133 TEST(autobroadcast, reshape_1x_broadcast)
134 {
135     Shape s2345{2, 3, 4, 5};
136     Shape s2341{2, 3, 4, 1};
137     auto lhs = getParamFromShape(s2345);
138     auto rhs = getParamFromShape(s2341);
139
140     auto shaped = builder::numpy_broadcast({lhs, rhs});
141     const shared_ptr<Node>& ab_lhs = shaped.first;
142     const shared_ptr<Node>& ab_rhs = shaped.second;
143
144     EXPECT_EQ(ab_lhs, lhs); // no change
145     EXPECT_EQ(getShapeFromParam(ab_lhs), s2345);
146
147     EXPECT_NE(ab_rhs, rhs);
148     EXPECT_EQ(getShapeFromParam(ab_rhs), s2345);
149 }
150
151 // same as above, but additionally
152 // lhs reshape to 2,4,5 then
153 // lhs broadcast to 2,3,4,5
154 TEST(autobroadcast, reshape_2x_broadcast)
155 {
156     Shape s2145{2, 1, 4, 5};
157     Shape s2341{2, 3, 4, 1};
158     auto lhs = getParamFromShape(s2145);
159     auto rhs = getParamFromShape(s2341);
160
161     auto shaped = builder::numpy_broadcast({lhs, rhs});
162     const shared_ptr<Node>& ab_lhs = shaped.first;
163     const shared_ptr<Node>& ab_rhs = shaped.second;
164
165     Shape s2345{2, 3, 4, 5};
166
167     EXPECT_NE(ab_lhs, lhs);
168     EXPECT_EQ(getShapeFromParam(ab_lhs), s2345);
169
170     EXPECT_NE(ab_rhs, rhs);
171     EXPECT_EQ(getShapeFromParam(ab_rhs), s2345);
172 }
173
174 // matching singular dimension on axis 2
175 // should not require reshape of either lhs or rhs
176 // i.e. this should be the same as normal broadcast casse
177 // rhs broadcast to 2,3,1,5
178 TEST(autobroadcast, broadcast_with_dim1)
179 {
180     Shape s2315{2, 3, 1, 5};
181     Shape s315{3, 1, 5};
182     auto lhs = getParamFromShape(s2315);
183     auto rhs = getParamFromShape(s315);
184
185     auto shaped = builder::numpy_broadcast({lhs, rhs});
186     const shared_ptr<Node>& ab_lhs = shaped.first;
187     const shared_ptr<Node>& ab_rhs = shaped.second;
188
189     EXPECT_EQ(ab_lhs, lhs); // no change
190     EXPECT_EQ(getShapeFromParam(ab_lhs), s2315);
191
192     EXPECT_NE(ab_rhs, rhs);
193     EXPECT_EQ(getShapeFromParam(ab_rhs), s2315);
194 }
195
196 // reshape only test
197 // rhs reshape to 1,3,4,5 with no broadcast
198 TEST(autobroadcast, broadcast_with_leading_dim1)
199 {
200     Shape s1345{1, 3, 4, 5};
201     Shape s345{3, 4, 5};
202     auto lhs = getParamFromShape(s1345);
203     auto rhs = getParamFromShape(s345);
204
205     auto shaped = builder::numpy_broadcast({lhs, rhs});
206     const shared_ptr<Node>& ab_lhs = shaped.first;
207     const shared_ptr<Node>& ab_rhs = shaped.second;
208
209     EXPECT_EQ(ab_lhs, lhs); // no change
210     EXPECT_EQ(getShapeFromParam(ab_lhs), s1345);
211
212     EXPECT_NE(ab_rhs, rhs);
213     EXPECT_EQ(getShapeFromParam(ab_rhs), s1345);
214 }
215
216 TEST(autobroadcast, numpy_broadcast_for_matmul_op_2d)
217 {
218     const Shape lhs{3, 1, 4, 6};
219     const Shape rhs{6, 5};
220     const auto lhs_node = make_shared<op::Parameter>(element::f32, lhs);
221     const auto rhs_node = make_shared<op::Parameter>(element::f32, rhs);
222
223     const OutputVector result = builder::numpy_broadcast_for_matmul_operation(lhs_node, rhs_node);
224
225     EXPECT_EQ(result.at(0).get_shape(), (Shape{3, 1, 4, 6}));
226     EXPECT_EQ(result.at(1).get_shape(), (Shape{3, 1, 6, 5}));
227 }
228
229 TEST(autobroadcast, numpy_broadcast_for_matmul_op_3d)
230 {
231     const Shape lhs{3, 1, 4, 6};
232     const Shape rhs{2, 6, 5};
233     const auto lhs_node = make_shared<op::Parameter>(element::f32, lhs);
234     const auto rhs_node = make_shared<op::Parameter>(element::f32, rhs);
235
236     const OutputVector result = builder::numpy_broadcast_for_matmul_operation(lhs_node, rhs_node);
237
238     EXPECT_EQ(result.at(0).get_shape(), (Shape{3, 2, 4, 6}));
239     EXPECT_EQ(result.at(1).get_shape(), (Shape{3, 2, 6, 5}));
240 }
241
242 TEST(autobroadcast, numpy_broadcast_for_matmul_op_nop)
243 {
244     const Shape lhs{4, 6};
245     const Shape rhs{6, 5};
246     const auto lhs_node = make_shared<op::Parameter>(element::f32, lhs);
247     const auto rhs_node = make_shared<op::Parameter>(element::f32, rhs);
248
249     const OutputVector result = builder::numpy_broadcast_for_matmul_operation(lhs_node, rhs_node);
250
251     EXPECT_EQ(result.at(0).get_shape(), (Shape{4, 6}));
252     EXPECT_EQ(result.at(1).get_shape(), (Shape{6, 5}));
253 }
254
255 TEST(autobroadcast, opset1_legacy_broadcast_scalar)
256 {
257     const Shape lhs{2, 3, 4, 5};
258     const Shape rhs{};
259     size_t start_match_axis{3};
260     const auto lhs_node = make_shared<op::Parameter>(element::f32, lhs);
261     const auto rhs_node = make_shared<op::Parameter>(element::f32, rhs);
262
263     const Output<Node> result = builder::opset1::legacy_broadcast_for_binary_operation(
264         lhs_node, rhs_node, start_match_axis);
265
266     EXPECT_EQ(result.get_shape(), lhs);
267 }
268
269 TEST(autobroadcast, opset1_legacy_broadcast_1elem_tensor)
270 {
271     const Shape lhs{2, 3, 4, 5};
272     const Shape rhs{1, 1, 1};
273     size_t start_match_axis{1};
274     const auto lhs_node = make_shared<op::Parameter>(element::f32, lhs);
275     const auto rhs_node = make_shared<op::Parameter>(element::f32, rhs);
276
277     const Output<Node> result = builder::opset1::legacy_broadcast_for_binary_operation(
278         lhs_node, rhs_node, start_match_axis);
279
280     EXPECT_EQ(result.get_shape(), lhs);
281 }
282
283 TEST(autobroadcast, opset1_legacy_broadcast_1d)
284 {
285     const Shape lhs{2, 3, 4, 5};
286     const Shape rhs{5};
287     size_t start_match_axis{3};
288     const auto lhs_node = make_shared<op::Parameter>(element::f32, lhs);
289     const auto rhs_node = make_shared<op::Parameter>(element::f32, rhs);
290
291     const Output<Node> result = builder::opset1::legacy_broadcast_for_binary_operation(
292         lhs_node, rhs_node, start_match_axis);
293
294     EXPECT_EQ(result.get_shape(), lhs);
295 }
296
297 TEST(autobroadcast, opset1_legacy_broadcast_2d)
298 {
299     const Shape lhs{2, 3, 4, 5};
300     const Shape rhs{4, 5};
301     size_t start_match_axis{2};
302     const auto lhs_node = make_shared<op::Parameter>(element::f32, lhs);
303     const auto rhs_node = make_shared<op::Parameter>(element::f32, rhs);
304
305     const Output<Node> result = builder::opset1::legacy_broadcast_for_binary_operation(
306         lhs_node, rhs_node, start_match_axis);
307
308     EXPECT_EQ(result.get_shape(), lhs);
309 }
310
311 TEST(autobroadcast, opset1_legacy_broadcast_2d_inside)
312 {
313     const Shape lhs{2, 3, 4, 5};
314     const Shape rhs{3, 4};
315     size_t start_match_axis{1};
316     const auto lhs_node = make_shared<op::Parameter>(element::f32, lhs);
317     const auto rhs_node = make_shared<op::Parameter>(element::f32, rhs);
318
319     const Output<Node> result = builder::opset1::legacy_broadcast_for_binary_operation(
320         lhs_node, rhs_node, start_match_axis);
321
322     EXPECT_EQ(result.get_shape(), lhs);
323 }
324
325 TEST(autobroadcast, opset1_legacy_broadcast_1d_left)
326 {
327     const Shape lhs{2, 3, 4, 5};
328     const Shape rhs{2};
329     size_t start_match_axis{0};
330     const auto lhs_node = make_shared<op::Parameter>(element::f32, lhs);
331     const auto rhs_node = make_shared<op::Parameter>(element::f32, rhs);
332
333     const Output<Node> result = builder::opset1::legacy_broadcast_for_binary_operation(
334         lhs_node, rhs_node, start_match_axis);
335
336     EXPECT_EQ(result.get_shape(), lhs);
337 }
338
339 TEST(autobroadcast, opset1_legacy_broadcast_identical)
340 {
341     const Shape lhs{2, 3, 4, 5};
342     size_t start_match_axis{0};
343     const auto lhs_node = make_shared<op::Parameter>(element::f32, lhs);
344     const auto rhs_node = make_shared<op::Parameter>(element::f32, lhs);
345
346     const Output<Node> result = builder::opset1::legacy_broadcast_for_binary_operation(
347         lhs_node, rhs_node, start_match_axis);
348
349     EXPECT_EQ(result.get_shape(), lhs);
350 }
351
352 TEST(autobroadcast, axes_mapping_from_bcast_axes)
353 {
354     const Shape output_shape{2, 3, 4, 5};
355     const Shape input_shape{3, 5};
356     const AxisSet broadcast_axes{0, 2};
357
358     auto axes_mapping = builder::opset1::get_axes_mapping_output(output_shape, broadcast_axes);
359     EXPECT_TRUE(op::is_constant(axes_mapping.get_node()));
360     Shape axes_mapping_shape = as_type<op::v0::Constant>(axes_mapping.get_node())->get_shape_val();
361     EXPECT_EQ(axes_mapping_shape.size(), 2);
362     EXPECT_EQ(axes_mapping_shape, (Shape{1, 3}));
363 }
364
365 TEST(autobroadcast, axes_mapping_from_bcast_axes_scalar)
366 {
367     const Shape output_shape{2, 3, 4, 5};
368     const Shape input_shape{};
369     const AxisSet broadcast_axes{0, 1, 2, 3};
370
371     auto axes_mapping = builder::opset1::get_axes_mapping_output(output_shape, broadcast_axes);
372     EXPECT_TRUE(op::is_constant(axes_mapping.get_node()));
373     Shape axes_mapping_shape = as_type<op::v0::Constant>(axes_mapping.get_node())->get_shape_val();
374     EXPECT_EQ(axes_mapping_shape.size(), 0);
375     EXPECT_EQ(axes_mapping_shape, (Shape{}));
376 }
377
378 TEST(autobroadcast, axes_mapping_from_bcast_axes_identical)
379 {
380     const Shape output_shape{2, 3, 4, 5};
381     const Shape input_shape(output_shape);
382     const AxisSet broadcast_axes{};
383
384     auto axes_mapping = builder::opset1::get_axes_mapping_output(output_shape, broadcast_axes);
385     EXPECT_TRUE(op::is_constant(axes_mapping.get_node()));
386     Shape axes_mapping_shape = as_type<op::v0::Constant>(axes_mapping.get_node())->get_shape_val();
387     EXPECT_EQ(axes_mapping_shape.size(), output_shape.size());
388     EXPECT_EQ(axes_mapping_shape, (Shape{0, 1, 2, 3}));
389 }
390
391 TEST(autobroadcast, axes_mapping_start_match_axis)
392 {
393     const Shape output_shape{2, 3, 4, 5};
394     const Shape input_shape{3, 4};
395     const std::size_t start_match_axis{1};
396
397     auto axes_mapping =
398         builder::opset1::get_axes_mapping_output(output_shape, input_shape, start_match_axis);
399     EXPECT_TRUE(op::is_constant(axes_mapping.get_node()));
400     Shape axes_mapping_shape = as_type<op::v0::Constant>(axes_mapping.get_node())->get_shape_val();
401     EXPECT_EQ(axes_mapping_shape.size(), 2);
402     EXPECT_EQ(axes_mapping_shape, (Shape{1, 2}));
403 }
404
405 TEST(autobroadcast, axes_mapping_start_match_axis_scalar)
406 {
407     const Shape output_shape{2, 3, 4, 5};
408     const Shape input_shape{};
409     const std::size_t start_match_axis{4};
410
411     auto axes_mapping =
412         builder::opset1::get_axes_mapping_output(output_shape, input_shape, start_match_axis);
413     EXPECT_TRUE(op::is_constant(axes_mapping.get_node()));
414     Shape axes_mapping_shape = as_type<op::v0::Constant>(axes_mapping.get_node())->get_shape_val();
415     EXPECT_EQ(axes_mapping_shape.size(), 0);
416     EXPECT_EQ(axes_mapping_shape, (Shape{}));
417 }
418
419 TEST(autobroadcast, axes_mapping_start_match_axis_identical)
420 {
421     const Shape output_shape{2, 3, 4, 5};
422     const Shape input_shape{2, 3, 4, 5};
423     const std::size_t start_match_axis{0};
424
425     auto axes_mapping =
426         builder::opset1::get_axes_mapping_output(output_shape, input_shape, start_match_axis);
427     EXPECT_TRUE(op::is_constant(axes_mapping.get_node()));
428     Shape axes_mapping_shape = as_type<op::v0::Constant>(axes_mapping.get_node())->get_shape_val();
429     EXPECT_EQ(axes_mapping_shape.size(), output_shape.size());
430     EXPECT_EQ(axes_mapping_shape, (Shape{0, 1, 2, 3}));
431 }