// Equal handler.
bool AttrsEqualHandler::Equal(const ObjectRef& lhs, const ObjectRef& rhs) {
if (lhs.same_as(rhs)) return true;
- if (!lhs.defined() || !rhs.defined()) return false;
+ if (!lhs.defined() && rhs.defined()) return false;
+ if (!rhs.defined() && lhs.defined()) return false;
return this->VisitAttr(lhs, rhs);
}
bool AttrsEqualHandler::VisitAttr_(const IntImmNode* lhs, const ObjectRef& other) {
if (const auto* rhs = other.as<IntImmNode>()) {
return lhs->value == rhs->value;
+ } else {
+ return false;
}
- return false;
}
bool AttrsEqualHandler::VisitAttr_(const FloatImmNode* lhs, const ObjectRef& other) {
if (const auto* rhs = other.as<FloatImmNode>()) {
return lhs->value == rhs->value;
+ } else {
+ return false;
}
- return false;
}
bool AttrsEqualHandler::VisitAttr_(const StringImmNode* lhs, const ObjectRef& other) {
if (const auto* rhs = other.as<StringImmNode>()) {
return lhs->value == rhs->value;
+ } else {
+ return false;
}
- return false;
}
bool AttrsEqualHandler::VisitAttr_(const ArrayNode* lhs, const ObjectRef& other) {
for (size_t i = 0; i < lhs->data.size(); ++i) {
if (!Equal(lhs->data[i], rhs->data[i])) return false;
}
+ return true;
+ } else {
+ return false;
}
- return true;
}
bool AttrsEqualHandler::VisitAttr_(const StrMapNode* lhs, const ObjectRef& other) {
if (it == rhs->data.end()) return false;
if (!Equal(kv.second, it->second)) return false;
}
+ return true;
+ } else {
+ return false;
}
- return true;
}
#define TVM_DEFINE_ATTRS_BINOP_EQUAL(NodeName) \
}
TVM_REGISTER_GLOBAL("ir.AttrsListFieldInfo")
-.set_body([](TVMArgs args, TVMRetValue* ret) {
- *ret = args[0].operator Attrs()->ListFieldInfo();
+.set_body_typed([](Attrs attrs) {
+ return attrs->ListFieldInfo();
+});
+
+TVM_REGISTER_GLOBAL("ir.AttrsEqual")
+.set_body_typed([](ObjectRef lhs, ObjectRef rhs) {
+ return AttrsEqual()(lhs, rhs);
});
} // namespace tvm
explicit DocTextNode(std::string str_val)
: str(str_val) {
- if (str.find_first_of("\t\n") != str.npos) {
- LOG(WARNING) << "text node: '" << str << "' should not has tab or newline.";
- }
}
static constexpr const char* _type_key = "printer.DocText";
class DocText : public DocAtom {
public:
explicit DocText(std::string str) {
+ if (str.find_first_of("\t\n") != str.npos) {
+ LOG(WARNING) << "text node: '" << str << "' should not has tab or newline.";
+ }
data_ = runtime::make_object<DocTextNode>(str);
}
return Doc() << DocText(text);
}
+Doc Doc::RawText(std::string text) {
+ return Doc() << DocAtom(runtime::make_object<DocTextNode>(text));
+}
+
Doc Doc::Indent(int indent, Doc doc) {
for (size_t i = 0; i < doc.stream_.size(); ++i) {
if (auto* line = doc.stream_[i].as<DocLineNode>()) {
#include <tvm/relay/op_attr_types.h>
#include <tvm/relay/attrs/nn.h>
#include "../../ir/attr_functor.h"
+
+
namespace tvm {
namespace relay {
* \return The comparison result.
*/
bool Equal(const ObjectRef& lhs, const ObjectRef& rhs) {
- if (!lhs.defined() || !rhs.defined()) return false;
- if (lhs.same_as(rhs)) return true;
- if (lhs->IsInstance<TypeNode>() || rhs->IsInstance<TypeNode>()) {
- if (!rhs->IsInstance<TypeNode>() || !lhs->IsInstance<TypeNode>()) return false;
- return TypeEqual(Downcast<Type>(lhs), Downcast<Type>(rhs));
- }
- if (lhs->IsInstance<ExprNode>() || rhs->IsInstance<ExprNode>()) {
- if (!rhs->IsInstance<ExprNode>() || !lhs->IsInstance<ExprNode>()) return false;
- return ExprEqual(Downcast<Expr>(lhs), Downcast<Expr>(rhs));
- }
- if (const auto lhsm = lhs.as<IRModuleNode>()) {
- auto rhsm = rhs.as<IRModuleNode>();
- if (!rhsm) return false;
- if (lhsm->functions.size() != rhsm->functions.size()) return false;
- for (const auto& p : lhsm->functions) {
- if (!Equal(p.second, rhsm->Lookup(p.first->name_hint))) return false;
- }
- if (lhsm->type_definitions.size() != rhsm->type_definitions.size()) return false;
- for (const auto& p : lhsm->type_definitions) {
- if (!rhsm->ContainGlobalTypeVar(p.first->name_hint) ||
- !Equal(p.second, rhsm->LookupTypeDef(p.first->name_hint))) {
- return false;
- }
- }
- return true;
- }
- return AttrEqual(lhs, rhs);
- }
-
- bool DoubleEqual(double l, double r) {
- return true;
+ return VisitAttr(lhs, rhs);
}
/*!
* Check equality of two attributes.
*/
bool AttrEqual(const ObjectRef& lhs, const ObjectRef& rhs) {
auto compute = [&]() {
- if (&lhs == &rhs) return true;
- if (auto lhsd = lhs.as<DictAttrsNode>()) {
- auto rhsd = rhs.as<DictAttrsNode>();
- if (!rhsd) return false;
- if (lhsd->dict.size() != rhsd->dict.size()) return false;
- for (const auto& k : lhsd->dict) {
- if (!Equal(k.second, rhsd->dict[k.first])) return false;
- }
- return true;
- }
- if (auto lhsbn = lhs.as<BatchNormAttrs>()) {
- auto rhsbn = rhs.as<BatchNormAttrs>();
- if (!rhsbn) return false;
- return (lhsbn->axis == rhsbn->axis)
- && DoubleEqual(lhsbn->epsilon, rhsbn->epsilon)
- && (lhsbn->center == rhsbn->center)
- && (lhsbn->scale == rhsbn->scale);
- }
- return AttrsEqualHandler::Equal(lhs, rhs);
+ return VisitAttr(lhs, rhs);
};
return Compare(compute(), lhs, rhs);
}
}
protected:
+ // So that the new definition of equality in relay can be handled directly.
+ // Specifically, if a DictAttr contains a value defined by a relay AST.
+ // We want to able to recursively check the equality in the attr defined by the relay AST.
+ bool VisitAttr(const ObjectRef& lhs, const ObjectRef& rhs) final {
+ if (lhs.same_as(rhs)) return true;
+ if (!lhs.defined() && rhs.defined()) return false;
+ if (!rhs.defined() && lhs.defined()) return false;
+ if (lhs->IsInstance<TypeNode>() || rhs->IsInstance<TypeNode>()) {
+ if (!rhs->IsInstance<TypeNode>() || !lhs->IsInstance<TypeNode>()) return false;
+ return TypeEqual(Downcast<Type>(lhs), Downcast<Type>(rhs));
+ }
+ if (lhs->IsInstance<ExprNode>() || rhs->IsInstance<ExprNode>()) {
+ if (!rhs->IsInstance<ExprNode>() || !lhs->IsInstance<ExprNode>()) return false;
+ return ExprEqual(Downcast<Expr>(lhs), Downcast<Expr>(rhs));
+ }
+ if (const auto lhsm = lhs.as<IRModuleNode>()) {
+ auto rhsm = rhs.as<IRModuleNode>();
+ if (!rhsm) return false;
+ if (lhsm->functions.size() != rhsm->functions.size()) return false;
+ for (const auto& p : lhsm->functions) {
+ if (!Equal(p.second, rhsm->Lookup(p.first->name_hint))) return false;
+ }
+ if (lhsm->type_definitions.size() != rhsm->type_definitions.size()) return false;
+ for (const auto& p : lhsm->type_definitions) {
+ if (!rhsm->ContainGlobalTypeVar(p.first->name_hint) ||
+ !Equal(p.second, rhsm->LookupTypeDef(p.first->name_hint))) {
+ return false;
+ }
+ }
+ return true;
+ }
+ // Fall back to the object equal case.
+ return AttrsEqualHandler::VisitAttr(lhs, rhs);
+ }
/*!
* \brief Check if data type equals each other.
* \param lhs The left hand operand.