Skip to content

Commit

Permalink
[Ref][Core][Opset13] Add BitwiseNot operation (openvinotoolkit#19956)
Browse files Browse the repository at this point in the history
* [Ref][Core][Opset13] Add bitwise_not operation

* Fix CI issues + add missing test

* improve test

* formatting

* Requested changes

* Remove unused include

* Add requested changes

* Try to fix test problems

* Fix CI

* Fix type validation

* Add checks in template eval
  • Loading branch information
mmikolajcz authored and alvoron committed Nov 6, 2023
1 parent d948c88 commit 9677eae
Show file tree
Hide file tree
Showing 17 changed files with 475 additions and 1 deletion.
30 changes: 30 additions & 0 deletions src/core/include/openvino/op/bitwise_not.hpp
Original file line number Diff line number Diff line change
@@ -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<Node>& arg);

void validate_and_infer_types() override;

std::shared_ptr<Node> clone_with_new_inputs(const OutputVector& new_args) const override;
};
} // namespace v13
} // namespace op
} // namespace ov
1 change: 1 addition & 0 deletions src/core/include/openvino/op/ops.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
1 change: 1 addition & 0 deletions src/core/include/openvino/opsets/opset13_tbl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
36 changes: 36 additions & 0 deletions src/core/reference/include/openvino/reference/bitwise_not.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (C) 2018-2023 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//

#pragma once

#include <algorithm>
#include <cstddef>

namespace ov {
namespace reference {
namespace func {
// Check for char datatype used by ov::element::boolean
template <class T, typename std::enable_if<std::is_same<typename std::decay<T>::type, char>::value>::type* = nullptr>
T bitwise_not(const T in) {
return static_cast<T>(!in);
}

template <class T, typename std::enable_if<!std::is_same<typename std::decay<T>::type, char>::value>::type* = nullptr>
T bitwise_not(const T in) {
return static_cast<T>(~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 <class T>
void bitwise_not(const T* in, T* out, size_t count) {
std::transform(in, std::next(in, count), out, &func::bitwise_not<T>);
}
} // namespace reference
} // namespace ov
33 changes: 33 additions & 0 deletions src/core/src/op/bitwise_not.cpp
Original file line number Diff line number Diff line change
@@ -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<Node>& 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<Node> 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<BitwiseNot>(new_args.at(0));
}

} // namespace v13
} // namespace op
} // namespace ov
1 change: 1 addition & 0 deletions src/core/tests/op_version_tbl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion src/core/tests/opset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
85 changes: 85 additions & 0 deletions src/core/tests/type_prop/bitwise_not.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright (C) 2018-2023 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//

#include "openvino/op/bitwise_not.hpp"

#include <gtest/gtest.h>

#include "common_test_utils/test_assertions.hpp"
#include "common_test_utils/type_prop.hpp"

using namespace ov;
using namespace testing;

using BitwiseNotTestParam = std::tuple<element::Type, PartialShape>;

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<ov::op::v13::BitwiseNot>, public WithParamInterface<BitwiseNotTestParam> {
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<ov::op::v0::Parameter>(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<ov::op::v0::Parameter>(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<ov::op::v0::Parameter>(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::op::v0::Parameter>(ov::element::f32, ov::Shape{2, 2});
OV_EXPECT_THROW(std::ignore = std::make_shared<ov::op::v13::BitwiseNot>(data),
ov::NodeValidationFailure,
HasSubstr("The element type of the input tensor must be integer or boolean."));
}
11 changes: 11 additions & 0 deletions src/core/tests/visitors/op/bitwise_not.cpp
Original file line number Diff line number Diff line change
@@ -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<UnaryOperatorType<ov::op::v13::BitwiseNot, ov::element::i32>>;

INSTANTIATE_TYPED_TEST_SUITE_P(visitor_without_attribute, UnaryOperatorVisitor, Type, UnaryOperatorTypeName);
52 changes: 52 additions & 0 deletions src/plugins/template/backend/ops/bitwise_not.cpp
Original file line number Diff line number Diff line change
@@ -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 <element::Type_t ET>
bool evaluate(const std::shared_ptr<ov::op::v13::BitwiseNot>& 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<ET>::value_type;
ov::reference::bitwise_not(inputs[0].data<T>(), outputs[0].data<T>(), shape_size(inputs[0].get_shape()));
return true;
}

template <>
bool evaluate_node<op::v13::BitwiseNot>(std::shared_ptr<ov::Node> node,
ov::TensorVector& outputs,
const ov::TensorVector& inputs) {
switch (node->get_input_element_type(0)) {
case element::boolean:
return evaluate<element::boolean>(as_type_ptr<op::v13::BitwiseNot>(node), outputs, inputs);
case element::u8:
return evaluate<element::u8>(as_type_ptr<op::v13::BitwiseNot>(node), outputs, inputs);
case element::i8:
return evaluate<element::i8>(as_type_ptr<op::v13::BitwiseNot>(node), outputs, inputs);
case element::u16:
return evaluate<element::u16>(as_type_ptr<op::v13::BitwiseNot>(node), outputs, inputs);
case element::i16:
return evaluate<element::i16>(as_type_ptr<op::v13::BitwiseNot>(node), outputs, inputs);
case element::u32:
return evaluate<element::u32>(as_type_ptr<op::v13::BitwiseNot>(node), outputs, inputs);
case element::i32:
return evaluate<element::i32>(as_type_ptr<op::v13::BitwiseNot>(node), outputs, inputs);
case element::u64:
return evaluate<element::u64>(as_type_ptr<op::v13::BitwiseNot>(node), outputs, inputs);
case element::i64:
return evaluate<element::i64>(as_type_ptr<op::v13::BitwiseNot>(node), outputs, inputs);
default:
OPENVINO_THROW("Unhandled data type ", node->get_element_type().get_type_name(), "in evaluate_node()");
}
}
4 changes: 4 additions & 0 deletions src/plugins/template/backend/ops/ops_evaluates.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,10 @@ extern template bool evaluate_node<ov::op::v12::GroupNormalization>(std::shared_
ov::TensorVector& outputs,
const ov::TensorVector& inputs);

extern template bool evaluate_node<ov::op::v13::BitwiseNot>(std::shared_ptr<ov::Node> node,
ov::TensorVector& outputs,
const ov::TensorVector& inputs);

extern template bool evaluate_node<ov::op::internal::AUGRUCell>(std::shared_ptr<ov::Node> node,
ov::TensorVector& outputs,
const ov::TensorVector& inputs);
Expand Down
2 changes: 2 additions & 0 deletions src/plugins/template/backend/opset_int_tbl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
1 change: 1 addition & 0 deletions src/plugins/template/src/plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
17 changes: 17 additions & 0 deletions src/plugins/template/tests/functional/op_reference/bitwise.cpp
Original file line number Diff line number Diff line change
@@ -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
Loading

0 comments on commit 9677eae

Please sign in to comment.