diff --git a/mindspore/core/abstract/abstract_function.cc b/mindspore/core/abstract/abstract_function.cc index ca8dff5e5a3..3d05feac83c 100644 --- a/mindspore/core/abstract/abstract_function.cc +++ b/mindspore/core/abstract/abstract_function.cc @@ -23,80 +23,124 @@ namespace mindspore { namespace abstract { class Evaluator; class AnalysisEngine; +// Function to create an AbstractFunction from a list of AbstractFuncAtomPtr. AbstractFunctionPtr AbstractFunction::MakeAbstractFunction(const AbstractFuncAtomPtrList &func_list) { + // Check the size of the input list. if (func_list.size() == 1) { + // If there is only one element in the list, return that element. return func_list[0]; } + // If there are multiple elements in the list, create an AbstractFuncUnion. return std::make_shared(func_list); } +// Join two AbstractFunctions into a single AbstractFunction. AbstractFunctionPtr AbstractFuncAtom::Join(const AbstractFunctionPtr &other) { + // Check if the 'other' AbstractFunction pointer is not null. MS_EXCEPTION_IF_NULL(other); + + // Get a shared pointer to the current AbstractFuncAtom. auto this_func = shared_from_base(); + if (other->isa()) { + // If 'other' is an AbstractFuncAtom, check if the two AbstractFuncAtoms are equal. if (*this_func == *other) { + // If they are equal, return the current AbstractFuncAtom. return this_func; } + // If they are not equal, create an AbstractFuncUnion with both AbstractFuncAtoms. return std::make_shared(this_func, other); } + + // If 'other' is an AbstractFuncUnion, check if it is a superset of the current AbstractFuncAtom. auto other_union = dyn_cast(other); MS_EXCEPTION_IF_NULL(other_union); + if (other_union->IsSuperSet(this_func)) { + // If 'other_union' is a superset of the current AbstractFuncAtom, return 'other'. return other; } + + // If 'other_union' is not a superset, create an AbstractFuncUnion with both AbstractFunctions. return std::make_shared(this_func, other); } +// Visit function to perform an operation on the current AbstractFuncAtom. void AbstractFuncAtom::Visit(std::function visit_func) const { + // Call the 'visit_func' function with the current AbstractFuncAtom. visit_func(const_cast(this)->shared_from_base()); } -bool AbstractFuncAtom::operator==(const AbstractFunction &other) const { return this == &other; } +// Equality comparison operator for AbstractFunction. +bool AbstractFuncAtom::operator==(const AbstractFunction &other) const { + // Check if the current AbstractFunction is equal to 'other' by comparing their addresses. + return this == &other; +} -AbstractFuncUnion::AbstractFuncUnion(const AbstractFuncAtomPtrList &func_list) { func_list_ = func_list; } +// Constructor for AbstractFuncUnion with a list of AbstractFuncAtom pointers. +AbstractFuncUnion::AbstractFuncUnion(const AbstractFuncAtomPtrList &func_list) { + func_list_ = func_list; +} +// Constructor for AbstractFuncUnion with two AbstractFunctions. AbstractFuncUnion::AbstractFuncUnion(const AbstractFunctionPtr &first, const AbstractFunctionPtr &second) { AbstractFuncAtomPtrList new_func_list; - auto build_func_list = [&new_func_list](const AbstractFuncAtomPtr &func) { new_func_list.push_back(func); }; + auto build_func_list = [&new_func_list](const AbstractFuncAtomPtr &func) { + new_func_list.push_back(func); + }; + + // Check if the input AbstractFunctions are not null. MS_EXCEPTION_IF_NULL(first); MS_EXCEPTION_IF_NULL(second); + + // Visit both AbstractFunctions and build the list. first->Visit(build_func_list); second->Visit(build_func_list); + func_list_ = new_func_list; } +// Convert AbstractFuncUnion to a string. std::string AbstractFuncUnion::ToString() const { std::ostringstream buffer; buffer << "AbstractFuncUnion({"; int64_t i = 0; + for (const auto &func : func_list_) { MS_EXCEPTION_IF_NULL(func); buffer << "[" << i << "]: " << func->ToString() << ", "; i++; } + buffer << "})"; return buffer.str(); } +// Convert AbstractFuncUnion to a string, optionally in a verbose mode. std::string AbstractFuncUnion::ToString(bool verbose) const { if (verbose) { return ToString(); } + std::ostringstream buffer; buffer << type_name() << "({"; size_t i = 0; + for (const auto &func : func_list_) { MS_EXCEPTION_IF_NULL(func); buffer << func->ToString(false); i++; + if (i < func_list_.size()) { buffer << ", "; } } + buffer << "})"; return buffer.str(); } +// Check if the current AbstractFuncUnion is a superset of another AbstractFunction. bool AbstractFuncUnion::IsSuperSet(const AbstractFunctionPtr &other) { MS_EXCEPTION_IF_NULL(other); std::vector is_in_list; @@ -107,61 +151,90 @@ bool AbstractFuncUnion::IsSuperSet(const AbstractFunctionPtr &other) { } return true; }; + + // Visit 'other' AbstractFunction and build a list of whether each element is in the current AbstractFuncUnion. other->Visit(build_in_list); + + // Check if all elements in the 'is_in_list' are true. return std::all_of(is_in_list.begin(), is_in_list.end(), [](bool is_in) { return is_in; }); } +// Join two AbstractFunctions into a single AbstractFunction. AbstractFunctionPtr AbstractFuncUnion::Join(const AbstractFunctionPtr &other) { + // Get a shared pointer to the current AbstractFunction. auto this_func = shared_from_base(); MS_EXCEPTION_IF_NULL(other); + if (other->isa()) { + // If 'other' is an AbstractFuncAtom, check if the current AbstractFuncUnion is a superset of 'other'. if (IsSuperSet(other)) { + // If it is a superset, return the current AbstractFunction. return this_func; } + // If not a superset, create an AbstractFuncUnion with both AbstractFunctions. return std::make_shared(this_func, other); } + + // If 'other' is an AbstractFuncUnion, check if it is a superset of the current AbstractFunction. auto other_union = dyn_cast(other); MS_EXCEPTION_IF_NULL(other_union); + if (other_union->IsSuperSet(this_func)) { + // If it is a superset, return 'other'. return other; } + + // If not a superset, create an AbstractFuncUnion with both AbstractFunctions. return std::make_shared(this_func, other); } +// Visit function to perform an operation on each element of the AbstractFuncUnion. void AbstractFuncUnion::Visit(std::function visit_func) const { for (const AbstractFuncAtomPtr &poss : func_list_) { visit_func(poss); } } +// Equality comparison operator for AbstractFunction. bool AbstractFuncUnion::operator==(const AbstractFunction &other) const { if (!other.isa()) { return false; } + auto other_union = static_cast(&other); + if (func_list_.size() != other_union->func_list_.size()) { return false; } + + // Check if the func_list_ vectors are equal. return func_list_ == other_union->func_list_; } +// Hash function for AbstractFuncUnion. std::size_t AbstractFuncUnion::hash() const { std::size_t hash_sum = 0; + for (const auto &f : func_list_) { MS_EXCEPTION_IF_NULL(f); hash_sum = hash_combine(hash_sum, f->hash()); } + return hash_sum; } +// Equality comparison operator for PrimitiveAbstractClosure. bool PrimitiveAbstractClosure::operator==(const AbstractFunction &other) const { if (!other.isa()) { return false; } + const auto &other_abs = static_cast(other); + // Check if both 'prim_' and 'tracking_id()' are equal. return (prim_ == other_abs.prim_) && (tracking_id() == other_abs.tracking_id()); } +// Hash function for PrimitiveAbstractClosure. std::size_t PrimitiveAbstractClosure::hash() const { // Keep in sync with operator==() which compares tid, prim_ & tracking_id; auto hash_value = static_cast(tid()); @@ -170,6 +243,7 @@ std::size_t PrimitiveAbstractClosure::hash() const { return hash_value; } +// Convert PrimitiveAbstractClosure to a string. std::string PrimitiveAbstractClosure::ToString(bool verbose) const { if (verbose) { return ToString(); @@ -177,15 +251,18 @@ std::string PrimitiveAbstractClosure::ToString(bool verbose) const { return type_name() + " (" + prim_->name() + ")"; } +// Equality comparison operator for FuncGraphAbstractClosure. bool FuncGraphAbstractClosure::operator==(const AbstractFunction &other) const { if (!other.isa()) { return false; } auto other_fg = static_cast(&other); + // Check if 'func_graph_', 'context_', and 'tracking_id()' are equal. return func_graph_ == other_fg->func_graph_ && context_ == other_fg->context_ && tracking_id() == other_fg->tracking_id(); } +// Hash function for FuncGraphAbstractClosure. std::size_t FuncGraphAbstractClosure::hash() const { auto hash_value = hash_combine(tid(), func_graph_->hash()); hash_value = hash_combine(hash_value, context_->hash()); @@ -195,6 +272,7 @@ std::size_t FuncGraphAbstractClosure::hash() const { return hash_value; } +// Convert FuncGraphAbstractClosure to a string. std::string FuncGraphAbstractClosure::ToString() const { std::stringstream ss; MS_EXCEPTION_IF_NULL(func_graph_); @@ -204,6 +282,7 @@ std::string FuncGraphAbstractClosure::ToString() const { return ss.str(); } +// Convert FuncGraphAbstractClosure to a string, optionally in a verbose mode. std::string FuncGraphAbstractClosure::ToString(bool verbose) const { if (verbose) { return ToString(); @@ -214,14 +293,17 @@ std::string FuncGraphAbstractClosure::ToString(bool verbose) const { return ss.str(); } +// Equality comparison operator for MetaFuncGraphAbstractClosure. bool MetaFuncGraphAbstractClosure::operator==(const AbstractFunction &other) const { if (!other.isa()) { return false; } auto other_meta_fg = static_cast(&other); + // Check if 'meta_func_graph_' and 'tracking_id()' are equal. return meta_func_graph_ == other_meta_fg->meta_func_graph_ && tracking_id() == other_meta_fg->tracking_id(); } +// Hash function for MetaFuncGraphAbstractClosure. std::size_t MetaFuncGraphAbstractClosure::hash() const { MS_EXCEPTION_IF_NULL(meta_func_graph_); auto hash_value = hash_combine(tid(), meta_func_graph_->hash()); @@ -231,16 +313,19 @@ std::size_t MetaFuncGraphAbstractClosure::hash() const { return hash_value; } +// Convert MetaFuncGraphAbstractClosure to a string. std::string MetaFuncGraphAbstractClosure::ToString() const { MS_EXCEPTION_IF_NULL(meta_func_graph_); return "MetaFuncGraphAbstractClosure: " + meta_func_graph_->name(); } +// Equality comparison operator for PartialAbstractClosure. bool PartialAbstractClosure::operator==(const AbstractFunction &other) const { if (!other.isa()) { return false; } auto other_partial = static_cast(&other); + // Check if 'fn_' and 'args_spec_list_' are equal. if (fn_ != other_partial->fn_) { return false; } @@ -250,6 +335,7 @@ bool PartialAbstractClosure::operator==(const AbstractFunction &other) const { return args_spec_list_ == other_partial->args_spec_list_; } +// Hash function for PartialAbstractClosure. std::size_t PartialAbstractClosure::hash() const { MS_EXCEPTION_IF_NULL(fn_); auto hash_value = hash_combine(tid(), fn_->hash()); @@ -257,6 +343,7 @@ std::size_t PartialAbstractClosure::hash() const { return hash_value; } +// Convert PartialAbstractClosure to a string. std::string PartialAbstractClosure::ToString() const { std::ostringstream buffer; buffer << "PartialAbstractClosure(" << fn_->ToString() << "("; @@ -274,6 +361,7 @@ std::string PartialAbstractClosure::ToString() const { return buffer.str(); } +// Convert PartialAbstractClosure to a string, optionally in a verbose mode. std::string PartialAbstractClosure::ToString(bool verbose) const { if (verbose) { return ToString(); @@ -283,57 +371,69 @@ std::string PartialAbstractClosure::ToString(bool verbose) const { return buffer.str(); } +// Equality comparison operator for JTransformedAbstractClosure. bool JTransformedAbstractClosure::operator==(const AbstractFunction &other) const { if (!other.isa()) { return false; } auto other_transformed = static_cast(&other); + // Check if 'fn_' is equal. return fn_ == other_transformed->fn_; } +// Hash function for JTransformedAbstractClosure. std::size_t JTransformedAbstractClosure::hash() const { MS_EXCEPTION_IF_NULL(fn_); auto hash_value = hash_combine(tid(), fn_->hash()); return hash_value; } +// Equality comparison operator for TaylorTransformedAbstractClosure. bool TaylorTransformedAbstractClosure::operator==(const AbstractFunction &other) const { if (!other.isa()) { return false; } auto other_transformed = static_cast(&other); + // Check if 'fn_' is equal. return fn_ == other_transformed->fn_; } +// Hash function for TaylorTransformedAbstractClosure. std::size_t TaylorTransformedAbstractClosure::hash() const { MS_EXCEPTION_IF_NULL(fn_); auto hash_value = hash_combine(tid(), fn_->hash()); return hash_value; } +// Equality comparison operator for ShardTransformedAbstractClosure. bool ShardTransformedAbstractClosure::operator==(const AbstractFunction &other) const { if (!other.isa()) { return false; } auto other_transformed = static_cast(&other); + // Check if 'fn_' is equal. return fn_ == other_transformed->fn_; } +// Hash function for ShardTransformedAbstractClosure. std::size_t ShardTransformedAbstractClosure::hash() const { MS_EXCEPTION_IF_NULL(fn_); auto hash_value = hash_combine(tid(), fn_->hash()); return hash_value; } +// Equality comparison operator for VmapTransformedAbstractClosure. bool VmapTransformedAbstractClosure::operator==(const AbstractFunction &other) const { if (!other.isa()) { return false; } auto other_transformed = static_cast(&other); + // Check if 'fn_', 'in_axes_', and 'out_axes_' are equal. return fn_ == other_transformed->fn_ && in_axes_ == other_transformed->in_axes_ && out_axes_ == other_transformed->out_axes_; } +// Hash function for VmapTransformedAbstractClosure. std::size_t VmapTransformedAbstractClosure::hash() const { MS_EXCEPTION_IF_NULL(fn_); MS_EXCEPTION_IF_NULL(in_axes_); @@ -342,11 +442,13 @@ std::size_t VmapTransformedAbstractClosure::hash() const { return hash_value; } +// Equality comparison operator for VirtualAbstractClosure. bool VirtualAbstractClosure::operator==(const AbstractFunction &other) const { if (!other.isa()) { return false; } auto other_virtual = static_cast(&other); + // Check if 'output_' and 'args_spec_list_' are equal. if (output_ != other_virtual->output_) { return false; } @@ -356,6 +458,7 @@ bool VirtualAbstractClosure::operator==(const AbstractFunction &other) const { return args_spec_list_ == other_virtual->args_spec_list_; } +// Hash function for VirtualAbstractClosure. std::size_t VirtualAbstractClosure::hash() const { MS_EXCEPTION_IF_NULL(output_); auto hash_value = hash_combine(tid(), output_->hash()); @@ -363,6 +466,7 @@ std::size_t VirtualAbstractClosure::hash() const { return hash_value; } +// Convert VirtualAbstractClosure to a string. std::string VirtualAbstractClosure::ToString() const { std::ostringstream buffer; buffer << "VirtualAbstractClosure(args: {"; @@ -383,11 +487,13 @@ std::string VirtualAbstractClosure::ToString() const { return buffer.str(); } +// Equality comparison operator for TypedPrimitiveAbstractClosure. bool TypedPrimitiveAbstractClosure::operator==(const AbstractFunction &other) const { if (!other.isa()) { return false; } auto other_typed = static_cast(&other); + // Check if 'output_', 'prim_', and 'args_spec_list_' are equal. if (output_ != other_typed->output_) { return false; } @@ -400,15 +506,20 @@ bool TypedPrimitiveAbstractClosure::operator==(const AbstractFunction &other) co return args_spec_list_ == other_typed->args_spec_list_; } +// Hash function for TypedPrimitiveAbstractClosure. std::size_t TypedPrimitiveAbstractClosure::hash() const { - auto hash_value = hash_combine(tid(), prim_->hash()); + MS_EXCEPTION_IF_NULL(output_); + MS_EXCEPTION_IF_NULL(prim_); + auto hash_value = hash_combine(tid(), output_->hash()); + hash_value = hash_combine(hash_value, PointerHash{}(prim_)); hash_value = hash_combine(hash_value, AbstractBasePtrListHash(args_spec_list_)); return hash_value; } +// Convert TypedPrimitiveAbstractClosure to a string. std::string TypedPrimitiveAbstractClosure::ToString() const { std::ostringstream buffer; - buffer << "TypedPrimitiveAbstractClosure: primitive: " << prim_->name() << "(args: {"; + buffer << "TypedPrimitiveAbstractClosure(args: {"; int64_t i = 0; for (const auto &arg : args_spec_list_) { MS_EXCEPTION_IF_NULL(arg); @@ -425,5 +536,6 @@ std::string TypedPrimitiveAbstractClosure::ToString() const { buffer << "}, output: " << output_->ToString() << ")"; return buffer.str(); } + } // namespace abstract } // namespace mindspore diff --git a/mindspore/core/abstract/abstract_function.h b/mindspore/core/abstract/abstract_function.h index 917cb23876d..c2246665cb2 100644 --- a/mindspore/core/abstract/abstract_function.h +++ b/mindspore/core/abstract/abstract_function.h @@ -38,14 +38,25 @@ class MS_CORE_API AbstractFuncAtom : public AbstractFunction { ~AbstractFuncAtom() override = default; MS_DECLARE_PARENT(AbstractFuncAtom, AbstractFunction) + /// Override the GetUnique function to return a shared pointer to the current instance. AbstractFunctionPtr GetUnique() override { return shared_from_base(); } + /// Override the Join function to merge two instances of AbstractFunction. + /// \param[in] other: Another instance of AbstractFunction to merge with. + /// \return The merged AbstractFunction. AbstractFunctionPtr Join(const AbstractFunctionPtr &other) final; + /// Override the Visit function to perform an action on the current instance. + /// \param[in] func: A function that accepts an AbstractFuncAtomPtr and performs an action on it. void Visit(std::function) const final; + /// Override the equality operator to compare the current instance with another AbstractFunction. + /// \param[in] other: Another AbstractFunction to compare with. + /// \return True if the two instances are equal, false otherwise. bool operator==(const AbstractFunction &other) const override; + /// Override the hash function to return the type ID as a hash value. + /// \return The hash value based on the type ID. std::size_t hash() const override { return tid(); } }; @@ -80,14 +91,26 @@ class MS_CORE_API AbstractFuncUnion final : public AbstractFunction { /// \return Return true if other is in AbstractFuncUnion, otherwise return False. bool IsSuperSet(const AbstractFunctionPtr &other); + /// Override the Join function to merge two instances of AbstractFunction. + /// \param[in] other: Another instance of AbstractFunction to merge with. + /// \return The merged AbstractFunction. AbstractFunctionPtr Join(const AbstractFunctionPtr &other) final; + /// Override the Visit function to perform an action on the current instance. + /// \param[in] func: A function that accepts an AbstractFuncAtomPtr and performs an action on it. void Visit(std::function) const final; + /// Override the equality operator to compare the current instance with another AbstractFunction. + /// \param[in] other: Another AbstractFunction to compare with. + /// \return True if the two instances are equal, false otherwise. bool operator==(const AbstractFunction &other) const override; + /// Override the hash function to return the type ID as a hash value. + /// \return The hash value based on the type ID. std::size_t hash() const override; + /// Override the Copy function to create a copy of the current instance. + /// This function should not be used for AbstractFuncUnion, so it throws an exception. AbstractFunctionPtr Copy() const override { MS_LOG(EXCEPTION) << "Cannot Copy from AbstractFuncUnion"; } private: @@ -113,20 +136,38 @@ class MS_CORE_API PrimitiveAbstractClosure final : public AbstractFuncAtom { /// \return The Primitive that this PrimitiveAbstractClosure corresponding to. PrimitivePtr prim() { return prim_; } + /// Override the tracking_id function to get the tracking ID of this AbstractFunction. + /// \return The tracking ID of this AbstractFunction as an AnfNodePtr. AnfNodePtr tracking_id() const override { return tracking_id_.lock(); } + /// Override the set_tracking_id function to set the tracking ID of this AbstractFunction. + /// \param[in] node: The AnfNodePtr to set as the tracking ID. void set_tracking_id(AnfNodePtr node) override { tracking_id_ = AnfNodeWeakPtr(node); } + /// Override the Copy function to create a copy of the current instance. + /// \return A copy of the current AbstractFunction as an AbstractFunctionPtr. AbstractFunctionPtr Copy() const override { return std::make_shared(prim_, tracking_id()); } + /// Override the equality operator to compare the current instance with another AbstractFunction. + /// \param[in] other: Another AbstractFunction to compare with. + /// \return True if the two instances are equal, false otherwise. bool operator==(const AbstractFunction &other) const override; + /// Override the hash function to return a hash value based on the type ID. + /// \return The hash value based on the type ID. std::size_t hash() const override; + /// Override the ToString function to provide a string representation of this AbstractFunction. + /// \return A string describing this AbstractFunction. std::string ToString() const override { return "Prim: " + prim_->name(); } + /// Override the ToString function to provide a string representation of this AbstractFunction with verbosity. + /// \param[in] verbose: A flag indicating whether to include verbose information. + /// \return A string describing this AbstractFunction with optional verbosity. std::string ToString(bool verbose) const override; + /// Override the RealBuildValue function to return the associated primitive as a ValuePtr. + /// \return The primitive associated with this AbstractFunction as a ValuePtr. ValuePtr RealBuildValue() const override { return prim_; } private: diff --git a/mindspore/core/abstract/analysis_context.cc b/mindspore/core/abstract/analysis_context.cc index 6d56d843d21..84f0fa4e0d0 100644 --- a/mindspore/core/abstract/analysis_context.cc +++ b/mindspore/core/abstract/analysis_context.cc @@ -24,7 +24,13 @@ namespace mindspore { namespace abstract { +/// \brief A static list that stores all AnalysisContext instances. std::list AnalysisContext::all_context_; + +/// \brief Creates a new AnalysisContext for a given FuncGraph and argument specifications. +/// \param func_graph The FuncGraph for which the AnalysisContext is created. +/// \param args_spec_list The list of AbstractBasePtr representing argument specifications. +/// \return A shared pointer to the newly created AnalysisContext. AnalysisContextPtr AnalysisContext::NewContext(const FuncGraphPtr &func_graph, const AbstractBasePtrList &args_spec_list) { // Find func graph's parent and its parent context firstly. @@ -32,10 +38,14 @@ AnalysisContextPtr AnalysisContext::NewContext(const FuncGraphPtr &func_graph, FuncGraphPtr parent_graph = func_graph->parent(); AnalysisContextPtr parent_context = nullptr; auto iter = extant_context_cache_.find(parent_graph); + + // If the parent context exists in the cache, get a shared pointer to it. if (iter != extant_context_cache_.end()) { parent_context = iter->second.lock(); } - if (parent_context == nullptr) { // If parent context is not found, we'll raise exception. + + // If the parent context is not found, raise an exception with detailed information. + if (parent_context == nullptr) { std::ostringstream oss; oss << "BUG: Failed to find parent context in current context: " << this->ToString() << ", func_graph: " << func_graph->ToString() << ", parent_graph: "; @@ -52,6 +62,8 @@ AnalysisContextPtr AnalysisContext::NewContext(const FuncGraphPtr &func_graph, if (children_context_map_iter != parent_context->children_cache_.end()) { auto children_context_map = children_context_map_iter->second; auto children_context_iter = children_context_map.find(args_spec_list); + + // If a context with the same arguments exists in the cache, return a shared pointer to it. if (children_context_iter != children_context_map.end()) { return children_context_iter->second.lock(); } @@ -59,25 +71,36 @@ AnalysisContextPtr AnalysisContext::NewContext(const FuncGraphPtr &func_graph, // Create a new context for the func graph and its specific arguments. AnalysisContextPtr new_context = CreateContext(parent_context, func_graph, args_spec_list); + // To avoid cycle-reference, use weak_ptr here. auto weak_new_context = std::weak_ptr(new_context); new_context->extant_context_cache_[func_graph] = weak_new_context; parent_context->children_cache_[func_graph][args_spec_list] = weak_new_context; + return new_context; } +/// \brief Finds the AnalysisContext for a given FuncGraph or its parent FuncGraph. +/// \param func_graph The FuncGraph for which the AnalysisContext is searched. +/// \return A shared pointer to the found AnalysisContext. AnalysisContextPtr AnalysisContext::FindOwnOrParentContext(const FuncGraphPtr &func_graph) { auto p_iter = extant_context_cache_.find(func_graph); AnalysisContextPtr extant_context = nullptr; + + // If the context for the given FuncGraph is found in the cache, get a shared pointer to it. if (p_iter != extant_context_cache_.end()) { extant_context = p_iter->second.lock(); } else { + // If not found, try to find the context for its parent FuncGraph. auto iter_parent = extant_context_cache_.find(func_graph->parent()); + + // If found, get a shared pointer to the parent context. if (iter_parent != extant_context_cache_.end()) { extant_context = iter_parent->second.lock(); } } - // If this happen, it would be a bug in code. But we raise exception to keep the scene. + + // If the context is still not found, raise an exception with detailed information. if (extant_context == nullptr) { std::ostringstream oss; oss << "BUG: Failed to find context for: " << func_graph->ToString() << ", parent_graph: "; @@ -93,42 +116,55 @@ AnalysisContextPtr AnalysisContext::FindOwnOrParentContext(const FuncGraphPtr &f } else { oss << " [graph: " << iter.first->ToString(); } - // iter.second cannot be nullptr even iter.first is nullptr as it will + // iter.second cannot be nullptr even if iter.first is nullptr, as it will // always be a Context() object. oss << ", context: " << iter.second.lock()->ToString() << "]"; } oss << "}"; MS_LOG(EXCEPTION) << oss.str() << " NodeInfo: " << trace::GetDebugInfo(func_graph->debug_info()); } + return extant_context; } +/// \brief Creates a dummy AnalysisContext that represents no specific function or arguments. +/// \return A shared pointer to the created dummy AnalysisContext. AnalysisContextPtr AnalysisContext::DummyContext() { AnalysisContextPtr dummy_context = CreateContext(nullptr, nullptr, AbstractBasePtrList()); dummy_context->extant_context_cache_[nullptr] = std::weak_ptr(dummy_context); return dummy_context; } +/// \brief Checks if the AnalysisContext is a dummy context with no specific function or arguments. +/// \return True if it's a dummy context, false otherwise. bool AnalysisContext::IsDummyContext() { return parent_ == nullptr && func_graph_ == nullptr && args_spec_list_.empty(); } +/// \brief An instance of AnalysisContext that represents a dummy context. const AnalysisContextPtr kDummyAnalysisContext = AnalysisContext::CreateContext(nullptr, nullptr, AbstractBasePtrList()); +/// \brief Checks if two AnalysisContext instances are equal. +/// \param other The other AnalysisContext instance to compare with. +/// \return True if they are equal, false otherwise. bool AnalysisContext::operator==(const AnalysisContext &other) const { + // Check if func_graph_ is equal. if (func_graph_ != other.func_graph_) { return false; } + // Check if args_spec_list_ size is equal. if (args_spec_list_.size() != other.args_spec_list_.size()) { return false; } + // Check if parent_ is either both nullptr or both not nullptr. if (((parent_ == nullptr) && (other.parent_ != nullptr)) || ((parent_ != nullptr) && (other.parent_ == nullptr))) { return false; } - // Compare parent with content. + + // Compare parent_ with content. bool is_parent_equal = false; if (parent_ == other.parent_) { is_parent_equal = true; @@ -137,33 +173,43 @@ bool AnalysisContext::operator==(const AnalysisContext &other) const { } else { return false; } + + // Compare each element in args_spec_list_. for (std::size_t i = 0; i < args_spec_list_.size(); i++) { if (func_graph_->has_flag(GRAPH_FLAG_IS_WHILE_HEADER) && args_spec_list_[i]->isa() && other.args_spec_list_[i]->isa()) { + // If both are FuncGraphAbstractClosure, make a copy and compare without tracking IDs. auto temp_this = args_spec_list_[i]->cast()->Copy(); auto temp_other = other.args_spec_list_[i]->cast()->Copy(); temp_this->set_tracking_id(nullptr); temp_other->set_tracking_id(nullptr); + + // If the copies are not equal, return false. if (!(*temp_this == *temp_other)) { return false; } } else if (!(*args_spec_list_[i] == *other.args_spec_list_[i])) { + // If not both FuncGraphAbstractClosure, compare directly. return false; } } + return is_parent_equal; } - -// brief The key which controls the graph cloning in Specialize. -// Originally, specialize use context directly as the key for cloning graph. The graph will be cloned multiple times -// for different context, which means the graph is called from different node with different arguments and different -// free values. In order to decrease the number of cloned graphs, we add this `SpecializeKey` method to control what -// graph can be reused. -// The graph called with different shape should not be reused, because the combination of `shape` and `Fill` relies -// on correct shape to specialize a tensor constant. +/// \brief Generates a key for controlling graph cloning during specialization. +/// Originally, specialization used the context directly as the key for cloning graphs. This led to multiple clones of +/// the same graph for different contexts, where the graph was called from different nodes with varying arguments and +/// free values. To reduce the number of cloned graphs, this method, `SpecializeKey`, is introduced to determine which +/// graphs can be reused. +/// Graphs called with different shapes should not be reused because the specialization of a tensor constant depends on +/// the correct shape. +/// \return A new AnalysisContextPtr representing the specialized key. AnalysisContextPtr AnalysisContext::SpecializeKey() const { + // Create a list for broadened arguments. AbstractBasePtrList args_broad_shp; + + // Iterate through the args_spec_list_ and add the broadened version of each argument to args_broad_shp. (void)std::transform(args_spec_list_.begin(), args_spec_list_.end(), std::back_inserter(args_broad_shp), [](const AbstractBasePtr &arg) -> AbstractBasePtr { MS_EXCEPTION_IF_NULL(arg); @@ -173,23 +219,34 @@ AnalysisContextPtr AnalysisContext::SpecializeKey() const { } return arg; }); + + // Create a new AnalysisContext using the broadened arguments and the same function graph. AnalysisContextPtr context_new = CreateContext(nullptr, func_graph_, args_broad_shp); context_new->parent_ = parent_; + return context_new; } +/// \brief Computes a hash value for the AnalysisContext instance. +/// The hash value is used for hashing and comparison purposes. +/// \return The computed hash value. std::size_t AnalysisContext::hash() { std::size_t hash_value = 0; - // hash() recursion exit condition. + + // Recursion exit condition for hash(). if (parent_ != nullptr) { hash_value = hash_combine(hash_value, parent_->hash()); } if (func_graph_ != nullptr) { hash_value = hash_combine(hash_value, func_graph_->hash()); } + return hash_value; } +/// \brief Converts the AnalysisContext instance to a string representation. +/// This method is primarily used for debugging and logging purposes. +/// \return A string representing the AnalysisContext. std::string AnalysisContext::ToString() const { std::ostringstream buffer; buffer << "{"; @@ -209,6 +266,7 @@ std::string AnalysisContext::ToString() const { return buffer.str(); } +/// \brief Clears all contexts stored in the `all_context_` list. void AnalysisContext::ClearContext() { for (auto &item : all_context_) { item->parent_ = nullptr; @@ -220,6 +278,11 @@ void AnalysisContext::ClearContext() { all_context_.clear(); } +/// \brief Creates a new AnalysisContext instance. +/// \param parent The parent context. +/// \param fg The FuncGraph associated with the context. +/// \param args_spec_list The list of AbstractBasePtr representing argument specifications. +/// \return A shared pointer to the newly created AnalysisContext. AnalysisContextPtr AnalysisContext::CreateContext(const AnalysisContextPtr &parent, const FuncGraphPtr &fg, const AbstractBasePtrList &args_spec_list) { auto context = std::make_shared(parent, fg, args_spec_list); diff --git a/mindspore/core/abstract/analysis_context.h b/mindspore/core/abstract/analysis_context.h index 01a30bf707f..11908263060 100644 --- a/mindspore/core/abstract/analysis_context.h +++ b/mindspore/core/abstract/analysis_context.h @@ -47,38 +47,86 @@ class MS_CORE_API AnalysisContext { } ~AnalysisContext() = default; - // Extend this context with values for another graph. + /// Create a new AnalysisContext for a given function graph and its associated argument specifications. + /// \param[in] func_graph: The FuncGraphPtr representing the function graph for which to create the context. + /// \param[in] args_spec_list: The AbstractBasePtrList containing argument specifications. + /// \return A new AnalysisContextPtr representing the context for the given function graph and arguments. AnalysisContextPtr NewContext(const FuncGraphPtr &func_graph, const AbstractBasePtrList &args_spec_list); - // Return a context restricted to a graph and its parent. + /// Find the AnalysisContext for a given function graph, or its parent if not found. + /// \param[in] graph: The FuncGraphPtr for which to find the context. + /// \return The AnalysisContextPtr for the specified function graph or its parent. AnalysisContextPtr FindOwnOrParentContext(const FuncGraphPtr &graph); + + /// Override the equality operator to compare two AnalysisContext instances. + /// \param[in] other: Another AnalysisContext to compare with. + /// \return True if the two AnalysisContext instances are equal, false otherwise. bool operator==(const AnalysisContext &other) const; + + /// Calculate a hash value for the AnalysisContext instance. + /// \return The hash value for the AnalysisContext. std::size_t hash(); + + /// Create a dummy AnalysisContextPtr, typically used as a placeholder. + /// \return A dummy AnalysisContextPtr. static AnalysisContextPtr DummyContext(); + + /// Check if the current AnalysisContext is a dummy context. + /// \return True if the current context is a dummy context, false otherwise. bool IsDummyContext(); + + /// Get the function graph associated with this AnalysisContext. + /// \return The FuncGraphPtr associated with this context. FuncGraphPtr func_graph() const { return func_graph_; } + + /// Get the parent context of this AnalysisContext. + /// \return The parent AnalysisContextPtr of this context. AnalysisContextPtr parent() const { return parent_; } + + /// Convert the AnalysisContext to a string representation. + /// \return A string representation of the AnalysisContext. std::string ToString() const; + + /// Specialize the current context key. + /// \return A specialized AnalysisContextPtr based on the current context key. AnalysisContextPtr SpecializeKey() const; + + /// Get the list of argument specifications associated with this context. + /// \return The AbstractBasePtrList containing argument specifications. AbstractBasePtrList args_spec_list() { return args_spec_list_; } + + /// Clear the current context, typically used for resetting context information. static void ClearContext(); + + /// Create a new AnalysisContext with the given parent, function graph, and argument specifications. + /// \param[in] parent: The parent AnalysisContextPtr. + /// \param[in] fg: The FuncGraphPtr representing the function graph. + /// \param[in] args_spec_list: The AbstractBasePtrList containing argument specifications. + /// \return A new AnalysisContextPtr created with the specified parameters. static AnalysisContextPtr CreateContext(const AnalysisContextPtr &parent, const FuncGraphPtr &fg, const AbstractBasePtrList &args_spec_list); private: + // Pointer to the parent AnalysisContext. AnalysisContextPtr parent_; + + // Pointer to the associated function graph. FuncGraphPtr func_graph_; + + // List of argument specifications associated with this context. AbstractBasePtrList args_spec_list_; - // Record all created context for each func graph. - // `extant_context_cache_` is copied from its parent context. + + // A HashMap that records all created context instances for each function graph. + // The extant_context_cache_ is copied from its parent context. mindspore::HashMap extant_context_cache_; - // Record all created child contexts from this context. - // Like: key: [func_graph & arguments], value: [child_context] + + // A HashMap that records all created child contexts from this context. + // The key is a combination of [function graph & arguments], and the value is the child context. mindspore::HashMap children_cache_; - // There may may be shared_ptr loop like: - // FuncGraphAbstactClosur->AnalysisContext->children_cache_->ArgsSpec->FuncGraphAbstactClosur. - // For break the loop, using all_context_ to clear context_. + // There may be shared_ptr loops in the form of: + // FuncGraphAbstactClosure -> AnalysisContext -> children_cache_ -> ArgsSpec -> FuncGraphAbstactClosure. + // To break the loop, use all_context_ to clear context_. static std::list all_context_; }; diff --git a/mindspore/core/abstract/dshape.cc b/mindspore/core/abstract/dshape.cc index 79df160c18e..eb711a14ddc 100644 --- a/mindspore/core/abstract/dshape.cc +++ b/mindspore/core/abstract/dshape.cc @@ -25,6 +25,8 @@ std::string ShapeVectorToStr(const std::vector &shp) { std::ostringstream buffer; bool f_begin = true; buffer << "("; + + // Iterate through the elements of the shape vector. for (auto &x : shp) { if (!f_begin) { buffer << ", "; @@ -50,9 +52,15 @@ std::ostream &operator<<(std::ostream &os, const std::shared_ptr bs) return os; } -bool BaseShape::operator==(const BaseShape &other) const { return tid() == other.tid(); } +bool BaseShape::operator==(const BaseShape &other) const { + // Check if the type identifier of the shapes matches. + return tid() == other.tid(); +} -bool BaseShape::operator!=(const BaseShape &other) const { return !(*this == other); } +bool BaseShape::operator!=(const BaseShape &other) const { + // Check if the type identifier of the shapes does not match. + return !(*this == other); +} std::string Shape::ToString() const { std::ostringstream buffer; @@ -74,6 +82,8 @@ std::string Shape::ToString() const { std::string Shape::DumpText() const { std::ostringstream buffer; buffer << "["; + + // Iterate through the shape elements and add them to the string representation. for (size_t i = 0; i < shape_.size(); i++) { buffer << (i > 0 ? ", " : "") << shape_[i]; if (shape_[i] == SHP_ANY && min_shape_.size() == shape_.size() && max_shape_.size() == shape_.size()) { @@ -99,7 +109,9 @@ bool Shape::operator==(const BaseShape &other) const { } const int64_t Shape::SHP_ANY; + void Shape::Broaden() { + // Set all elements of the shape to SHP_ANY. for (size_t i = 0; i < shape_.size(); i++) { shape_[i] = SHP_ANY; } @@ -108,6 +120,8 @@ void Shape::Broaden() { std::string SequenceShape::ToString() const { std::ostringstream buffer; bool f_begin = true; + + // Iterate through the elements of p_shapes_ and add them to the string representation. for (const auto &p_shp : p_shapes_) { if (!f_begin) { buffer << ", "; @@ -122,6 +136,8 @@ std::string SequenceShape::ToString() const { BaseShapePtrList SequenceShape::ElementsClone() const { BaseShapePtrList ele_list; + + // Clone each element in p_shapes_ and add them to ele_list. for (auto p_shp : p_shapes_) { MS_EXCEPTION_IF_NULL(p_shp); ele_list.push_back(p_shp->Clone()); @@ -129,6 +145,7 @@ BaseShapePtrList SequenceShape::ElementsClone() const { return ele_list; } +// Explicit template instantiations for SequenceEqual. template bool SequenceShape::SequenceEqual(const BaseShape &) const; template bool SequenceShape::SequenceEqual(const BaseShape &) const; } // namespace abstract diff --git a/mindspore/core/abstract/param_validator.cc b/mindspore/core/abstract/param_validator.cc index 6c4f31998a4..36d075d52b2 100644 --- a/mindspore/core/abstract/param_validator.cc +++ b/mindspore/core/abstract/param_validator.cc @@ -26,6 +26,7 @@ namespace mindspore { namespace abstract { +// Define and initialize the ReportNameTraits for various Abstract types. #define ABSTRACT_REPORT_NAME_DEC(abstract) constexpr char ReportNameTraits::name[]; ABSTRACT_REPORT_NAME_DEC(Tensor) @@ -39,6 +40,7 @@ ABSTRACT_REPORT_NAME_DEC(Type) ABSTRACT_REPORT_NAME_DEC(KeywordArg) ABSTRACT_REPORT_NAME_DEC(Class) +// Check if the type of 'type' matches one of the 'accepts' types. TypePtr CheckType(TypePtr type, const TypePtrList &accepts, const std::string &error_message_prefix) { auto ori_type = type; if (type->isa()) { @@ -46,15 +48,18 @@ TypePtr CheckType(TypePtr type, const TypePtrList &accepts, const std::string &e type = tensor->element(); MS_EXCEPTION_IF_NULL(type); } + + // Check if 'type' is compatible with any of the 'accepts' types. bool ok = std::any_of(accepts.begin(), accepts.end(), [type](const TypePtr &accept) -> bool { return IsIdentidityOrSubclass(type, accept); }); if (ok) { return type; } else { - MS_EXCEPTION(TypeError) << error_message_prefix << " should be " << accepts << ",but got " << ori_type->ToString(); + MS_EXCEPTION(TypeError) << error_message_prefix << " should be " << accepts << ", but got " << ori_type->ToString(); } } +// Check if the dtype of 'tensor' matches one of the 'accepts' types. TypePtr CheckTensorDType(const AbstractTensorPtr &tensor, const TypePtrList &accepts, const std::string &error_message_prefix) { MS_EXCEPTION_IF_NULL(tensor); @@ -66,6 +71,7 @@ TypePtr CheckTensorDType(const AbstractTensorPtr &tensor, const TypePtrList &acc return CheckType(type, accepts, error_message_prefix); } +// Check if the dtypes of all tensors in 'tensor_list' match one of the 'accepts' types. TypePtr CheckTensorsDTypeSame(const AbstractTensorPtrList &tensor_list, const TypePtrList &accepts, const std::string &error_message_prefix) { if (tensor_list.empty()) { @@ -81,7 +87,8 @@ TypePtr CheckTensorsDTypeSame(const AbstractTensorPtrList &tensor_list, const Ty std::ostringstream loginfoBuffer; loginfoBuffer << "[" << sample_tensor->BuildType()->ToString(); bool error_flag = false; - // Check if other elements have the same type with the first element. + + // Check if the dtypes of all tensors in 'tensor_list' match the dtype of the first tensor. for (size_t index = 1; index < tensor_list.size(); ++index) { MS_EXCEPTION_IF_NULL(tensor_list[index]); auto elem = tensor_list[index]->element(); @@ -94,12 +101,13 @@ TypePtr CheckTensorsDTypeSame(const AbstractTensorPtrList &tensor_list, const Ty } } if (error_flag) { - MS_EXCEPTION(ValueError) << error_message_prefix << " must be same, but got " << loginfoBuffer.str() << "]"; + MS_EXCEPTION(ValueError) << error_message_prefix << " must be the same, but got " << loginfoBuffer.str() << "]"; } MS_LOG(DEBUG) << error_message_prefix << loginfoBuffer.str(); return CheckTensorDType(sample_tensor, accepts, error_message_prefix); } +// Check if the scalar's type matches one of the 'accepts' types. TypePtr CheckScalarType(const AbstractScalarPtr &scalar, const TypePtrList &accepts, const std::string &error_message_prefix) { if (scalar == nullptr) { @@ -113,6 +121,7 @@ TypePtr CheckScalarType(const AbstractScalarPtr &scalar, const TypePtrList &acce return CheckType(type, accepts, error_message_prefix); } +// Check if the shapes of two tensors are the same. void CheckShapeSame(const std::string &op, const AbstractTensorPtr &tensor_base, const AbstractTensorPtr &tensor) { MS_EXCEPTION_IF_NULL(tensor_base); ShapePtr shape_base = tensor_base->shape(); @@ -128,7 +137,7 @@ void CheckShapeSame(const std::string &op, const AbstractTensorPtr &tensor_base, auto shape_base_vector = shape_base->shape(); if (shape_vector.size() != shape_base_vector.size()) { MS_LOG(EXCEPTION) << op << " evaluator first arg shape " << shape->ToString() - << " are not consistent with second arg shape " << shape_base->ToString(); + << " is not consistent with second arg shape " << shape_base->ToString(); } for (size_t i = 0; i < shape_vector.size(); i++) { @@ -137,12 +146,12 @@ void CheckShapeSame(const std::string &op, const AbstractTensorPtr &tensor_base, } if (shape_vector[i] != shape_base_vector[i]) { MS_LOG(EXCEPTION) << op << " evaluator first arg shape " << shape->ToString() - << " are not consistent with second arg shape " << shape_base->ToString(); + << " is not consistent with second arg shape " << shape_base->ToString(); } } - return; } +// Check if the dtype of two tensors is the same. TypePtr CheckDtypeSame(const std::string &op, const AbstractTensorPtr &tensor_base, const AbstractTensorPtr &tensor) { MS_EXCEPTION_IF_NULL(tensor_base); auto base_elem = tensor_base->element(); @@ -156,11 +165,12 @@ TypePtr CheckDtypeSame(const std::string &op, const AbstractTensorPtr &tensor_ba MS_EXCEPTION_IF_NULL(type); if (*type != *type_base) { MS_LOG(EXCEPTION) << op << " evaluator first arg dtype " << type_base->ToString() - << " are not consistent with second arg dtype " << type->ToString(); + << " is not consistent with second arg dtype " << type->ToString(); } return type_base; } +// Check if 'axis' is within the valid range. int64_t CheckAxis(const std::string &op, const std::string &args_name, const ValuePtr &axis, int64_t minimum, int64_t max, const std::string &rank_name) { if (axis == nullptr) { @@ -180,6 +190,8 @@ int64_t CheckAxis(const std::string &op, const std::string &args_name, const Val } return axis_value; } + +// Check if the number of input arguments matches 'size_expect'. void CheckArgsSize(const std::string &op, const mindspore::abstract::AbstractBasePtrList &args_spec_list, size_t size_expect) { if (args_spec_list.size() != size_expect) { @@ -192,23 +204,26 @@ void CheckArgsSize(const std::string &op, const mindspore::abstract::AbstractBas } } +// Check if all elements in 'shape' are positive integers. void CheckShapeAllPositive(const std::string &op, const ShapeVector &shape) { for (size_t i = 0; i < shape.size(); ++i) { if (shape[i] < 0) { - MS_LOG(EXCEPTION) << op << " shape element [" << i << "] must be positive integer, but got " << shape[i]; + MS_LOG(EXCEPTION) << op << " shape element [" << i << "] must be a positive integer, but got " << shape[i]; } } } +// Check if all elements in 'shape' are either positive integers or SHP_ANY. void CheckShapeAnyAndPositive(const std::string &op, const ShapeVector &shape) { for (size_t i = 0; i < shape.size(); ++i) { if ((shape[i] < 0) && (shape[i] != Shape::SHP_ANY)) { - MS_EXCEPTION(ValueError) << op << " shape element [" << i << "] must be positive integer or SHP_ANY, but got " + MS_EXCEPTION(ValueError) << op << " shape element [" << i << "] must be a positive integer or SHP_ANY, but got " << shape[i]; } } } +// Check if the number of input arguments is at least 'size_expect'. void CheckRequiredArgsSize(const std::string &op, const mindspore::abstract::AbstractBasePtrList &args_spec_list, size_t size_expect) { if (args_spec_list.size() < size_expect) { diff --git a/mindspore/core/abstract/param_validator.h b/mindspore/core/abstract/param_validator.h index c088cdc08b8..62a47114c16 100644 --- a/mindspore/core/abstract/param_validator.h +++ b/mindspore/core/abstract/param_validator.h @@ -30,37 +30,99 @@ namespace mindspore { namespace abstract { -// check if variable's type is an instance of any of accepts or of a subclass of it. +/// \brief Checks if the given type is an instance of any of the accepted types or a subclass of them. +/// \param[in] type: The TypePtr to check. +/// \param[in] accepts: A list of accepted types. +/// \param[in] error_message_prefix: A prefix to use in error messages if the check fails. +/// \return The input type if it is valid; otherwise, raises an error. TypePtr CheckType(TypePtr type, const TypePtrList &accepts, const std::string &error_message_prefix); +/// \brief Checks the data type of a tensor against a list of accepted types. +/// \param[in] tensor: The AbstractTensorPtr to check. +/// \param[in] accepts: A list of accepted data types. +/// \param[in] error_message_prefix: A prefix to use in error messages if the check fails. +/// \return The data type of the input tensor if it is valid; otherwise, raises an error. TypePtr CheckTensorDType(const AbstractTensorPtr &tensor, const TypePtrList &accepts, const std::string &error_message_prefix); +/// \brief Checks that the data types of a list of tensors are the same and within the accepted types. +/// \param[in] tensor_list: A list of AbstractTensorPtr to check. +/// \param[in] accepts: A list of accepted data types. +/// \param[in] error_message_prefix: A prefix to use in error messages if the check fails. +/// \return The data type of the input tensors if they are valid; otherwise, raises an error. TypePtr CheckTensorsDTypeSame(const AbstractTensorPtrList &tensor_list, const TypePtrList &accepts, const std::string &error_message_prefix); +/// \brief Checks the data type of a scalar against a list of accepted types. +/// \param[in] scalar: The AbstractScalarPtr to check. +/// \param[in] accepts: A list of accepted data types. +/// \param[in] error_message_prefix: A prefix to use in error messages if the check fails. +/// \return The data type of the input scalar if it is valid; otherwise, raises an error. TypePtr CheckScalarType(const AbstractScalarPtr &scalar, const TypePtrList &accepts, const std::string &error_message_prefix); +/// \brief Checks that the shapes of two tensors are the same. +/// \param[in] op: The name of the operation. +/// \param[in] tensor_base: The first AbstractTensorPtr to compare. +/// \param[in] tensor: The second AbstractTensorPtr to compare. void CheckShapeSame(const std::string &op, const AbstractTensorPtr &tensor_base, const AbstractTensorPtr &tensor); +/// \brief Checks that the data types of two tensors are the same. +/// \param[in] op: The name of the operation. +/// \param[in] tensor_base: The first AbstractTensorPtr to compare. +/// \param[in] tensor: The second AbstractTensorPtr to compare. +/// \return The data type of the input tensors if they are valid; otherwise, raises an error. TypePtr CheckDtypeSame(const std::string &op, const AbstractTensorPtr &tensor_base, const AbstractTensorPtr &tensor); +/// \brief Checks the axis value within a specified range. +/// \param[in] op: The name of the operation. +/// \param[in] arg_name: The name of the argument. +/// \param[in] axis: The ValuePtr representing the axis to check. +/// \param[in] min: The minimum valid axis value. +/// \param[in] max: The maximum valid axis value. +/// \param[in] rank_name: The name of the rank argument for error messages. +/// \return The valid axis value. MS_CORE_API int64_t CheckAxis(const std::string &op, const std::string &arg_name, const ValuePtr &axis, int64_t min, int64_t max, const std::string &rank_name); -MS_CORE_API void CheckArgsSize(const std::string &op, const AbstractBasePtrList &args_spec_list, size_t size_expect); +/// \brief Checks the size of a list of arguments. +/// \param[in] op: The name of the operation. +/// \param[in] args_spec_list: The list of AbstractBasePtr to check. +/// \param[in] size_expect: The expected size of the list. +void CheckArgsSize(const std::string &op, const AbstractBasePtrList &args_spec_list, size_t size_expect); +/// \brief Checks that all values in the given shape are positive. +/// \param[in] op: The name of the operation. +/// \param[in] shape: The shape to check. void CheckShapeAllPositive(const std::string &op, const ShapeVector &shape); +/// \brief Checks that at least one value in the given shape is positive. +/// \param[in] op: The name of the operation. +/// \param[in] shape: The shape to check. void CheckShapeAnyAndPositive(const std::string &op, const ShapeVector &shape); +/// \brief Checks if the attribute is an integer or a tuple of integers. +/// \param[in] op: The name of the operation. +/// \param[in] attr: The ValuePtr representing the attribute to check. +/// \param[in] start_idx: The starting index of the attribute elements in case it's a tuple. +/// \param[in] num_element: The number of elements to check. +/// \return A vector of integers extracted from the attribute. std::vector CheckAttrIntOrTuple(const std::string &op, const ValuePtr &attr, const size_t start_idx, const size_t num_element); +/// \brief Checks if the attribute is a string within a set of valid values. +/// \param[in] op: The name of the operation. +/// \param[in] attr: The ValuePtr representing the attribute to check. +/// \param[in] attr_name: The name of the attribute for error messages. +/// \param[in] val_set: A set of valid string values. +/// \return The valid string attribute value. std::string CheckAttrStringSet(const std::string &op, const ValuePtr &attr, const std::string &attr_name, const std::set &val_set); +/// \brief Checks the size of a list of required arguments. +/// \param[in] op: The name of the operation. +/// \param[in] args_spec_list: The list of AbstractBasePtr to check. +/// \param[in] size_expect: The expected size of the list. void CheckRequiredArgsSize(const std::string &op, const AbstractBasePtrList &args_spec_list, size_t size_expect); template diff --git a/mindspore/core/abstract/primitive_infer_map.cc b/mindspore/core/abstract/primitive_infer_map.cc index ab2a4243129..f893ea96870 100644 --- a/mindspore/core/abstract/primitive_infer_map.cc +++ b/mindspore/core/abstract/primitive_infer_map.cc @@ -45,9 +45,16 @@ namespace mindspore { namespace abstract { +// Function that returns a set of integers representing dependencies based on a primitive's name and input number. +// Parameters: +// - prim_name: A string representing the name of the primitive. +// - input_num: The number of inputs to the primitive. +// Returns: +// - A set of integers representing the dependencies. std::set GetDependsFormMap(const std::string &prim_name, size_t input_num) { using ShapeSet = std::set; using PrimShapeDependMap = mindspore::HashMap; + // Static mapping of primitive names to sets of integers representing dependencies. static const auto &kOneHot = prim::kPrimOneHot->name(); static const auto &kDropoutGenMask = prim::kPrimDropoutGenMask->name(); static const auto &kTranspose = prim::kPrimTranspose->name(); @@ -71,6 +78,7 @@ std::set GetDependsFormMap(const std::string &prim_name, size_t input_n static const auto &kReshape = prim::kPrimReshape->name(); static const auto &kFillV2 = prim::kPrimFillV2->name(); // Common dynamic shape depends. + // Define a map of dependencies for specific primitives. static const PrimShapeDependMap dynamic_shape_depends{{kUnsortedSegmentSum, ShapeSet{2}}, {kUnsortedSegmentMin, ShapeSet{2}}, {kUnsortedSegmentMax, ShapeSet{2}}, @@ -97,10 +105,11 @@ std::set GetDependsFormMap(const std::string &prim_name, size_t input_n MS_EXCEPTION_IF_NULL(ms_context); auto device = ms_context->get_param(MS_CTX_DEVICE_TARGET); // Special dynamic shape depends for Ascend. + // Special case for dynamic shape depends on Ascend device for the 'Transpose' primitive. if (device == kAscendDevice && prim_name == kTranspose) { return {1}; } - + // Look up the primitive name in the map and filter dependencies based on input number. auto iter = dynamic_shape_depends.find(prim_name); if (iter != dynamic_shape_depends.end()) { ShapeSet res; @@ -111,7 +120,11 @@ std::set GetDependsFormMap(const std::string &prim_name, size_t input_n } return {}; } - +// Function that returns a set of integers representing dependencies based on a CNode. +// Parameters: +// - cnode: A CNodePtr representing the computation node. +// Returns: +// - A set of integers representing the dependencies. std::set GetDependsFormMap(const CNodePtr &cnode) { MS_EXCEPTION_IF_NULL(cnode); if (cnode->inputs().empty()) { @@ -122,9 +135,11 @@ std::set GetDependsFormMap(const CNodePtr &cnode) { auto prim_name = primitive->ToString(); return GetDependsFormMap(prim_name, cnode->inputs().size() - 1); } - +// Function that provides a mapping between primitives and their shape and value inference implementations. +// - A map where primitive names (keys) are mapped to their corresponding inference implementations (values). PrimitiveEvalImplMap &GetPrimitiveToEvalImplMap() { using R = PrimitiveEvalImplMap::mapped_type; + // Static mapping between primitive names and their inference implementations. static PrimitiveEvalImplMap prim_eval_implement_map{ // Statements {prim::kPrimReturn, R{InferImplReturn, nullptr, true}}, @@ -259,9 +274,12 @@ PrimitiveEvalImplMap &GetPrimitiveToEvalImplMap() { }; return prim_eval_implement_map; } - +// Function that provides a mapping between primitives and their backend shape and value inference implementations. +// Returns: +// - A map where primitive names (keys) are mapped to their corresponding backend inference implementations (values). PrimitiveEvalImplMap &GetPrimitiveToBackendEvalImplMap() { using R = PrimitiveEvalImplMap::mapped_type; + // Static mapping between primitive names and their backend inference implementations. static PrimitiveEvalImplMap prim_backend_eval_implement_map = { {prim::kPrimMul, R{ops::MulInfer, nullptr, true}}, {prim::kPrimMod, R{ops::ModInfer, nullptr, true}}, @@ -314,7 +332,11 @@ PrimitiveEvalImplMap &GetPrimitiveToBackendEvalImplMap() { }; return prim_backend_eval_implement_map; } - +// Function that retrieves the shape and value inference implementations for a given primitive. +// Parameters: +// - primitive: A PrimitivePtr representing the primitive for which to retrieve the implementations. +// Returns: +// - A StandardPrimitiveImplReg struct containing the inference implementations and a flag indicating if it's in the white list. StandardPrimitiveImplReg GetPrimitiveInferImpl(const PrimitivePtr &primitive) { MS_EXCEPTION_IF_NULL(primitive); auto iter = GetPrimitiveToEvalImplMap().find(primitive); @@ -323,7 +345,10 @@ StandardPrimitiveImplReg GetPrimitiveInferImpl(const PrimitivePtr &primitive) { } return iter->second; } - +// Function to register shape and value inference implementations for a primitive. +// Parameters: +// - primitive: A PrimitivePtr representing the primitive for which to register the implementations. +// - impl_reg: A StandardPrimitiveImplReg struct containing the inference implementations and a flag indicating if it's in the white list. void RegisterStandardPrimitiveImpl(const PrimitivePtr &primitive, const StandardPrimitiveImplReg &impl_reg) { auto &prim_eval_map = GetPrimitiveToEvalImplMap(); prim_eval_map[primitive] = impl_reg; diff --git a/mindspore/core/abstract/primitive_infer_map.h b/mindspore/core/abstract/primitive_infer_map.h index 99948ba7c92..8b38e5db0f9 100644 --- a/mindspore/core/abstract/primitive_infer_map.h +++ b/mindspore/core/abstract/primitive_infer_map.h @@ -31,33 +31,52 @@ namespace mindspore { namespace abstract { + +// Define function pointer types for shape and value inference for primitives. using InferShapeImpl = AbstractBasePtr (*)(const abstract::AnalysisEnginePtr &, const PrimitivePtr &, const AbstractBasePtrList &); using InferValueImpl = ValuePtr (*)(const PrimitivePtr &, const AbstractBasePtrList &); +// Structure to register shape and value inference implementations for primitives. struct StandardPrimitiveImplReg { - InferShapeImpl infer_shape_impl_; // infer shape and type for ops - InferValueImpl infer_value_impl_; // infer value for ops - // in_white_list_ is true means this primitive can be executed by vm backend - // else will be optimized by frontend - bool in_white_list_; + InferShapeImpl infer_shape_impl_; // Function pointer for shape inference. + InferValueImpl infer_value_impl_; // Function pointer for value inference. + bool in_white_list_; // Indicates if the primitive is in the white list for execution by the VM backend. }; +// Define a mapping between primitives and their shape and value inference implementations. using PrimitiveEvalImplMap = mindspore::HashMap; +/// \brief Provides a mapping between primitives and their shape and value inference implementations. +/// \return A map where primitive names (keys) are mapped to their corresponding inference implementations (values). MS_CORE_API PrimitiveEvalImplMap &GetPrimitiveToEvalImplMap(); +/// \brief Provides a mapping between primitives and their backend shape and value inference implementations. +/// \return A map where primitive names (keys) are mapped to their corresponding backend inference implementations (values). MS_CORE_API PrimitiveEvalImplMap &GetPrimitiveToBackendEvalImplMap(); + +/// \brief Retrieves the shape and value inference implementations for a given primitive. +/// \param[in] primitive: A PrimitivePtr representing the primitive for which to retrieve the implementations. +/// \return A StandardPrimitiveImplReg struct containing the inference implementations and a flag indicating if it's in the white list. MS_CORE_API StandardPrimitiveImplReg GetPrimitiveInferImpl(const PrimitivePtr &primitive); +/// \brief get dependencies from a map for a given primitive name and input number. +/// \return A map where primitive names (keys) are mapped to their corresponding inference implementations (values). MS_CORE_API std::set GetDependsFormMap(const std::string &prim_name, size_t input_num); +/// \brief Get dependencies based on a CNode. +/// \param[in] cnode: A CNodePtr representing the computation node. +/// \return A set of integers representing the dependencies. MS_CORE_API std::set GetDependsFormMap(const CNodePtr &cnode); +/// \brief Registers shape and value inference implementations for a primitive. +/// \param[in] primitive: A PrimitivePtr representing the primitive for which to register the implementations. +/// \param[in] impl_reg: A StandardPrimitiveImplReg struct containing the inference implementations and a flag indicating if it's in the white list MS_CORE_API void RegisterStandardPrimitiveImpl(const PrimitivePtr &primitive, const StandardPrimitiveImplReg &impl_reg); +// Helper class for registering shape and value inference implementations for primitives. class RegisterStandardPrimitiveEvalHelper { public: RegisterStandardPrimitiveEvalHelper(const PrimitivePtr &primitive, const InferShapeImpl &infer_impl, @@ -68,6 +87,7 @@ class RegisterStandardPrimitiveEvalHelper { ~RegisterStandardPrimitiveEvalHelper() = default; }; +// Macro to simplify the registration of shape and value inference implementations for primitives. #define REGISTER_PRIMITIVE_EVAL_IMPL(name, primitive, infer_impl, infer_value_impl, is_white_list) \ static auto helper_##name = \ abstract::RegisterStandardPrimitiveEvalHelper(primitive, infer_impl, infer_value_impl, is_white_list); \ @@ -78,4 +98,4 @@ class RegisterStandardPrimitiveEvalHelper { ops::OpPrimCRegisterHelper primc_gen_##name(#name, GetDefaultPrimC##name); } // namespace abstract } // namespace mindspore -#endif // MINDSPORE_CORE_ABSTRACT_PRIMITIVE_INFER_MAP_H_ +#endif // MINDSPORE_CORE_ABSTRACT_PRIMITIVE_INFER_MAP_H_ \ No newline at end of file diff --git a/mindspore/core/abstract/utils.cc b/mindspore/core/abstract/utils.cc index 37127ff3906..4d7aa797bc6 100644 --- a/mindspore/core/abstract/utils.cc +++ b/mindspore/core/abstract/utils.cc @@ -24,33 +24,36 @@ namespace mindspore { namespace abstract { +// A mapping of MindSpore data types to their sizes in bytes const std::map type_map = { {kNumberTypeBool, 1}, {kNumberTypeInt, 4}, {kNumberTypeInt8, 1}, {kNumberTypeInt16, 2}, {kNumberTypeInt32, 4}, {kNumberTypeInt64, 8}, {kNumberTypeUInt, 4}, {kNumberTypeUInt8, 1}, {kNumberTypeUInt16, 2}, {kNumberTypeUInt32, 4}, {kNumberTypeUInt64, 8}, {kNumberTypeFloat, 4}, {kNumberTypeFloat16, 2}, {kNumberTypeFloat32, 4}, {kNumberTypeFloat64, 8}, {kNumberTypeComplex64, 8}, {kNumberTypeComplex128, 16}}; - ValuePtr ValueJoin(const ValuePtr &value1, const ValuePtr &value2) { MS_EXCEPTION_IF_NULL(value1); MS_EXCEPTION_IF_NULL(value2); if (*value1 == *value2) { - return value1; + return value1; } return kAnyValue; } - +// Join two Type objects TypePtr TypeJoin(const TypePtr &type1, const TypePtr &type2) { MS_EXCEPTION_IF_NULL(type1); MS_EXCEPTION_IF_NULL(type2); + // If the two types are equal, return one of them if (*type1 == *type2) { return type1; } + // Otherwise, return a generic "Any" type return kAnyType; } +// Calculate the dynamic shape based on two shapes and a vector of dimensions ShapePtr CalculateDynamicShape(const ShapePtr &shape1, const ShapePtr &shape2, const ShapeVector &dims) { - // calculate dynamic shape + // Initialize min_dims and max_dims with the provided dimensions ShapeVector min_dims(dims.size()); ShapeVector max_dims(dims.size()); MS_EXCEPTION_IF_NULL(shape1); @@ -83,7 +86,7 @@ ShapePtr CalculateDynamicShape(const ShapePtr &shape1, const ShapePtr &shape2, c max_dims[i] = std::max(shape1->shape()[i], shape2->max_shape()[i]); continue; } - // both shapes contains dynamic shape + // Both shapes contain dynamic shape if (shape1->min_shape().size() <= i || shape1->max_shape().size() <= i) { MS_EXCEPTION(ValueError) << "Shape " << shape1->ToString() << " has dynamic shape, but does not have min/max shape info."; @@ -95,18 +98,21 @@ ShapePtr CalculateDynamicShape(const ShapePtr &shape1, const ShapePtr &shape2, c min_dims[i] = std::min(shape1->min_shape()[i], shape2->min_shape()[i]); max_dims[i] = std::max(shape1->max_shape()[i], shape2->max_shape()[i]); } + // Create a new Shape object with the calculated dynamic shape return std::make_shared(dims, min_dims, max_dims); } +// Join two Shape objects ShapePtr ShapeJoin(const ShapePtr &shape1, const ShapePtr &shape2) { MS_EXCEPTION_IF_NULL(shape1); MS_EXCEPTION_IF_NULL(shape2); + // If the two shapes are equal, return one of them if (*shape1 == *shape2) { return shape1; } - // lengths of two shapes are not same, join failed + // If the lengths of the two shapes are not the same, join failed if (shape1->shape().size() != shape2->shape().size()) { - // special case: shape(1), shape() -> shape(1) + // Special case: shape(1), shape() -> shape(1) if (shape1->shape().size() == 1 && shape1->shape()[0] == 1 && shape2->shape().empty()) { return shape1; } @@ -130,35 +136,41 @@ ShapePtr ShapeJoin(const ShapePtr &shape1, const ShapePtr &shape2) { } } if (!has_dynamic_shape) { + // If there are no dynamic shapes, return a new Shape with the calculated dimensions return std::make_shared(dims); } + // If there are dynamic shapes, calculate the dynamic shape based on the two shapes and dimensions return CalculateDynamicShape(shape1, shape2, dims); } +// Join a list of AbstractBasePtr objects AbstractBasePtr AbstractJoin(const AbstractBasePtrList &args_spec_list) { if (args_spec_list.empty()) { - MS_LOG(EXCEPTION) << "AbstractJoin requires at least 1 params, while the input size is " << args_spec_list.size() + MS_LOG(EXCEPTION) << "AbstractJoin requires at least 1 parameter, but the input size is " << args_spec_list.size() << "."; } AbstractBasePtr arg_spec_tmp = args_spec_list[0]; MS_EXCEPTION_IF_NULL(arg_spec_tmp); for (const auto &arg_spec : args_spec_list) { MS_EXCEPTION_IF_NULL(arg_spec); + // Join the AbstractBasePtr objects to create a new one arg_spec_tmp = arg_spec_tmp->Join(arg_spec); MS_EXCEPTION_IF_NULL(arg_spec_tmp); } return arg_spec_tmp; } +// Join two lists of AbstractBasePtr objects AbstractBasePtrList AbstractJoin(const AbstractBasePtrList &spec1, const AbstractBasePtrList &spec2) { if (spec1.size() != spec2.size()) { - MS_LOG(EXCEPTION) << "Join failed as list don't have the same size. spec1: " << ::mindspore::ToString(spec1) - << ", spec2: " << ::mindspore::ToString(spec2); + MS_LOG(EXCEPTION) << "Join failed because the lists do not have the same size. spec1: " + << ::mindspore::ToString(spec1) << ", spec2: " << ::mindspore::ToString(spec2); } AbstractBasePtrList joined_list; bool changes = false; for (std::size_t i = 0; i < spec1.size(); i++) { MS_EXCEPTION_IF_NULL(spec1[i]); + // Join each pair of AbstractBasePtr objects in the lists auto joined_elem = spec1[i]->Join(spec2[i]); MS_EXCEPTION_IF_NULL(joined_elem); if (joined_elem != spec1[i]) { @@ -167,20 +179,28 @@ AbstractBasePtrList AbstractJoin(const AbstractBasePtrList &spec1, const Abstrac joined_list.push_back(joined_elem); } if (!changes) { + // If there are no changes, return spec1 return spec1; } + // Otherwise, return the joined_list return joined_list; } +// Transform an AbstractBasePtr into its sensitivity AbstractBasePtr SensitivityTransform(const AbstractBasePtr &spec) { + // Check if the spec is an AbstractFunction AbstractFunctionPtr f_spec = dyn_cast(spec); if (f_spec != nullptr) { + // If it is, return an AbstractScalar with "AnyValue" and an EnvType return std::make_shared(kAnyValue, std::make_shared()); } + // Otherwise, return a clone of the spec return spec->Clone(); } +// Broadcast two ShapeVectors to have the same dimensions ShapeVector BroadcastShape(ShapeVector shpx, ShapeVector shpy) { + // Calculate the difference in dimensions int dlen = SizeToInt(shpx.size()) - SizeToInt(shpy.size()); if (dlen < 0) { for (int i = 0; i < -dlen; ++i) { @@ -191,6 +211,7 @@ ShapeVector BroadcastShape(ShapeVector shpx, ShapeVector shpy) { (void)shpy.insert(shpy.begin(), 1); } } + // Check if the two ShapeVectors have the same size if (shpx.size() != shpy.size()) { MS_LOG(EXCEPTION) << "Failure: shpx.size() != shpy.size()."; } @@ -209,26 +230,34 @@ ShapeVector BroadcastShape(ShapeVector shpx, ShapeVector shpy) { } else if (a == b) { shp.push_back(a); } else { + // If dimensions are incompatible, return an empty ShapeVector return ShapeVector(); } } + // Return the broadcasted ShapeVector return shp; } +// Get the size in bytes for a given data type size_t TypeIdSize(const TypeId data_type) { const size_t unsupported_type_error = 0; auto iter = type_map.find(data_type); if (iter != type_map.end()) { return iter->second; } + // If the data type is not in the map, return 0 (unsupported type) return unsupported_type_error; } +// Check and update the minimum and maximum shapes based on a new shape void CheckMinMaxShape(const ShapeVector &shape, ShapeVector *min_shape, ShapeVector *max_shape) { + // If min_shape is empty, set it to the new shape *min_shape = (*min_shape).empty() ? shape : *min_shape; + // If max_shape is empty, set it to the new shape *max_shape = (*max_shape).empty() ? shape : *max_shape; } +// Create an AbstractTensor with the given shape and type AbstractBasePtr MakeAbstractTensor(const ShapePtr &shape, const TypePtr &type) { MS_EXCEPTION_IF_NULL(shape); MS_EXCEPTION_IF_NULL(type); @@ -254,18 +283,22 @@ AbstractBasePtr MakeAbstractTensor(const ShapePtr &shape, const TypePtr &type) { auto element = std::make_shared(kAnyValue, type); tensor = std::make_shared(element, ret_shape); } + // Return the created AbstractTensor return tensor; } +// Create a Monad abstract based on the given MonadType AbstractBasePtr MakeMonadAbstract(const MonadTypePtr &type) { if (type->isa()) { return kUMonad->ToAbstract(); } else if (type->isa()) { return kIOMonad->ToAbstract(); } + // Raise an exception for unsupported MonadType MS_EXCEPTION(UnknownError) << "Unsupported to convert type " << type->ToString() << " to monad abstract"; } +// Create an AbstractBasePtr based on a BaseShapePtr and a TypePtr AbstractBasePtr MakeAbstract(const BaseShapePtr &base_shape, const TypePtr &type) { MS_EXCEPTION_IF_NULL(base_shape); MS_EXCEPTION_IF_NULL(type); @@ -273,11 +306,12 @@ AbstractBasePtr MakeAbstract(const BaseShapePtr &base_shape, const TypePtr &type auto shape = base_shape->cast(); MS_EXCEPTION_IF_NULL(shape); auto shape_vec = shape->shape(); - // if the size of shape list is empty, return an scalar abstract + // If the size of shape list is empty and the type is not TensorType, return an AbstractScalar if (shape_vec.empty() && (!type->isa())) { abstract::AbstractScalarPtr abs_scalar = std::make_shared(kAnyValue, type); return abs_scalar; } + // Create an AbstractTensor based on the given shape and type return MakeAbstractTensor(shape, type); } else if (base_shape->isa() && type->isa()) { auto shape_tuple = base_shape->cast(); @@ -287,6 +321,7 @@ AbstractBasePtr MakeAbstract(const BaseShapePtr &base_shape, const TypePtr &type auto tensor_it = MakeAbstract((*shape_tuple)[it], (*type_tuple)[it]); ptr_list.push_back(tensor_it); } + // Create an AbstractTuple based on the given list of AbstractBasePtr auto tuple = std::make_shared(ptr_list); return tuple; } else if (base_shape->isa() && type->isa()) { @@ -297,6 +332,7 @@ AbstractBasePtr MakeAbstract(const BaseShapePtr &base_shape, const TypePtr &type auto tensor_it = MakeAbstract((*shape_list)[it], (*type_list)[it]); ptr_list.push_back(tensor_it); } + // Create an AbstractList based on the given list of AbstractBasePtr auto list = std::make_shared(ptr_list); return list; } else if (base_shape->isa() && type->isa()) { @@ -304,18 +340,20 @@ AbstractBasePtr MakeAbstract(const BaseShapePtr &base_shape, const TypePtr &type auto abstract_none = std::make_shared(); return abstract_none; } else if (type->isa()) { - // Return monad abstract if it is monad type. + // Return a Monad abstract if it is a MonadType return MakeMonadAbstract(type->cast()); } else { - // When sparse enabled, the undetermined might be raised and eliminated in opt passes + // When sparse is enabled, the "Undetermined" type might be raised and eliminated in optimization passes auto context = MsContext::GetInstance(); MS_EXCEPTION_IF_NULL(context); bool enable_sparse = context->get_param(MS_CTX_ENABLE_SPARSE); if (enable_sparse) { return std::make_shared(); } - MS_LOG(EXCEPTION) << "evaluator return invalid shape " << base_shape->ToString() << "or type. " << type->ToString(); + MS_LOG(EXCEPTION) << "Evaluator returned an invalid shape " << base_shape->ToString() << " or type " + << type->ToString(); } } + } // namespace abstract -} // namespace mindspore +} // namespace mindspore \ No newline at end of file diff --git a/mindspore/core/abstract/utils.h b/mindspore/core/abstract/utils.h index 5a98da43911..39648fd61a3 100644 --- a/mindspore/core/abstract/utils.h +++ b/mindspore/core/abstract/utils.h @@ -32,32 +32,102 @@ namespace mindspore { namespace abstract { + +/// \brief Joins two values. + +/// \param[in] value1: The first ValuePtr to join. +/// \param[in] value2: The second ValuePtr to join. + +/// \return A ValuePtr representing the result of joining value1 and value2. ValuePtr ValueJoin(const ValuePtr &value1, const ValuePtr &value2); + +/// \brief Joins two types. + +/// \param[in] type1: The first TypePtr to join. +/// \param[in] type2: The second TypePtr to join. + +/// \return A TypePtr representing the result of joining type1 and type2. MS_CORE_API TypePtr TypeJoin(const TypePtr &type1, const TypePtr &type2); + +/// \brief Joins two shapes. + +/// \param[in] shape1: The first ShapePtr to join. +/// \param[in] shape2: The second ShapePtr to join. + +/// \return A ShapePtr representing the result of joining shape1 and shape2. ShapePtr ShapeJoin(const ShapePtr &shape1, const ShapePtr &shape2); +/// \brief Joins a list of AbstractBasePtr. + +/// \param[in] args_spec_list: A list of AbstractBasePtr to join. + +/// \return An AbstractBasePtr representing the result of joining the input AbstractBasePtrs. MS_CORE_API AbstractBasePtr AbstractJoin(const AbstractBasePtrList &args_spec_list); + +/// \brief Joins two lists of AbstractBasePtr. + +/// \param[in] spec1: The first list of AbstractBasePtr to join. +/// \param[in] spec2: The second list of AbstractBasePtr to join. + +/// \return A list of AbstractBasePtr representing the result of joining spec1 and spec2. MS_CORE_API AbstractBasePtrList AbstractJoin(const AbstractBasePtrList &spec1, const AbstractBasePtrList &spec2); -// Return an abstract value for the sensitivity of x. -// The sensitivity of a function is an Env -// The sensitivity of J(x) is x -// else self.Clone; +/// \brief Transforms the sensitivity of an AbstractBasePtr. + +/// \param[in] spec: The AbstractBasePtr to transform. + +/// \return An AbstractBasePtr representing the transformed AbstractBasePtr. MS_CORE_API AbstractBasePtr SensitivityTransform(const AbstractBasePtr &spec); +/// \brief Computes the broadcasted shape of two ShapeVectors. + +/// \param[in] shpx: The first ShapeVector. +/// \param[in] shpy: The second ShapeVector. + +/// \return A ShapeVector representing the broadcasted shape of shpx and shpy. ShapeVector BroadcastShape(ShapeVector shpx, ShapeVector shpy); + +/// \brief Returns the size of a data type based on its TypeId. + +/// \param[in] data_type: The TypeId of the data type. + +/// \return The size of the data type in bytes. MS_CORE_API size_t TypeIdSize(const TypeId data_type); -template + T ShapeSize(const std::vector &shape) { return std::accumulate(shape.begin(), shape.end(), static_cast(1), std::multiplies()); } -// Check dynamic shape routine +/// \brief Checks and updates the minimum and maximum shapes based on the given shape. + +/// \param[in] shape: The shape to check. +/// \param[in, out] min_shape: A pointer to the minimum shape vector, which will be updated if the input shape is smaller. +/// \param[in, out] max_shape: A pointer to the maximum shape vector, which will be updated if the input shape is larger. void CheckMinMaxShape(const ShapeVector &shape, ShapeVector *min_shape, ShapeVector *max_shape); +/// \brief Creates an AbstractBasePtr from a BaseShapePtr and a TypePtr. + +/// \param[in] base_shape: The BaseShapePtr to use for creating the AbstractBasePtr. +/// \param[in] type: The TypePtr to use for creating the AbstractBasePtr. + +/// \return An AbstractBasePtr representing the specified shape and type. AbstractBasePtr MakeAbstract(const BaseShapePtr &base_shape, const TypePtr &type); + +/// \brief Creates an AbstractBasePtr from a MonadTypePtr. + +/// \param[in] type: The MonadTypePtr to use for creating the AbstractBasePtr. + +/// \return An AbstractBasePtr representing the specified monadic type. MS_CORE_API AbstractBasePtr MakeMonadAbstract(const MonadTypePtr &type); + +/// \brief Creates an AbstractBasePtr from a ShapePtr and a TypePtr. + +/// \param[in] shape: The ShapePtr to use for creating the AbstractBasePtr. +/// \param[in] type: The TypePtr to use for creating the AbstractBasePtr. + +/// \return An AbstractBasePtr representing the specified shape and type. MS_CORE_API AbstractBasePtr MakeAbstractTensor(const ShapePtr &shape, const TypePtr &type); + } // namespace abstract } // namespace mindspore #endif // MINDSPORE_CORE_ABSTRACT_UTILS_H_