diff --git a/src/core/src/bound_evaluate.cpp b/src/core/src/bound_evaluate.cpp index 930d71b80ce..1aea44f9fa7 100644 --- a/src/core/src/bound_evaluate.cpp +++ b/src/core/src/bound_evaluate.cpp @@ -179,14 +179,26 @@ ov::Tensor or_tensor(const ov::Tensor& lhs, const ov::Tensor& rhs) { } struct TensorVectorCmp { + // Comparing Tensor vectors as numbers composed with pointers as digits. + // Indexed loop used to preserve order of comparison. bool operator()(const ov::TensorVector& lhs, const ov::TensorVector& rhs) const { - auto rhs_it = rhs.begin(); - return std::any_of(lhs.begin(), lhs.end(), [&rhs_it](const ov::Tensor& lhs) { - bool is_less = - (lhs && *rhs_it) ? lhs.data() < rhs_it->data() : static_cast(lhs) < static_cast(*rhs_it); - ++rhs_it; - return is_less; - }); + const auto lhs_size = lhs.size(); + const auto rhs_size = rhs.size(); + + if (lhs_size < rhs_size) + return true; + if (lhs_size > rhs_size) + return false; + + for (size_t i = 0; i < lhs_size; ++i) { + if (lhs[i].data() < rhs[i].data()) + return true; + if (lhs[i].data() > rhs[i].data()) + return false; + } + + // if all equals + return false; } }; @@ -281,17 +293,14 @@ bool ov::interval_bound_evaluator(const Node* node, auto low_1 = ov::evaluate_lower_bound(node->get_input_source_output(1)); auto up_0 = ov::evaluate_upper_bound(node->get_input_source_output(0)); auto up_1 = ov::evaluate_upper_bound(node->get_input_source_output(1)); + if (!low_0 || !low_1 || !up_0 || !up_1) + return false; std::set input_variants = {{low_0, low_1}, {low_0, up_1}, {up_0, low_1}, {up_0, up_1}}; - for (const auto& variant_of_input_vector : input_variants) - for (const auto& input_tensor : variant_of_input_vector) - if (!input_tensor) - return false; - if (input_variants.size() == 1) return node->evaluate(upper_output_values, *input_variants.begin()) && node->evaluate(lower_output_values, *input_variants.begin()); diff --git a/src/core/tests/bound_evaluate.cpp b/src/core/tests/bound_evaluate.cpp index cb855ddfa76..664f8ebcb81 100644 --- a/src/core/tests/bound_evaluate.cpp +++ b/src/core/tests/bound_evaluate.cpp @@ -51,3 +51,31 @@ TEST_F(EvaluateBoundTest, no_exception_when_node_has_output_with_dynamic_element EXPECT_NO_THROW(evaluate_both_bounds(fn_op)); } + +using BoundEvaluatorTest = ::testing::Test; +TEST(BoundEvaluatorTest, no_exception_on_single_bound) { + constexpr auto et = element::i32; + const auto s = Shape{1, 1}; + const auto a = std::make_shared(et, PartialShape{s}); + const auto b = Constant::create(et, s, {1}); + const auto sub = std::make_shared(a, b); + + int32_t a_l[1] = {1}; + a->get_output_tensor(0).set_lower_value(Tensor{et, s, a_l}); + + int32_t o_[1] = {INT32_MIN}; // initial value of output tensor is not needed, it's set to check whether changed + TensorVector output{{et, s, o_}}; + // evaluations won't be performed due to missing upper bound tensor of parameter a + ASSERT_NO_THROW(sub->evaluate_lower(output)); + EXPECT_EQ(o_[0], INT32_MIN); + ASSERT_NO_THROW(sub->evaluate_upper(output)); + EXPECT_EQ(o_[0], INT32_MIN); + + int32_t a_u[1] = {11}; + a->get_output_tensor(0).set_upper_value(Tensor{et, s, a_u}); + // now both bounds of sub node can be calculated + ASSERT_NO_THROW(sub->evaluate_lower(output)); + EXPECT_EQ(o_[0], 0); + ASSERT_NO_THROW(sub->evaluate_upper(output)); + EXPECT_EQ(o_[0], 10); +}