diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc index e535d6f9d..579c6700a 100644 --- a/src/db/db/dbNetlistCompare.cc +++ b/src/db/db/dbNetlistCompare.cc @@ -345,13 +345,13 @@ public: // .. nothing yet .. } - void map (const Obj *a, const Obj *b) + bool map (const Obj *a, const Obj *b) { - bool inserted; - inserted = m_eq.insert (std::make_pair (a, b)).second; - tl_assert (inserted == true); - inserted = m_eq.insert (std::make_pair (b, a)).second; - tl_assert (inserted == true); + std::pair::iterator, bool> inserted1 = m_eq.insert (std::make_pair (a, b)); + tl_assert (inserted1.first->second == b); + std::pair::iterator, bool> inserted2 = m_eq.insert (std::make_pair (b, a)); + tl_assert (inserted2.first->second == a); + return inserted1.second; } const Obj *other (const Obj *o) const @@ -673,6 +673,16 @@ public: m_id2 = pin2_id; } + size_t id1 () const + { + return m_id1; + } + + size_t id2 () const + { + return m_id2; + } + bool operator< (const Transition &other) const { if (is_for_subcircuit () != other.is_for_subcircuit ()) { @@ -1107,7 +1117,7 @@ public: * with a proposed identity. With "with_ambiguous", amiguities are resolved by trying * different combinations in tentative mode and deciding for one combination if possible. */ - size_t derive_node_identities_from_node_set (std::vector &nodes, std::vector &other_nodes, size_t depth, size_t n_branch, TentativeNodeMapping *tentative, bool with_ambiguous, CompareData *data); + size_t derive_node_identities_from_node_set (NetGraphNode::edge_iterator e, NetGraphNode::edge_iterator ee, NetGraphNode::edge_iterator e_other, NetGraphNode::edge_iterator ee_other, std::vector &nodes, std::vector &other_nodes, size_t depth, size_t n_branch, TentativeNodeMapping *tentative, bool with_ambiguous, CompareData *data); private: std::vector m_nodes; @@ -1631,6 +1641,39 @@ NetGraph::build (const db::Circuit *c, DeviceCategorizer &device_categorizer, Ci } } +/** + * @brief Returns true if the edges (given by transition iterators) are compatible with already established device or subcircuit equivalences. + */ +static bool edges_are_compatible (std::vector::const_iterator t, std::vector::const_iterator tt, std::vector::const_iterator t_other, std::vector::const_iterator tt_other, const DeviceEquivalenceTracker &device_eq, const SubCircuitEquivalenceTracker &sc_eq) +{ + while (t != tt && t_other != tt_other) { + + tl_assert (*t == *t_other); + + if (t->is_for_subcircuit ()) { + + const db::SubCircuit *other = sc_eq.other (t->subcircuit_pair ().first); + if (other && other != t_other->subcircuit_pair ().first) { + return false; + } + + } else { + + const db::Device *other = device_eq.other (t->device_pair ().first); + if (other && other != t_other->device_pair ().first) { + return false; + } + + } + + ++t; + ++t_other; + + } + + return true; +} + size_t NetGraph::derive_node_identities_for_edges (NetGraphNode::edge_iterator e, NetGraphNode::edge_iterator ee, NetGraphNode::edge_iterator e_other, NetGraphNode::edge_iterator ee_other, size_t net_index, size_t other_net_index, size_t depth, size_t n_branch, TentativeNodeMapping *tentative, bool with_ambiguous, CompareData *data) { @@ -1641,6 +1684,9 @@ NetGraph::derive_node_identities_for_edges (NetGraphNode::edge_iterator e, NetGr std::vector other_nodes; other_nodes.reserve (ee - e); + + tl_assert (e->first == e_other->first); + if (options ()->debug_netcompare) { tl::info << indent(depth) << "considering transitions:"; } @@ -1665,6 +1711,15 @@ NetGraph::derive_node_identities_for_edges (NetGraphNode::edge_iterator e, NetGr } } + // reject the transition if the edges provide a contradiction to already established equivalences + + if (! edges_are_compatible (e->first.begin (), e->first.end (), e_other->first.begin (), e_other->first.end (), *data->device_equivalence, *data->subcircuit_equivalence)) { + if (options ()->debug_netcompare) { + tl::info << indent(depth) << "=> rejected because edges are incompatible with already established device or subcircuit equivalences"; + } + return tentative ? failed_match : 0; + } + if (! nodes.empty ()) { // if non-ambiguous, non-assigned first = true; @@ -1722,7 +1777,7 @@ NetGraph::derive_node_identities_for_edges (NetGraphNode::edge_iterator e, NetGr // propagate pairing in picky mode: this means we only accept exact a match if the node set // is exactly identical and no ambiguous nodes are present when ambiguous nodes are forbidden - size_t bt_count = derive_node_identities_from_node_set (nodes, other_nodes, depth, n_branch, tentative, with_ambiguous, data); + size_t bt_count = derive_node_identities_from_node_set (e, ee, e_other, ee_other, nodes, other_nodes, depth, n_branch, tentative, with_ambiguous, data); if (bt_count == failed_match) { if (tentative) { @@ -1947,8 +2002,167 @@ static bool net_names_are_different (const db::Net *a, const db::Net *b) } } +namespace { + +struct CatAndIds +{ +public: + CatAndIds (size_t _cat, size_t _id1, size_t _id2) + : cat (_cat), id1 (_id1), id2 (_id2) + { } + + bool operator== (const CatAndIds &other) const + { + return cat == other.cat && id1 == other.id1 && id2 == other.id2; + } + + bool operator< (const CatAndIds &other) const + { + if (cat != other.cat) { + return cat < other.cat; + } + if (id1 != other.id1) { + return id1 < other.id1; + } + if (id2 != other.id2) { + return id2 < other.id2; + } + return false; + } + + size_t cat, id1, id2; +}; + +template +static std::string log_text_for_equivalence (); + +template <> +static std::string log_text_for_equivalence () +{ + return "enforcing device equivalence"; +} + +template <> +static std::string log_text_for_equivalence () +{ + return "enforcing subcircuit equivalence"; +} + +template +class generic_mapper_for_target_node +{ +public: + generic_mapper_for_target_node () + { + // .. nothing yet .. + } + + static void derive_mapping (const generic_mapper_for_target_node &m1, const generic_mapper_for_target_node &m2, size_t n1, size_t n2, generic_equivalence_tracker &eq, size_t depth) + { + if (m1.empty () || m2.empty ()) { + return; + } + + const std::set > &s1 = m1.for_node (n1); + const std::set > &s2 = m2.for_node (n2); + + typename std::set >::const_iterator i1 = s1.begin (), i2 = s2.begin (); + + while (i1 != s1.end () && i2 != s2.end ()) { + + if (i1->first < i2->first) { + ++i1; + } else if (i2->first < i1->first) { + ++i2; + } else { + typename std::set >::const_iterator i10 = i1, i20 = i2; + size_t n1 = 0, n2 = 0; + while (i1 != s1.end () && i1->first == i10->first) { + ++i1; + ++n1; + } + while (i2 != s2.end () && i2->first == i20->first) { + ++i2; + ++n2; + } + if (n1 == 1 && n2 == 1) { + // unique mapping - one device of one category + if (eq.map (i10->second, i20->second)) { + if (options ()->debug_netcompare) { + tl::info << indent(depth) << log_text_for_equivalence () << ": " << i10->second->expanded_name () << " vs. " << i20->second->expanded_name (); + } + } + } + } + + } + + } + +protected: + const std::set > &for_node (size_t ni) const + { + typename std::map > >::const_iterator d = m_per_target_node.find (ni); + tl_assert (d != m_per_target_node.end ()); + return d->second; + } + + std::set > &for_node_nc (size_t ni) + { + return m_per_target_node [ni]; + } + + bool empty () const + { + return m_per_target_node.empty (); + } + +private: + std::map > > m_per_target_node; +}; + +class DeviceMapperForTargetNode + : public generic_mapper_for_target_node +{ +public: + DeviceMapperForTargetNode (NetGraphNode::edge_iterator e, NetGraphNode::edge_iterator ee) + : generic_mapper_for_target_node () + { + for (NetGraphNode::edge_iterator i = e; i != ee; ++i) { + size_t ni = i->second.first; + std::set > &dev = for_node_nc (ni); + for (std::vector::const_iterator j = i->first.begin (); j != i->first.end (); ++j) { + if (! j->is_for_subcircuit ()) { + dev.insert (std::make_pair (CatAndIds (j->device_pair ().second, j->id1 (), j->id2 ()), j->device_pair ().first)); + } + } + } + } +}; + +class SubCircuitMapperForTargetNode + : public generic_mapper_for_target_node +{ +public: + SubCircuitMapperForTargetNode (NetGraphNode::edge_iterator e, NetGraphNode::edge_iterator ee) + : generic_mapper_for_target_node () + { + for (NetGraphNode::edge_iterator i = e; i != ee; ++i) { + size_t ni = i->second.first; + std::set > &sc = for_node_nc (ni); + for (std::vector::const_iterator j = i->first.begin (); j != i->first.end (); ++j) { + if (j->is_for_subcircuit ()) { + sc.insert (std::make_pair (CatAndIds (j->subcircuit_pair ().second, j->id1 (), j->id2 ()), j->subcircuit_pair ().first)); + } + } + } + } +}; + +} + size_t -NetGraph::derive_node_identities_from_node_set (std::vector &nodes, std::vector &other_nodes, size_t depth, size_t n_branch, TentativeNodeMapping *tentative, bool with_ambiguous, CompareData *data) +NetGraph::derive_node_identities_from_node_set (NetGraphNode::edge_iterator e, NetGraphNode::edge_iterator ee, NetGraphNode::edge_iterator e_other, NetGraphNode::edge_iterator ee_other, std::vector &nodes, std::vector &other_nodes, size_t depth, size_t n_branch, TentativeNodeMapping *tentative, bool with_ambiguous, CompareData *data) { std::string indent_s; if (options ()->debug_netcompare) { @@ -1965,6 +2179,12 @@ NetGraph::derive_node_identities_from_node_set (std::vectorhas_any_other () && ! other_nodes.front ()->has_any_other ()) { @@ -1976,6 +2196,10 @@ NetGraph::derive_node_identities_from_node_set (std::vectorother->node_index_for_net (other_nodes.front ()->net ()); TentativeNodeMapping::map_pair (tentative, this, ni, data->other, other_ni); + if (! tentative) { + DeviceMapperForTargetNode::derive_mapping (dm, dm_other, ni, other_ni, *data->device_equivalence, depth); + SubCircuitMapperForTargetNode::derive_mapping (scm, scm_other, ni, other_ni, *data->subcircuit_equivalence, depth); + } if (options ()->debug_netcompare) { tl::info << indent_s << "deduced match (singular): " << nodes.front ()->net ()->expanded_name () << " vs. " << other_nodes.front ()->net ()->expanded_name (); @@ -2139,6 +2363,10 @@ NetGraph::derive_node_identities_from_node_set (std::vectorother->node_index_for_net ((*nr->n2)->net ()); TentativeNodeMapping::map_pair (tentative, this, ni, data->other, other_ni); + if (! tentative) { + DeviceMapperForTargetNode::derive_mapping (dm, dm_other, ni, other_ni, *data->device_equivalence, depth); + SubCircuitMapperForTargetNode::derive_mapping (scm, scm_other, ni, other_ni, *data->subcircuit_equivalence, depth); + } if (options ()->debug_netcompare) { tl::info << indent_s << "deduced match (singular): " << (*nr->n1)->net ()->expanded_name () << " vs. " << (*nr->n2)->net ()->expanded_name (); @@ -2301,8 +2529,9 @@ NetGraph::derive_node_identities_from_node_set (std::vectorfirst->net ()); size_t other_ni = data->other->node_index_for_net (p->second->net ()); - TentativeNodeMapping::map_pair (tentative, this, ni, data->other, other_ni); - // @@@ we should derive subcircuit and device mapping here. + TentativeNodeMapping::map_pair (0, this, ni, data->other, other_ni); + DeviceMapperForTargetNode::derive_mapping (dm, dm_other, ni, other_ni, *data->device_equivalence, depth); + SubCircuitMapperForTargetNode::derive_mapping (scm, scm_other, ni, other_ni, *data->subcircuit_equivalence, depth); if (options ()->debug_netcompare) { if (equivalent_other_nodes.has_attribute (p->second)) { @@ -3032,7 +3261,9 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, data.device_equivalence = &device_equivalence; data.logger = mp_logger; - size_t ni = g1.derive_node_identities_from_node_set (nodes, other_nodes, 0, 1, 0 /*not tentative*/, pass > 0 /*with ambiguities*/, &data); + NetGraphNode empty; + + size_t ni = g1.derive_node_identities_from_node_set (empty.begin (), empty.begin (), empty.begin (), empty.begin (), nodes, other_nodes, 0, 1, 0 /*not tentatively*/, pass > 0 /*with ambiguities*/, &data); if (ni > 0 && ni != failed_match) { new_identities += ni; if (options ()->debug_netcompare) {