[Core] Assure TensorVector comparison uniqueness (#16232)
* Assure TensorVector comparison uniqueness * Add test * Make the flow clear
This commit is contained in:
@@ -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<bool>(lhs) < static_cast<bool>(*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<TensorVector, TensorVectorCmp> 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());
|
||||
|
||||
@@ -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<Parameter>(et, PartialShape{s});
|
||||
const auto b = Constant::create(et, s, {1});
|
||||
const auto sub = std::make_shared<Subtract>(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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user