diff --git a/src/core/include/openvino/op/bitwise_not.hpp b/src/core/include/openvino/op/bitwise_not.hpp new file mode 100644 index 00000000000..8b5c8faa800 --- /dev/null +++ b/src/core/include/openvino/op/bitwise_not.hpp @@ -0,0 +1,30 @@ +// Copyright (C) 2018-2023 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include "openvino/op/op.hpp" + +namespace ov { +namespace op { +namespace v13 { +/// \brief Elementwise bitwise negation operation. +/// \ingroup ov_ops_cpp_api +class OPENVINO_API BitwiseNot : public op::Op { +public: + OPENVINO_OP("BitwiseNot", "opset13", op::Op); + /// \brief Constructs a bitwise negation operation. + BitwiseNot() = default; + /// \brief Constructs a bitwise negation operation. + /// + /// \param arg Node that produces the input tensor. + BitwiseNot(const Output& arg); + + void validate_and_infer_types() override; + + std::shared_ptr clone_with_new_inputs(const OutputVector& new_args) const override; +}; +} // namespace v13 +} // namespace op +} // namespace ov diff --git a/src/core/include/openvino/op/ops.hpp b/src/core/include/openvino/op/ops.hpp index 05eaa7e5d43..fe48372636c 100644 --- a/src/core/include/openvino/op/ops.hpp +++ b/src/core/include/openvino/op/ops.hpp @@ -21,6 +21,7 @@ #include "openvino/op/batch_norm.hpp" #include "openvino/op/batch_to_space.hpp" #include "openvino/op/binary_convolution.hpp" +#include "openvino/op/bitwise_not.hpp" #include "openvino/op/broadcast.hpp" #include "openvino/op/bucketize.hpp" #include "openvino/op/ceiling.hpp" diff --git a/src/core/include/openvino/opsets/opset13_tbl.hpp b/src/core/include/openvino/opsets/opset13_tbl.hpp index f8b1709648e..abe98b4754f 100644 --- a/src/core/include/openvino/opsets/opset13_tbl.hpp +++ b/src/core/include/openvino/opsets/opset13_tbl.hpp @@ -209,3 +209,4 @@ _OPENVINO_OP_REG(Pad, ov::op::v12) _OPENVINO_OP_REG(ScatterElementsUpdate, ov::op::v12) // New operations added in opset13 +_OPENVINO_OP_REG(BitwiseNot, ov::op::v13) diff --git a/src/core/reference/include/openvino/reference/bitwise_not.hpp b/src/core/reference/include/openvino/reference/bitwise_not.hpp new file mode 100644 index 00000000000..da0cd9095c3 --- /dev/null +++ b/src/core/reference/include/openvino/reference/bitwise_not.hpp @@ -0,0 +1,36 @@ +// Copyright (C) 2018-2023 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include +#include + +namespace ov { +namespace reference { +namespace func { +// Check for char datatype used by ov::element::boolean +template ::type, char>::value>::type* = nullptr> +T bitwise_not(const T in) { + return static_cast(!in); +} + +template ::type, char>::value>::type* = nullptr> +T bitwise_not(const T in) { + return static_cast(~in); +} +} // namespace func +/** + * @brief Reference implementation of BitwiseNot operator. + * + * @param in Input pointer to data. + * @param out Output pointer to results. + * @param count Number of elements in input buffer. + */ +template +void bitwise_not(const T* in, T* out, size_t count) { + std::transform(in, std::next(in, count), out, &func::bitwise_not); +} +} // namespace reference +} // namespace ov diff --git a/src/core/src/op/bitwise_not.cpp b/src/core/src/op/bitwise_not.cpp new file mode 100644 index 00000000000..92aeace18ad --- /dev/null +++ b/src/core/src/op/bitwise_not.cpp @@ -0,0 +1,33 @@ +// Copyright (C) 2018-2023 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// +#include "openvino/op/bitwise_not.hpp" + +#include "itt.hpp" +#include "openvino/core/validation_util.hpp" +#include "openvino/op/op.hpp" + +namespace ov { +namespace op { +namespace v13 { +BitwiseNot::BitwiseNot(const Output& arg) : op::Op({arg}) { + constructor_validate_and_infer_types(); +} +void BitwiseNot::validate_and_infer_types() { + OV_OP_SCOPE(v13_BitwiseNot_validate_and_infer_types); + const auto& element_type = get_input_element_type(0); + NODE_VALIDATION_CHECK(this, + element_type.is_dynamic() || element_type.is_integral(), + "The element type of the input tensor must be integer or boolean."); + set_output_type(0, element_type, get_input_partial_shape(0)); +} + +std::shared_ptr BitwiseNot::clone_with_new_inputs(const OutputVector& new_args) const { + OV_OP_SCOPE(v13_BitwiseNot_clone_with_new_inputs); + check_new_args_count(this, new_args); + return std::make_shared(new_args.at(0)); +} + +} // namespace v13 +} // namespace op +} // namespace ov diff --git a/src/core/tests/op_version_tbl.hpp b/src/core/tests/op_version_tbl.hpp index 358a6ef4162..bf2fc789b12 100644 --- a/src/core/tests/op_version_tbl.hpp +++ b/src/core/tests/op_version_tbl.hpp @@ -26,6 +26,7 @@ _OPENVINO_OP_REG(AvgPool, ov::op::v1) _OPENVINO_OP_REG(BatchNormInference, ov::op::v0) _OPENVINO_OP_REG(BatchToSpace, ov::op::v1) _OPENVINO_OP_REG(BinaryConvolution, ov::op::v1) +_OPENVINO_OP_REG(BitwiseNot, ov::op::v13) _OPENVINO_OP_REG(Broadcast, ov::op::v1) _OPENVINO_OP_REG(Broadcast, ov::op::v3) _OPENVINO_OP_REG(Bucketize, ov::op::v3) diff --git a/src/core/tests/opset.cpp b/src/core/tests/opset.cpp index e8007d9b74b..b0e540171d9 100644 --- a/src/core/tests/opset.cpp +++ b/src/core/tests/opset.cpp @@ -71,7 +71,7 @@ INSTANTIATE_TEST_SUITE_P(opset, OpsetTestParams{ov::get_opset10, 177}, OpsetTestParams{ov::get_opset11, 177}, OpsetTestParams{ov::get_opset12, 178}, - OpsetTestParams{ov::get_opset13, 178}), + OpsetTestParams{ov::get_opset13, 179}), OpsetTestNameGenerator{}); class MyOpOld : public ov::op::Op { diff --git a/src/core/tests/type_prop/bitwise_not.cpp b/src/core/tests/type_prop/bitwise_not.cpp new file mode 100644 index 00000000000..edfb0693db3 --- /dev/null +++ b/src/core/tests/type_prop/bitwise_not.cpp @@ -0,0 +1,85 @@ +// Copyright (C) 2018-2023 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "openvino/op/bitwise_not.hpp" + +#include + +#include "common_test_utils/test_assertions.hpp" +#include "common_test_utils/type_prop.hpp" + +using namespace ov; +using namespace testing; + +using BitwiseNotTestParam = std::tuple; + +namespace { +using namespace ov::element; +constexpr size_t exp_num_of_outputs = 1; + +const auto types = Values(boolean, i8, i16, i32, i64, u8, u16, u32, u64); + +const auto static_shapes = Values(PartialShape{0}, PartialShape{1}, PartialShape{2, 3, 7, 8}); +const auto dynamic_shapes = + Values(PartialShape::dynamic(3), PartialShape{2, {0, 5}, {4, -1}, -1, {3, 8}}, PartialShape::dynamic()); +} // namespace + +class BitwiseNotTest : public TypePropOpTest, public WithParamInterface { +protected: + void SetUp() override { + std::tie(exp_type, exp_shape) = GetParam(); + } + + element::Type exp_type; + PartialShape exp_shape; +}; + +INSTANTIATE_TEST_SUITE_P(type_prop_static_shape, + BitwiseNotTest, + Combine(types, static_shapes), + PrintToStringParamName()); +INSTANTIATE_TEST_SUITE_P(type_prop_dynamic_shape, + BitwiseNotTest, + Combine(types, dynamic_shapes), + PrintToStringParamName()); + +TEST_P(BitwiseNotTest, propagate_dimensions) { + const auto input = std::make_shared(exp_type, exp_shape); + const auto op = make_op(input); + + EXPECT_EQ(op->get_element_type(), exp_type); + EXPECT_EQ(op->get_output_size(), exp_num_of_outputs); + EXPECT_EQ(op->get_output_partial_shape(0), exp_shape); +} + +TEST_P(BitwiseNotTest, propagate_labels) { + if (exp_shape.rank().is_static()) { + set_shape_labels(exp_shape, 10); + } + const auto exp_labels = get_shape_labels(exp_shape); + + const auto input = std::make_shared(exp_type, exp_shape); + const auto op = make_op(input); + + EXPECT_EQ(get_shape_labels(op->get_output_partial_shape(0)), exp_labels); +} + +TEST_P(BitwiseNotTest, default_ctor) { + const auto op = make_op(); + const auto input = std::make_shared(exp_type, exp_shape); + + op->set_argument(0, input); + op->validate_and_infer_types(); + + EXPECT_EQ(op->get_element_type(), exp_type); + EXPECT_EQ(op->get_output_size(), exp_num_of_outputs); + EXPECT_EQ(op->get_output_partial_shape(0), exp_shape); +} + +TEST(BitwiseNotTest, invalid_element_type) { + auto data = std::make_shared(ov::element::f32, ov::Shape{2, 2}); + OV_EXPECT_THROW(std::ignore = std::make_shared(data), + ov::NodeValidationFailure, + HasSubstr("The element type of the input tensor must be integer or boolean.")); +} diff --git a/src/core/tests/visitors/op/bitwise_not.cpp b/src/core/tests/visitors/op/bitwise_not.cpp new file mode 100644 index 00000000000..ef874eb8fd2 --- /dev/null +++ b/src/core/tests/visitors/op/bitwise_not.cpp @@ -0,0 +1,11 @@ +// Copyright (C) 2018-2023 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "openvino/op/bitwise_not.hpp" + +#include "unary_ops.hpp" + +using Type = ::testing::Types>; + +INSTANTIATE_TYPED_TEST_SUITE_P(visitor_without_attribute, UnaryOperatorVisitor, Type, UnaryOperatorTypeName); diff --git a/src/plugins/template/backend/ops/bitwise_not.cpp b/src/plugins/template/backend/ops/bitwise_not.cpp new file mode 100644 index 00000000000..91a73fa0dd1 --- /dev/null +++ b/src/plugins/template/backend/ops/bitwise_not.cpp @@ -0,0 +1,52 @@ +// Copyright (C) 2018-2023 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "openvino/op/bitwise_not.hpp" + +#include "evaluate_node.hpp" +#include "openvino/reference/bitwise_not.hpp" +#include "utils.hpp" + +using namespace ov; + +template +bool evaluate(const std::shared_ptr& node, + ov::TensorVector& outputs, + const ov::TensorVector& inputs) { + OPENVINO_ASSERT(inputs.size() == 1); + OPENVINO_ASSERT(outputs.size() == 1); + outputs[0].set_shape(inputs[0].get_shape()); + + using T = typename ov::element_type_traits::value_type; + ov::reference::bitwise_not(inputs[0].data(), outputs[0].data(), shape_size(inputs[0].get_shape())); + return true; +} + +template <> +bool evaluate_node(std::shared_ptr node, + ov::TensorVector& outputs, + const ov::TensorVector& inputs) { + switch (node->get_input_element_type(0)) { + case element::boolean: + return evaluate(as_type_ptr(node), outputs, inputs); + case element::u8: + return evaluate(as_type_ptr(node), outputs, inputs); + case element::i8: + return evaluate(as_type_ptr(node), outputs, inputs); + case element::u16: + return evaluate(as_type_ptr(node), outputs, inputs); + case element::i16: + return evaluate(as_type_ptr(node), outputs, inputs); + case element::u32: + return evaluate(as_type_ptr(node), outputs, inputs); + case element::i32: + return evaluate(as_type_ptr(node), outputs, inputs); + case element::u64: + return evaluate(as_type_ptr(node), outputs, inputs); + case element::i64: + return evaluate(as_type_ptr(node), outputs, inputs); + default: + OPENVINO_THROW("Unhandled data type ", node->get_element_type().get_type_name(), "in evaluate_node()"); + } +} diff --git a/src/plugins/template/backend/ops/ops_evaluates.hpp b/src/plugins/template/backend/ops/ops_evaluates.hpp index c3a316bea50..bc0918ae3dd 100644 --- a/src/plugins/template/backend/ops/ops_evaluates.hpp +++ b/src/plugins/template/backend/ops/ops_evaluates.hpp @@ -445,6 +445,10 @@ extern template bool evaluate_node(std::shared_ ov::TensorVector& outputs, const ov::TensorVector& inputs); +extern template bool evaluate_node(std::shared_ptr node, + ov::TensorVector& outputs, + const ov::TensorVector& inputs); + extern template bool evaluate_node(std::shared_ptr node, ov::TensorVector& outputs, const ov::TensorVector& inputs); diff --git a/src/plugins/template/backend/opset_int_tbl.hpp b/src/plugins/template/backend/opset_int_tbl.hpp index c94db72de77..b4435c87a47 100644 --- a/src/plugins/template/backend/opset_int_tbl.hpp +++ b/src/plugins/template/backend/opset_int_tbl.hpp @@ -150,5 +150,7 @@ _OPENVINO_OP_REG(Interpolate, op::v11) _OPENVINO_OP_REG(GroupNormalization, ov::op::v12) +_OPENVINO_OP_REG(BitwiseNot, ov::op::v13) + _OPENVINO_OP_REG(AUGRUCell, ov::op::internal) _OPENVINO_OP_REG(AUGRUSequence, ov::op::internal) diff --git a/src/plugins/template/src/plugin.cpp b/src/plugins/template/src/plugin.cpp index 918bfbfb9b0..fde640e7f01 100644 --- a/src/plugins/template/src/plugin.cpp +++ b/src/plugins/template/src/plugin.cpp @@ -194,6 +194,7 @@ ov::SupportedOpsMap ov::template_plugin::Plugin::query_model(const std::shared_p #include "openvino/opsets/opset10_tbl.hpp" #include "openvino/opsets/opset11_tbl.hpp" #include "openvino/opsets/opset12_tbl.hpp" +#include "openvino/opsets/opset13_tbl.hpp" // clang-format on #undef _OPENVINO_OP_REG return op_super_set.contains_type(node->get_type_info()); diff --git a/src/plugins/template/tests/functional/op_reference/bitwise.cpp b/src/plugins/template/tests/functional/op_reference/bitwise.cpp new file mode 100644 index 00000000000..a3f490fbd86 --- /dev/null +++ b/src/plugins/template/tests/functional/op_reference/bitwise.cpp @@ -0,0 +1,17 @@ +// Copyright (C) 2018-2023 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "bitwise.hpp" + +namespace reference_tests { +namespace BitwiseOpsRefTestDefinitions { +namespace { + +TEST_P(ReferenceBitwiseLayerTest, BitwiseWithHardcodedRefs) { + Exec(); +} + +} // namespace +} // namespace BitwiseOpsRefTestDefinitions +} // namespace reference_tests diff --git a/src/plugins/template/tests/functional/op_reference/bitwise.hpp b/src/plugins/template/tests/functional/op_reference/bitwise.hpp new file mode 100644 index 00000000000..0e8ff7af32c --- /dev/null +++ b/src/plugins/template/tests/functional/op_reference/bitwise.hpp @@ -0,0 +1,74 @@ +// Copyright (C) 2018-2023 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include + +#include "base_reference_test.hpp" +#include "openvino/op/bitwise_not.hpp" + +using namespace ov; + +namespace reference_tests { +namespace BitwiseOpsRefTestDefinitions { + +enum BitwiseTypes { BITWISE_NOT }; + +struct RefBitwiseParams { + BitwiseTypes opType; + std::vector inputs; + reference_tests::Tensor expected; +}; + +struct Builder : ParamsBuilder { + REFERENCE_TESTS_ADD_SET_PARAM(Builder, opType); + REFERENCE_TESTS_ADD_SET_PARAM(Builder, inputs); + REFERENCE_TESTS_ADD_SET_PARAM(Builder, expected); +}; + +class ReferenceBitwiseLayerTest : public testing::TestWithParam, public CommonReferenceTest { +public: + void SetUp() override { + const auto& params = GetParam(); + function = CreateFunction(params.opType, params.inputs); + for (auto& input : params.inputs) { + inputData.push_back(input.data); + } + refOutData = {params.expected.data}; + } + static std::string getTestCaseName(const testing::TestParamInfo& obj) { + const auto& param = obj.param; + std::ostringstream result; + result << "BitwiseType=" << param.opType << "_"; + for (size_t i = 0; i < param.inputs.size(); i++) { + const auto input = param.inputs[i]; + result << "inpt_shape" << i << "=" << input.shape << "_"; + result << "inpt_type" << i << "=" << input.type << "_"; + } + result << "oType=" << param.expected.type; + return result.str(); + } + +private: + static std::shared_ptr CreateFunction(BitwiseTypes op_type, + const std::vector& inputs) { + ov::ParameterVector params_vec; + for (auto& input : inputs) { + params_vec.push_back(std::make_shared(input.type, input.shape)); + } + + std::shared_ptr bitwise_op; + switch (op_type) { + case BitwiseTypes::BITWISE_NOT: { + bitwise_op = std::make_shared(params_vec[0]); + break; + } + default: { + throw std::runtime_error("Incorrect type of Bitwise operation"); + } + } + return std::make_shared(ov::NodeVector{bitwise_op}, ov::ParameterVector{params_vec}); + } +}; +} // namespace BitwiseOpsRefTestDefinitions +} // namespace reference_tests diff --git a/src/plugins/template/tests/functional/op_reference/bitwise_not.cpp b/src/plugins/template/tests/functional/op_reference/bitwise_not.cpp new file mode 100644 index 00000000000..3c79473532e --- /dev/null +++ b/src/plugins/template/tests/functional/op_reference/bitwise_not.cpp @@ -0,0 +1,119 @@ +// Copyright (C) 2018-2023 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "openvino/op/bitwise_not.hpp" + +#include + +#include "bitwise.hpp" + +using namespace ov; + +namespace reference_tests { +namespace BitwiseOpsRefTestDefinitions { +namespace { + +std::vector generateBitwiseParams() { + std::vector bitwiseParams{ + Builder{} + .opType(BitwiseTypes::BITWISE_NOT) + .inputs({{{2, 2}, element::boolean, std::vector{true, false, true, false}}}) + .expected({{2, 2}, element::boolean, std::vector{false, true, false, true}}), + Builder{} + .opType(BitwiseTypes::BITWISE_NOT) + .inputs({{{3}, + element::i8, + std::vector{std::numeric_limits::max(), std::numeric_limits::min(), -7}}}) + .expected({{3}, + element::i8, + std::vector{std::numeric_limits::min(), std::numeric_limits::max(), 6}}), + Builder{} + .opType(BitwiseTypes::BITWISE_NOT) + .inputs( + {{{3}, + element::u8, + std::vector{std::numeric_limits::max(), std::numeric_limits::min(), 7}}}) + .expected({{3}, + element::u8, + std::vector{std::numeric_limits::min(), + std::numeric_limits::max(), + std::numeric_limits::max() - 7}}), + Builder{} + .opType(BitwiseTypes::BITWISE_NOT) + .inputs( + {{{3}, + element::i16, + std::vector{std::numeric_limits::max(), std::numeric_limits::min(), -7}}}) + .expected( + {{3}, + element::i16, + std::vector{std::numeric_limits::min(), std::numeric_limits::max(), 6}}), + Builder{} + .opType(BitwiseTypes::BITWISE_NOT) + .inputs({{{3}, + element::u16, + std::vector{std::numeric_limits::max(), + std::numeric_limits::min(), + 7}}}) + .expected({{3}, + element::u16, + std::vector{std::numeric_limits::min(), + std::numeric_limits::max(), + std::numeric_limits::max() - 7}}), + Builder{} + .opType(BitwiseTypes::BITWISE_NOT) + .inputs( + {{{3}, + element::i32, + std::vector{std::numeric_limits::max(), std::numeric_limits::min(), -7}}}) + .expected( + {{3}, + element::i32, + std::vector{std::numeric_limits::min(), std::numeric_limits::max(), 6}}), + Builder{} + .opType(BitwiseTypes::BITWISE_NOT) + .inputs({{{3}, + element::u32, + std::vector{std::numeric_limits::max(), + std::numeric_limits::min(), + 7}}}) + .expected({{3}, + element::u32, + std::vector{std::numeric_limits::min(), + std::numeric_limits::max(), + std::numeric_limits::max() - 7}}), + Builder{} + .opType(BitwiseTypes::BITWISE_NOT) + .inputs( + {{{3}, + element::i64, + std::vector{std::numeric_limits::max(), std::numeric_limits::min(), -7}}}) + .expected( + {{3}, + element::i64, + std::vector{std::numeric_limits::min(), std::numeric_limits::max(), 6}}), + Builder{} + .opType(BitwiseTypes::BITWISE_NOT) + .inputs({{{3}, + element::u64, + std::vector{std::numeric_limits::max(), + std::numeric_limits::min(), + 7}}}) + .expected({{3}, + element::u64, + std::vector{std::numeric_limits::min(), + std::numeric_limits::max(), + std::numeric_limits::max() - 7}}), + }; + return bitwiseParams; +} + +INSTANTIATE_TEST_SUITE_P(smoke_BitwiseNot_With_Hardcoded_Refs, + ReferenceBitwiseLayerTest, + ::testing::ValuesIn(generateBitwiseParams()), + ReferenceBitwiseLayerTest::getTestCaseName); + +} // namespace +} // namespace BitwiseOpsRefTestDefinitions +} // namespace reference_tests diff --git a/src/tests/functional/plugin/conformance/test_runner/op_conformance_runner/src/op_impl_check/single_op_graph.cpp b/src/tests/functional/plugin/conformance/test_runner/op_conformance_runner/src/op_impl_check/single_op_graph.cpp index a5383310174..cd3f69e6e5f 100644 --- a/src/tests/functional/plugin/conformance/test_runner/op_conformance_runner/src/op_impl_check/single_op_graph.cpp +++ b/src/tests/functional/plugin/conformance/test_runner/op_conformance_runner/src/op_impl_check/single_op_graph.cpp @@ -1242,6 +1242,13 @@ std::shared_ptr generate(const std::shared_ptr &n return std::make_shared(results, ov::ParameterVector{param}, "is_nan_graph"); } +std::shared_ptr generate(const std::shared_ptr &node) { + const auto param = std::make_shared(ov::element::i64, ov::PartialShape{1, 2}); + auto bitwise = std::make_shared(param); + ov::ResultVector results{std::make_shared(bitwise)}; + return std::make_shared(results, ov::ParameterVector{param}, "BitwiseNotGraph"); +} + std::shared_ptr generateArithmeticReductionKeepDims(const std::shared_ptr &node) { const auto data = std::make_shared(ov::element::f32, ov::PartialShape{3, 3}); const auto axes = ov::op::v0::Constant::create(ov::element::i32, {1}, {1});