diff --git a/src/core/dev_api/openvino/core/dimension_tracker.hpp b/src/core/dev_api/openvino/core/dimension_tracker.hpp deleted file mode 100644 index 612ab4a01f8318..00000000000000 --- a/src/core/dev_api/openvino/core/dimension_tracker.hpp +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (C) 2018-2021 Intel Corporation -// SPDX-License-Identifier: Apache-2.0 -// - -#pragma once - -#include -#include -#include - -#include "openvino/core/dimension.hpp" -#include "openvino/core/partial_shape.hpp" -#include "openvino/core/type/element_type.hpp" - -namespace ov { -/// \brief Special label value indicate no label set. -constexpr label_t no_label = 0; - -/// \brief Friend class of Dimension to set, get and track dimensions and their equivalence -class OPENVINO_API DimensionTracker { -public: - DimensionTracker() = delete; - explicit DimensionTracker(const std::shared_ptr& table) : m_table_of_equivalence(table) { - OPENVINO_ASSERT(table != nullptr, - "Can not set nullptr as table of equivalence shared pointer for DimensionTracker"); - }; - - static void set_label(ov::Dimension& d, label_t label); - static bool has_label(const ov::Dimension& d); - static label_t get_label(const ov::Dimension& d); - - void set_table_of_equivalence(ov::Dimension& d) const; - static const std::shared_ptr& get_table_of_equivalence(const ov::Dimension& d); - - void set_up_for_tracking(ov::PartialShape& shape); - void set_up_for_tracking(ov::Dimension& d); - void set_up_for_tracking(ov::Dimension& d, label_t label) const; - static void reset_tracking_info(ov::Dimension& d); - -private: - std::shared_ptr m_table_of_equivalence; -}; - -using EqualitySoup = std::shared_ptr>; -using EqTable = std::unordered_map; -using ValTable = std::unordered_map; - -class OPENVINO_API TableOfEquivalence { -public: - explicit TableOfEquivalence(label_t label = 1) : current_label(label){}; - void set_as_equal(const ov::Dimension& lhs, const ov::Dimension& rhs); - bool are_equal(const ov::Dimension& lhs, const ov::Dimension& rhs); - - const EqTable& get_equivalence_table() const; - const ValTable& get_value_equivalence_table() const; - label_t get_next_label(); - -private: - label_t current_label; - EqTable dimension_table_of_equivalence; - ValTable value_table_of_equivalence; -}; - -} // namespace ov diff --git a/src/core/include/openvino/core/dimension.hpp b/src/core/include/openvino/core/dimension.hpp index 1bffc3174fac83..d89ea5a5e9fada 100644 --- a/src/core/include/openvino/core/dimension.hpp +++ b/src/core/include/openvino/core/dimension.hpp @@ -13,9 +13,11 @@ #include "openvino/core/interval.hpp" namespace ov { -class TableOfEquivalence; +class LabelTable; /// \brief Alias for dimension label type. using label_t = uint32_t; +/// \brief Special label value indicate no label set. +constexpr label_t no_label = 0; /// \brief Class representing a dimension, which may be dynamic (undetermined until runtime), /// in a shape or shape-like object. @@ -180,22 +182,33 @@ class OPENVINO_API Dimension { using std::swap; swap(a.m_dimension, b.m_dimension); swap(a.m_label, b.m_label); - swap(a.m_table_of_equivalence, b.m_table_of_equivalence); + swap(a.m_label_table, b.m_label_table); } /// \brief String representation of Dimension std::string to_string() const; + /// Label-related methods of ov::Dimension class + + /// \brief Indicates if meaningful label was set to the Dimension + bool has_label() const; + /// \brief Returns label of the Dimension + ov::label_t get_label() const; + /// \brief Sets label value to the Dimension + void set_label(const ov::label_t& label); + /// \brief Sets Label Table to the Dimension + void set_label_table(const std::shared_ptr& table); + /// \brief Returns Label Table + std::shared_ptr get_label_table() const; + private: Dimension(const Interval& interval) : m_dimension(interval) {} // The actual numerical value of the dimension. Interval m_dimension{}; - // private fields for dimension tracking - friend class DimensionTracker; - label_t m_label{0}; - std::shared_ptr m_table_of_equivalence = nullptr; + label_t m_label{ov::no_label}; + std::shared_ptr m_label_table = nullptr; }; /// \brief Insert a human-readable representation of a dimension into an output stream. diff --git a/src/core/include/openvino/core/label_table.hpp b/src/core/include/openvino/core/label_table.hpp new file mode 100644 index 00000000000000..f7834e7bd85a64 --- /dev/null +++ b/src/core/include/openvino/core/label_table.hpp @@ -0,0 +1,41 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include +#include +#include + +#include "openvino/core/dimension.hpp" +#include "openvino/core/partial_shape.hpp" +#include "openvino/core/type/element_type.hpp" + +namespace ov { +using EqualitySoup = std::shared_ptr>; +using EqTable = std::unordered_map; +using ValTable = std::unordered_map; + +class OPENVINO_API LabelTable : public std::enable_shared_from_this { +public: + explicit LabelTable(label_t label = 1) : current_label(label){}; + void set_as_equal(const ov::Dimension& lhs, const ov::Dimension& rhs); + bool are_equal(const ov::Dimension& lhs, const ov::Dimension& rhs); + + const EqTable& get_equivalence_table() const; + const ValTable& get_value_equivalence_table() const; + label_t get_next_label(); + + void set_up_for_tracking(ov::PartialShape& shape); + void set_up_for_tracking(ov::Dimension& d); + void set_up_for_tracking(ov::Dimension& d, label_t label); + static void reset_tracking_info(ov::Dimension& d); + +private: + label_t current_label; + EqTable dimension_table_of_equivalence; + ValTable value_table_of_equivalence; +}; + +} // namespace ov diff --git a/src/core/src/dimension.cpp b/src/core/src/dimension.cpp index c9e34a5758bec4..6e4abfe9d65f89 100644 --- a/src/core/src/dimension.cpp +++ b/src/core/src/dimension.cpp @@ -10,7 +10,7 @@ #include #include -#include "openvino/core/dimension_tracker.hpp" +#include "openvino/core/label_table.hpp" #include "openvino/util/common_util.hpp" using namespace ov; @@ -197,9 +197,9 @@ bool Dimension::merge(Dimension& dst, const Dimension& d1, const Dimension& d2) dst = Dimension(result_interval); } - if (auto& t = d1.m_table_of_equivalence) + if (auto& t = d1.m_label_table) t->set_as_equal(d1, d2); - else if (auto& t = d2.m_table_of_equivalence) + else if (auto& t = d2.m_label_table) t->set_as_equal(d1, d2); dst.m_label = merge_labels(d1.m_label, d2.m_label); @@ -242,3 +242,23 @@ Dimension::value_type Dimension::get_max_length() const { Dimension::value_type Dimension::get_min_length() const { return dimension_length(m_dimension.get_min_val()); } + +bool Dimension::has_label() const { + return m_label != ov::no_label; +} + +ov::label_t Dimension::get_label() const { + return m_label; +} + +void Dimension::set_label(const label_t& label) { + m_label = label; +} + +void Dimension::set_label_table(const std::shared_ptr& table) { + m_label_table = table; +} + +std::shared_ptr Dimension::get_label_table() const { + return m_label_table; +} diff --git a/src/core/src/dimension_tracker.cpp b/src/core/src/dimension_tracker.cpp deleted file mode 100644 index 4de869ead861e9..00000000000000 --- a/src/core/src/dimension_tracker.cpp +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (C) 2018-2021 Intel Corporation -// SPDX-License-Identifier: Apache-2.0 -// - -#include "openvino/core/dimension_tracker.hpp" - -using namespace ov; - -void TableOfEquivalence::set_as_equal(const Dimension& lhs, const Dimension& rhs) { - const auto &l_label = DimensionTracker::get_label(lhs), r_label = DimensionTracker::get_label(rhs); - if (l_label == ov::no_label || r_label == ov::no_label) - // TODO after value restriction enabling: non labeled dim propagates restriction (if any) to labeled dim - return; - - auto get_soup = [](const label_t& label, EqTable& table) -> EqualitySoup { - if (!table.count(label) || !table.at(label)) - table[label] = std::make_shared>(std::set{label}); - return table.at(label); - }; - - auto l_soup = get_soup(l_label, dimension_table_of_equivalence); - auto r_soup = get_soup(r_label, dimension_table_of_equivalence); - if (r_soup->size() > l_soup->size()) // we would like to minimize number of iterations in the following for-loop - std::swap(l_soup, r_soup); - l_soup->insert(r_soup->begin(), r_soup->end()); - for (const auto& label : *r_soup) - dimension_table_of_equivalence[label] = l_soup; -} - -const ValTable& TableOfEquivalence::get_value_equivalence_table() const { - return value_table_of_equivalence; -} - -const EqTable& TableOfEquivalence::get_equivalence_table() const { - return dimension_table_of_equivalence; -} - -label_t TableOfEquivalence::get_next_label() { - return current_label++; -} - -bool TableOfEquivalence::are_equal(const Dimension& lhs, const Dimension& rhs) { - if (!DimensionTracker::has_label(lhs) || !DimensionTracker::has_label(rhs)) - return false; - const auto &l_label = DimensionTracker::get_label(lhs), &r_label = DimensionTracker::get_label(rhs); - if (l_label == r_label) - return true; - if (dimension_table_of_equivalence.count(l_label) && dimension_table_of_equivalence[l_label]) - return dimension_table_of_equivalence[l_label]->count(r_label); - return false; -} - -void DimensionTracker::set_label(Dimension& d, label_t label) { - OPENVINO_ASSERT(label != no_label, "Can not set zero as label for dimension -- it is reserved for no label"); - d.m_label = label; -} - -bool DimensionTracker::has_label(const Dimension& d) { - return d.m_label != no_label; -} - -label_t DimensionTracker::get_label(const Dimension& d) { - return d.m_label; -} - -const std::shared_ptr& DimensionTracker::get_table_of_equivalence(const Dimension& d) { - return d.m_table_of_equivalence; -} - -void DimensionTracker::set_table_of_equivalence(Dimension& d) const { - OPENVINO_ASSERT(d.m_table_of_equivalence == nullptr, "Dimension is already being tracked"); - OPENVINO_ASSERT(m_table_of_equivalence != nullptr, "Can not set nullptr as table of equivalence shared pointer"); - d.m_table_of_equivalence = m_table_of_equivalence; -} - -void DimensionTracker::reset_tracking_info(Dimension& d) { - d.m_label = no_label; - d.m_table_of_equivalence = nullptr; -} - -void DimensionTracker::set_up_for_tracking(Dimension& d) { - set_up_for_tracking(d, m_table_of_equivalence->get_next_label()); -} - -void DimensionTracker::set_up_for_tracking(Dimension& d, label_t label) const { - set_label(d, label); - set_table_of_equivalence(d); -} - -void DimensionTracker::set_up_for_tracking(ov::PartialShape& shape) { - for (auto& d : shape) - set_up_for_tracking(d); -} diff --git a/src/core/src/label_table.cpp b/src/core/src/label_table.cpp new file mode 100644 index 00000000000000..51f4c62cee3a19 --- /dev/null +++ b/src/core/src/label_table.cpp @@ -0,0 +1,70 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "openvino/core/label_table.hpp" + +using namespace ov; + +void LabelTable::set_as_equal(const Dimension& lhs, const Dimension& rhs) { + const auto &l_label = lhs.get_label(), r_label = rhs.get_label(); + if (l_label == ov::no_label || r_label == ov::no_label) + // TODO after value restriction enabling: non labeled dim propagates restriction (if any) to labeled dim + return; + + auto get_soup = [](const label_t& label, EqTable& table) -> EqualitySoup { + if (!table.count(label) || !table.at(label)) + table[label] = std::make_shared>(std::set{label}); + return table.at(label); + }; + + auto l_soup = get_soup(l_label, dimension_table_of_equivalence); + auto r_soup = get_soup(r_label, dimension_table_of_equivalence); + if (r_soup->size() > l_soup->size()) // we would like to minimize number of iterations in the following for-loop + std::swap(l_soup, r_soup); + l_soup->insert(r_soup->begin(), r_soup->end()); + for (const auto& label : *r_soup) + dimension_table_of_equivalence[label] = l_soup; +} + +const ValTable& LabelTable::get_value_equivalence_table() const { + return value_table_of_equivalence; +} + +const EqTable& LabelTable::get_equivalence_table() const { + return dimension_table_of_equivalence; +} + +label_t LabelTable::get_next_label() { + return current_label++; +} + +bool LabelTable::are_equal(const Dimension& lhs, const Dimension& rhs) { + if (!lhs.has_label() || !rhs.has_label()) + return false; + const auto &l_label = lhs.get_label(), &r_label = rhs.get_label(); + if (l_label == r_label) + return true; + if (dimension_table_of_equivalence.count(l_label) && dimension_table_of_equivalence[l_label]) + return dimension_table_of_equivalence[l_label]->count(r_label); + return false; +} + +void LabelTable::reset_tracking_info(Dimension& d) { + d.set_label(no_label); + d.set_label_table(nullptr); +} + +void LabelTable::set_up_for_tracking(Dimension& d) { + set_up_for_tracking(d, get_next_label()); +} + +void LabelTable::set_up_for_tracking(Dimension& d, label_t label) { + d.set_label(label); // TODO: should we update current label if user uses larger label? + d.set_label_table(this->shared_from_this()); +} + +void LabelTable::set_up_for_tracking(ov::PartialShape& shape) { + for (auto& d : shape) + set_up_for_tracking(d); +}