From b74254228657f7b757f6abacf73776d25a4359ca Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 21 Jun 2020 23:41:16 +0200 Subject: [PATCH 1/7] Remove net sorting which is not required and partially based on net pointers --- src/db/db/dbNetlistCompare.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc index 39be51719..8f050160d 100644 --- a/src/db/db/dbNetlistCompare.cc +++ b/src/db/db/dbNetlistCompare.cc @@ -1533,8 +1533,6 @@ NetGraph::build (const db::Circuit *c, DeviceCategorizer &device_categorizer, Ci } } - std::sort (m_nodes.begin (), m_nodes.end ()); - for (std::vector::const_iterator i = m_nodes.begin (); i != m_nodes.end (); ++i) { m_net_index.insert (std::make_pair (i->net (), i - m_nodes.begin ())); } From 408a0b571dc777e641a0a9434a693d963789510b Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 22 Jun 2020 21:07:16 +0200 Subject: [PATCH 2/7] Updated test cases --- src/db/unit_tests/dbNetlistCompareTests.cc | 28 +++++++++++----------- testdata/lvs/double_height2.lvsdb | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/db/unit_tests/dbNetlistCompareTests.cc b/src/db/unit_tests/dbNetlistCompareTests.cc index c0d190f6d..934394ec9 100644 --- a/src/db/unit_tests/dbNetlistCompareTests.cc +++ b/src/db/unit_tests/dbNetlistCompareTests.cc @@ -2657,10 +2657,10 @@ TEST(17_InherentlyAmbiguousDecoder) "match_nets B B\n" "match_nets NB NB\n" "match_nets NA NA\n" - "match_nets NQ0 NQ0\n" - "match_nets NQ2 NQ2\n" "match_nets NQ1 NQ1\n" "match_nets NQ3 NQ3\n" + "match_nets NQ2 NQ2\n" + "match_nets NQ0 NQ0\n" "match_pins $0 $1\n" "match_pins $1 $0\n" "match_pins $2 $2\n" @@ -2922,24 +2922,24 @@ TEST(19_SymmetricCircuit) "match_nets g1 G1\n" "match_nets $44 YI\n" "match_nets $14 WELL\n" - "match_nets $8 NET215\n" - "match_nets $9 NET175\n" - "match_nets $6 NET181\n" - "match_nets $4 NET200\n" - "match_nets nn1 NN1\n" - "match_nets $11 CS0\n" - "match_nets $13 CS1\n" "match_nets nn2 NN2\n" "match_nets nn2_ NN2_\n" "match_nets q0 Q0\n" "match_nets q1 Q1\n" + "match_nets $11 CS0\n" "match_nets q0_ Q0_\n" + "match_nets $6 NET181\n" + "match_nets nn1 NN1\n" + "match_nets $8 NET215\n" + "match_nets $13 CS1\n" "match_nets q1_ Q1_\n" - "match_nets a0_ A0_\n" - "match_nets $34 HNET48\n" - "match_nets nn1_ NN1_\n" "match_nets a0 A0\n" "match_nets $35 HNET44\n" + "match_nets nn1_ NN1_\n" + "match_nets $9 NET175\n" + "match_nets $4 NET200\n" + "match_nets a0_ A0_\n" + "match_nets $34 HNET48\n" "match_pins VDD VDD\n" "match_pins nn1_ NN1_\n" "match_pins nn1 NN1\n" @@ -3805,11 +3805,11 @@ TEST(25c_JoinSymmetricNetsMultipleMessedUp) // NOTE $1 and $2 are joined because they are symmetric EXPECT_EQ (nl.to_string (), "circuit NOR3 (A=A,C=C,B=B,OUT=OUT,VSS=VSS,VDD=VDD);\n" - " device PMOS $1 (S=$5,G=B,D=$3) (L=0.27,W=3.3,AS=0,AD=0,PS=0,PD=0);\n" + " device PMOS $1 (S=$6,G=B,D=$3) (L=0.27,W=3.3,AS=0,AD=0,PS=0,PD=0);\n" " device NMOS $2 (S=OUT,G=A,D=VSS) (L=0.23,W=2.05,AS=0,AD=0,PS=0,PD=0);\n" " device PMOS $3 (S=$3,G=A,D=OUT) (L=0.27,W=3.3,AS=0,AD=0,PS=0,PD=0);\n" " device NMOS $4 (S=OUT,G=B,D=VSS) (L=0.23,W=2.05,AS=0,AD=0,PS=0,PD=0);\n" - " device PMOS $8 (S=VDD,G=C,D=$5) (L=0.27,W=3.3,AS=0,AD=0,PS=0,PD=0);\n" + " device PMOS $8 (S=VDD,G=C,D=$6) (L=0.27,W=3.3,AS=0,AD=0,PS=0,PD=0);\n" " device NMOS $12 (S=VSS,G=C,D=OUT) (L=0.23,W=2.05,AS=0,AD=0,PS=0,PD=0);\n" "end;\n" ) diff --git a/testdata/lvs/double_height2.lvsdb b/testdata/lvs/double_height2.lvsdb index f9d933d9c..b75ed63bc 100644 --- a/testdata/lvs/double_height2.lvsdb +++ b/testdata/lvs/double_height2.lvsdb @@ -314,8 +314,8 @@ Z( N(5 2 1) N(4 1 1) N(2 4 1) - P(2 () 1) P(0 () 1) + P(2 () 1) P(4 () 1) P(3 () 1) P(1 () 1) From d65888fcd991cec992efdfb05ef3a74c4110f9da Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 22 Jun 2020 21:07:29 +0200 Subject: [PATCH 3/7] WIP: better handling of ambiguity resolution --- src/db/db/dbNetlistCompare.cc | 259 +++++++++++++++++++++++----------- src/db/db/dbNetlistCompare.h | 6 +- 2 files changed, 183 insertions(+), 82 deletions(-) diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc index 8f050160d..e535d6f9d 100644 --- a/src/db/db/dbNetlistCompare.cc +++ b/src/db/db/dbNetlistCompare.cc @@ -333,6 +333,57 @@ private: double m_cap_threshold, m_res_threshold; }; +// -------------------------------------------------------------------------------------------------------------------- +// A generic equivalence mapper + +template +class generic_equivalence_tracker +{ +public: + generic_equivalence_tracker () + { + // .. nothing yet .. + } + + void 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); + } + + const Obj *other (const Obj *o) const + { + typename std::map::const_iterator i = m_eq.find (o); + return i == m_eq.end () ? 0 : i->second; + } + +public: + std::map m_eq; +}; + +// -------------------------------------------------------------------------------------------------------------------- +// A class describing the equivalence between subcircuits we established so far + +class SubCircuitEquivalenceTracker + : public generic_equivalence_tracker +{ +public: + SubCircuitEquivalenceTracker () : generic_equivalence_tracker () { } +}; + +// -------------------------------------------------------------------------------------------------------------------- +// A class describing the equivalence between devices we established so far + +class DeviceEquivalenceTracker + : public generic_equivalence_tracker +{ +public: + DeviceEquivalenceTracker () : generic_equivalence_tracker () { } +}; + // -------------------------------------------------------------------------------------------------------------------- // generic_categorizer definition and implementation @@ -559,7 +610,8 @@ class NetGraph; struct CompareData { CompareData () - : other (0), max_depth (0), max_n_branch (0), dont_consider_net_names (false), logger (0), circuit_pin_mapper (0) + : other (0), max_depth (0), max_n_branch (0), dont_consider_net_names (false), logger (0), + circuit_pin_mapper (0), subcircuit_equivalence (0), device_equivalence (0) { } NetGraph *other; @@ -568,6 +620,8 @@ struct CompareData bool dont_consider_net_names; NetlistCompareLogger *logger; CircuitPinMapper *circuit_pin_mapper; + SubCircuitEquivalenceTracker *subcircuit_equivalence; + DeviceEquivalenceTracker *device_equivalence; }; // -------------------------------------------------------------------------------------------------------------------- @@ -2248,6 +2302,7 @@ NetGraph::derive_node_identities_from_node_set (std::vectorother->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. if (options ()->debug_netcompare) { if (equivalent_other_nodes.has_attribute (p->second)) { @@ -2858,6 +2913,8 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, std::map &c22_circuit_and_pin_mapping) const { db::DeviceFilter device_filter (m_cap_threshold, m_res_threshold); + SubCircuitEquivalenceTracker subcircuit_equivalence; + DeviceEquivalenceTracker device_equivalence; db::NetGraph g1, g2; @@ -2912,6 +2969,8 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, data.max_n_branch = m_max_n_branch; data.dont_consider_net_names = m_dont_consider_net_names; data.circuit_pin_mapper = &circuit_pin_mapper; + data.subcircuit_equivalence = &subcircuit_equivalence; + data.device_equivalence = &device_equivalence; data.logger = mp_logger; size_t ni = g1.derive_node_identities (i1 - g1.begin (), 0, 1, 0 /*not tentative*/, pass > 0 /*with ambiguities*/, &data); @@ -2969,6 +3028,8 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, data.max_n_branch = m_max_n_branch; data.dont_consider_net_names = m_dont_consider_net_names; data.circuit_pin_mapper = &circuit_pin_mapper; + data.subcircuit_equivalence = &subcircuit_equivalence; + 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); @@ -3023,8 +3084,8 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, } do_pin_assignment (c1, g1, c2, g2, c12_circuit_and_pin_mapping, c22_circuit_and_pin_mapping, pin_mismatch, good); - do_device_assignment (c1, g1, c2, g2, device_filter, device_categorizer, good); - do_subcircuit_assignment (c1, g1, c2, g2, circuit_categorizer, circuit_pin_mapper, c12_circuit_and_pin_mapping, c22_circuit_and_pin_mapping, good); + do_device_assignment (c1, g1, c2, g2, device_filter, device_categorizer, device_equivalence, good); + do_subcircuit_assignment (c1, g1, c2, g2, circuit_categorizer, circuit_pin_mapper, c12_circuit_and_pin_mapping, c22_circuit_and_pin_mapping, subcircuit_equivalence, good); return good; } @@ -3239,7 +3300,7 @@ NetlistComparer::do_pin_assignment (const db::Circuit *c1, const db::NetGraph &g } void -NetlistComparer::do_device_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, const db::DeviceFilter &device_filter, db::DeviceCategorizer &device_categorizer, bool &good) const +NetlistComparer::do_device_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, const db::DeviceFilter &device_filter, db::DeviceCategorizer &device_categorizer, DeviceEquivalenceTracker &device_eq, bool &good) const { // Report device assignment @@ -3254,6 +3315,10 @@ NetlistComparer::do_device_assignment (const db::Circuit *c1, const db::NetGraph continue; } + if (device_eq.other (d.operator-> ())) { + continue; + } + size_t device_cat = device_categorizer.cat_for_device (d.operator-> ()); if (! device_cat) { // device is ignored @@ -3294,53 +3359,71 @@ NetlistComparer::do_device_assignment (const db::Circuit *c1, const db::NetGraph continue; } - std::vector > k = compute_device_key (*d, g2, device_categorizer.is_strict_device_category (device_cat)); + const db::Device *c1_device = device_eq.other (d.operator-> ()); + size_t c1_device_cat = 0; - bool mapped = true; - for (std::vector >::iterator i = k.begin (); i != k.end (); ++i) { - if (! g2.begin () [i->second].has_other ()) { - i->second = invalid_id; // normalization - mapped = false; - } else { - i->second = g2.begin () [i->second].other_net_index (); - } - } + if (c1_device) { - std::sort (k.begin (), k.end ()); - - std::multimap >, std::pair >::iterator dm = device_map.find (k); - - if (! mapped || dm == device_map.end () || dm->first != k) { - - if (mp_logger) { - unmatched_b.push_back (std::make_pair (k, std::make_pair (d.operator-> (), device_cat))); - } - good = false; + c1_device_cat = device_categorizer.cat_for_device (c1_device); } else { + std::vector > k = compute_device_key (*d, g2, device_categorizer.is_strict_device_category (device_cat)); + + bool mapped = true; + for (std::vector >::iterator i = k.begin (); i != k.end (); ++i) { + if (! g2.begin () [i->second].has_other ()) { + i->second = invalid_id; // normalization + mapped = false; + } else { + i->second = g2.begin () [i->second].other_net_index (); + } + } + + std::sort (k.begin (), k.end ()); + + std::multimap >, std::pair >::iterator dm = device_map.find (k); + + if (! mapped || dm == device_map.end () || dm->first != k) { + + if (mp_logger) { + unmatched_b.push_back (std::make_pair (k, std::make_pair (d.operator-> (), device_cat))); + } + good = false; + + } else { + + c1_device = dm->second.first; + c1_device_cat = dm->second.second; + + device_map.erase (dm); + + } + + } + + if (c1_device) { + db::DeviceCompare dc; - if (! dc.equals (dm->second, std::make_pair (d.operator-> (), device_cat))) { - if (dm->second.second != device_cat) { + if (! dc.equals (std::make_pair (c1_device, c1_device_cat), std::make_pair (d.operator-> (), device_cat))) { + if (c1_device_cat != device_cat) { if (mp_logger) { - mp_logger->match_devices_with_different_device_classes (dm->second.first, d.operator-> ()); + mp_logger->match_devices_with_different_device_classes (c1_device, d.operator-> ()); } good = false; } else { if (mp_logger) { - mp_logger->match_devices_with_different_parameters (dm->second.first, d.operator-> ()); + mp_logger->match_devices_with_different_parameters (c1_device, d.operator-> ()); } good = false; } } else { if (mp_logger) { - mp_logger->match_devices (dm->second.first, d.operator-> ()); + mp_logger->match_devices (c1_device, d.operator-> ()); } } - device_map.erase (dm); - } } @@ -3424,7 +3507,7 @@ NetlistComparer::do_device_assignment (const db::Circuit *c1, const db::NetGraph } void -NetlistComparer::do_subcircuit_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, CircuitCategorizer &circuit_categorizer, const CircuitPinMapper &circuit_pin_mapper, std::map &c12_circuit_and_pin_mapping, std::map &c22_circuit_and_pin_mapping, bool &good) const +NetlistComparer::do_subcircuit_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, CircuitCategorizer &circuit_categorizer, const CircuitPinMapper &circuit_pin_mapper, std::map &c12_circuit_and_pin_mapping, std::map &c22_circuit_and_pin_mapping, SubCircuitEquivalenceTracker &subcircuit_eq, bool &good) const { // Report subcircuit assignment @@ -3438,6 +3521,10 @@ NetlistComparer::do_subcircuit_assignment (const db::Circuit *c1, const db::NetG continue; } + if (subcircuit_eq.other (sc.operator-> ())) { + continue; + } + std::vector > k; bool valid = compute_subcircuit_key (*sc, g1, &c12_circuit_and_pin_mapping, &circuit_pin_mapper, k); @@ -3471,75 +3558,87 @@ NetlistComparer::do_subcircuit_assignment (const db::Circuit *c1, const db::NetG continue; } - std::vector > k; - compute_subcircuit_key (*sc, g2, &c22_circuit_and_pin_mapping, &circuit_pin_mapper, k); + const db::SubCircuit *c1_subcircuit = subcircuit_eq.other (sc.operator-> ()); - bool mapped = true; - for (std::vector >::iterator i = k.begin (); i != k.end (); ++i) { - if (! g2.begin () [i->second].has_other ()) { - mapped = false; - } else { - i->second = g2.begin () [i->second].other_net_index (); - } - } - - std::sort (k.begin (), k.end ()); - - std::multimap >, std::pair >::iterator scm = subcircuit_map.find (k); - - if (! mapped || scm == subcircuit_map.end ()) { + if (c1_subcircuit) { if (mp_logger) { - unmatched_b.push_back (std::make_pair (k, sc.operator-> ())); + mp_logger->match_subcircuits (c1_subcircuit, sc.operator-> ()); } - good = false; } else { - db::SubCircuitCompare scc; + std::vector > k; + compute_subcircuit_key (*sc, g2, &c22_circuit_and_pin_mapping, &circuit_pin_mapper, k); - std::multimap >, std::pair >::iterator scm_start = scm; - - bool found = false; - size_t nscm = 0; - while (! found && scm != subcircuit_map.end () && scm->first == k) { - ++nscm; - if (scc.equals (scm->second, std::make_pair (sc.operator-> (), sc_cat))) { - found = true; + bool mapped = true; + for (std::vector >::iterator i = k.begin (); i != k.end (); ++i) { + if (! g2.begin () [i->second].has_other ()) { + mapped = false; + } else { + i->second = g2.begin () [i->second].other_net_index (); } } - if (! found) { + std::sort (k.begin (), k.end ()); - if (nscm == 1) { + std::multimap >, std::pair >::iterator scm = subcircuit_map.find (k); - // unique match, but doesn't fit: report this one as paired, but mismatching: - if (mp_logger) { - mp_logger->subcircuit_mismatch (scm_start->second.first, sc.operator-> ()); - } - - // no longer look for this one - subcircuit_map.erase (scm_start); - - } else { - - // no unqiue match - if (mp_logger) { - mp_logger->subcircuit_mismatch (0, sc.operator-> ()); - } + if (! mapped || scm == subcircuit_map.end ()) { + if (mp_logger) { + unmatched_b.push_back (std::make_pair (k, sc.operator-> ())); } - good = false; } else { - if (mp_logger) { - mp_logger->match_subcircuits (scm->second.first, sc.operator-> ()); + db::SubCircuitCompare scc; + + std::multimap >, std::pair >::iterator scm_start = scm; + + bool found = false; + size_t nscm = 0; + while (! found && scm != subcircuit_map.end () && scm->first == k) { + ++nscm; + if (scc.equals (scm->second, std::make_pair (sc.operator-> (), sc_cat))) { + found = true; + } } - // no longer look for this one - subcircuit_map.erase (scm); + if (! found) { + + if (nscm == 1) { + + // unique match, but doesn't fit: report this one as paired, but mismatching: + if (mp_logger) { + mp_logger->subcircuit_mismatch (scm_start->second.first, sc.operator-> ()); + } + + // no longer look for this one + subcircuit_map.erase (scm_start); + + } else { + + // no unqiue match + if (mp_logger) { + mp_logger->subcircuit_mismatch (0, sc.operator-> ()); + } + + } + + good = false; + + } else { + + if (mp_logger) { + mp_logger->match_subcircuits (scm->second.first, sc.operator-> ()); + } + + // no longer look for this one + subcircuit_map.erase (scm); + + } } diff --git a/src/db/db/dbNetlistCompare.h b/src/db/db/dbNetlistCompare.h index d639ed12f..d9748d36d 100644 --- a/src/db/db/dbNetlistCompare.h +++ b/src/db/db/dbNetlistCompare.h @@ -38,6 +38,8 @@ class DeviceCategorizer; class CircuitCategorizer; class CircuitMapper; class NetGraph; +class SubCircuitEquivalenceTracker; +class DeviceEquivalenceTracker; /** * @brief A receiver for netlist compare events @@ -326,8 +328,8 @@ protected: bool all_subcircuits_verified (const db::Circuit *c, const std::set &verified_circuits) const; static void derive_pin_equivalence (const db::Circuit *ca, const db::Circuit *cb, CircuitPinMapper *circuit_pin_mapper); void do_pin_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, std::map &c12_circuit_and_pin_mapping, std::map &c22_circuit_and_pin_mapping, bool &pin_mismatch, bool &good) const; - void do_device_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, const db::DeviceFilter &device_filter, DeviceCategorizer &device_categorizer, bool &good) const; - void do_subcircuit_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, CircuitCategorizer &circuit_categorizer, const db::CircuitPinMapper &circuit_pin_mapper, std::map &c12_circuit_and_pin_mapping, std::map &c22_circuit_and_pin_mapping, bool &good) const; + void do_device_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, const db::DeviceFilter &device_filter, DeviceCategorizer &device_categorizer, db::DeviceEquivalenceTracker &device_eq, bool &good) const; + void do_subcircuit_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, CircuitCategorizer &circuit_categorizer, const db::CircuitPinMapper &circuit_pin_mapper, std::map &c12_circuit_and_pin_mapping, std::map &c22_circuit_and_pin_mapping, db::SubCircuitEquivalenceTracker &subcircuit_eq, bool &good) const; bool handle_pin_mismatch (const NetGraph &g1, const db::Circuit *c1, const db::Pin *pin1, const NetGraph &g2, const db::Circuit *c2, const db::Pin *p2) const; mutable NetlistCompareLogger *mp_logger; From 783f3e08df4a51ac3d25690f5b2f61c84348db4b Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 23 Jun 2020 00:51:52 +0200 Subject: [PATCH 4/7] Enhanced ambiguity resolution in netlist compare The solution consists of considering device and subcircuit equivalences during the evaluation of the node equivalence. This will block certain paths and help resolving ambiguities without creating contradictions. --- src/db/db/dbNetlistCompare.cc | 255 ++++++++++++++++++++++++++++++++-- 1 file changed, 243 insertions(+), 12 deletions(-) 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) { From 2399833271b44c2b77622bddb41598967fe91f17 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 23 Jun 2020 21:36:32 +0200 Subject: [PATCH 5/7] WIP: enhancement of the net compare algorithm. --- testdata/lvs/ringo_simple_dmos.lvsdb.2 | 912 ------------------------- 1 file changed, 912 deletions(-) delete mode 100644 testdata/lvs/ringo_simple_dmos.lvsdb.2 diff --git a/testdata/lvs/ringo_simple_dmos.lvsdb.2 b/testdata/lvs/ringo_simple_dmos.lvsdb.2 deleted file mode 100644 index 45fc263a5..000000000 --- a/testdata/lvs/ringo_simple_dmos.lvsdb.2 +++ /dev/null @@ -1,912 +0,0 @@ -#%lvsdb-klayout - -# Layout -layout( - top(RINGO) - unit(0.001) - - # Layer section - # This section lists the mask layers (drawing or derived) and their connections. - - # Mask layers - layer(l4 '1/0') - layer(l5 '5/0') - layer(l10 '8/0') - layer(l13 '9/0') - layer(l14 '10/0') - layer(l15 '11/0') - layer(l9) - layer(l3) - layer(l1) - layer(l11) - layer(l8) - layer(l6) - layer(l12) - - # Mask layer connectivity - connect(l4 l4 l11) - connect(l5 l5 l10) - connect(l10 l5 l10 l13 l3 l1 l11 l8 l6 l12) - connect(l13 l10 l13 l14) - connect(l14 l13 l14 l15) - connect(l15 l14 l15) - connect(l9 l9) - connect(l3 l10 l3) - connect(l1 l10 l1) - connect(l11 l4 l10 l11) - connect(l8 l10 l8) - connect(l6 l10 l6) - connect(l12 l10 l12) - - # Global nets and connectivity - global(l9 SUBSTRATE) - global(l12 SUBSTRATE) - - # Device class section - class(PMOS MOS4) - class(NMOS MOS4) - - # Device abstracts section - # Device abstracts list the pin shapes of the devices. - device(D$PMOS PMOS - terminal(S - rect(l3 (125 -750) (450 1500)) - ) - terminal(G - rect(l5 (-125 -750) (250 1500)) - ) - terminal(D - rect(l1 (-550 -750) (425 1500)) - ) - terminal(B - rect(l4 (-125 -750) (250 1500)) - ) - ) - device(D$PMOS$1 PMOS - terminal(S - rect(l3 (-575 -750) (450 1500)) - ) - terminal(G - rect(l5 (-125 -750) (250 1500)) - ) - terminal(D - rect(l1 (125 -750) (425 1500)) - ) - terminal(B - rect(l4 (-125 -750) (250 1500)) - ) - ) - device(D$PMOS$2 PMOS - terminal(S - rect(l3 (-550 -750) (425 1500)) - ) - terminal(G - rect(l5 (-125 -750) (250 1500)) - ) - terminal(D - rect(l1 (125 -750) (425 1500)) - ) - terminal(B - rect(l4 (-125 -750) (250 1500)) - ) - ) - device(D$NMOS NMOS - terminal(S - rect(l8 (125 -475) (450 950)) - ) - terminal(G - rect(l5 (-125 -475) (250 950)) - ) - terminal(D - rect(l6 (-550 -475) (425 950)) - ) - terminal(B - rect(l9 (-125 -475) (250 950)) - ) - ) - device(D$NMOS$1 NMOS - terminal(S - rect(l8 (-575 -475) (450 950)) - ) - terminal(G - rect(l5 (-125 -475) (250 950)) - ) - terminal(D - rect(l6 (125 -475) (425 950)) - ) - terminal(B - rect(l9 (-125 -475) (250 950)) - ) - ) - device(D$NMOS$2 NMOS - terminal(S - rect(l8 (-550 -475) (425 950)) - ) - terminal(G - rect(l5 (-125 -475) (250 950)) - ) - terminal(D - rect(l6 (125 -475) (425 950)) - ) - terminal(B - rect(l9 (-125 -475) (250 950)) - ) - ) - - # Circuit section - # Circuits are the hierarchical building blocks of the netlist. - circuit(ND2X1 - - # Circuit boundary - rect((-100 400) (2600 7600)) - - # Nets with their geometries - net(1 name(VDD) - rect(l10 (1110 5160) (180 180)) - rect(l10 (-180 920) (180 180)) - rect(l10 (-180 -730) (180 180)) - rect(l13 (-240 -790) (300 1700)) - rect(l13 (-1350 0) (2400 800)) - rect(l13 (-1151 -401) (2 2)) - rect(l3 (-251 -2151) (425 1500)) - rect(l3 (-450 -1500) (425 1500)) - ) - net(2 name(OUT) - rect(l10 (1810 1770) (180 180)) - rect(l10 (-180 370) (180 180)) - rect(l10 (-1580 3760) (180 180)) - rect(l10 (-180 -730) (180 180)) - rect(l10 (-180 -730) (180 180)) - rect(l10 (1220 920) (180 180)) - rect(l10 (-180 -1280) (180 180)) - rect(l10 (-180 370) (180 180)) - polygon(l13 (-240 -4180) (0 1390) (490 0) (0 -300) (-190 0) (0 -1090)) - rect(l13 (-110 1390) (300 1400)) - polygon(l13 (-1890 0) (0 600) (300 0) (0 -300) (1590 0) (0 -300)) - rect(l13 (-141 -501) (2 2)) - rect(l13 (-1751 1099) (300 1400)) - rect(l13 (1100 -1700) (300 300)) - rect(l13 (-300 0) (300 1400)) - rect(l1 (-1750 -1450) (425 1500)) - rect(l1 (950 -1500) (425 1500)) - rect(l6 (-425 -4890) (425 950)) - ) - net(3 name(VSS) - rect(l10 (410 1770) (180 180)) - rect(l10 (-180 370) (180 180)) - rect(l13 (-240 -1300) (300 1360)) - rect(l13 (-650 -2160) (2400 800)) - rect(l13 (-1151 -401) (2 2)) - rect(l6 (-951 859) (425 950)) - ) - net(4 - rect(l8 (1000 1660) (425 950)) - rect(l8 (-450 -950) (425 950)) - ) - net(5 - rect(l4 (-100 4500) (2600 3500)) - ) - net(6 name(B) - rect(l5 (1425 2860) (250 1940)) - rect(l5 (-345 -950) (300 300)) - rect(l5 (-205 650) (250 2000)) - rect(l5 (-250 -2000) (250 2000)) - rect(l5 (-250 -5390) (250 1450)) - rect(l10 (-285 1050) (180 180)) - rect(l13 (-71 -91) (2 2)) - rect(l13 (-171 -151) (300 300)) - ) - net(7 name(A) - rect(l5 (725 2860) (250 1940)) - rect(l5 (-325 -1850) (300 300)) - rect(l5 (-225 1550) (250 2000)) - rect(l5 (-250 -2000) (250 2000)) - rect(l5 (-250 -5390) (250 1450)) - rect(l10 (-265 150) (180 180)) - rect(l13 (-91 -91) (2 2)) - rect(l13 (-151 -151) (300 300)) - ) - net(8 name(SUBSTRATE)) - - # Outgoing pins and their connections to nets - pin(1 name(VDD)) - pin(2 name(OUT)) - pin(3 name(VSS)) - pin(5) - pin(6 name(B)) - pin(7 name(A)) - pin(8 name(SUBSTRATE)) - - # Devices and their connections - device(1 D$PMOS - location(850 5800) - param(L 0.25) - param(W 1.5) - param(AS 0.3375) - param(AD 0.6375) - param(PS 1.95) - param(PD 3.85) - terminal(S 1) - terminal(G 7) - terminal(D 2) - terminal(B 5) - ) - device(2 D$PMOS$1 - location(1550 5800) - param(L 0.25) - param(W 1.5) - param(AS 0.3375) - param(AD 0.6375) - param(PS 1.95) - param(PD 3.85) - terminal(S 1) - terminal(G 6) - terminal(D 2) - terminal(B 5) - ) - device(3 D$NMOS - location(850 2135) - param(L 0.25) - param(W 0.95) - param(AS 0.21375) - param(AD 0.40375) - param(PS 1.4) - param(PD 2.75) - terminal(S 4) - terminal(G 7) - terminal(D 3) - terminal(B 8) - ) - device(4 D$NMOS$1 - location(1550 2135) - param(L 0.25) - param(W 0.95) - param(AS 0.21375) - param(AD 0.40375) - param(PS 1.4) - param(PD 2.75) - terminal(S 4) - terminal(G 6) - terminal(D 2) - terminal(B 8) - ) - - ) - circuit(INVX1 - - # Circuit boundary - rect((-100 400) (2000 7600)) - - # Nets with their geometries - net(1 name(VDD) - rect(l10 (410 6260) (180 180)) - rect(l10 (-180 -730) (180 180)) - rect(l10 (-180 -730) (180 180)) - rect(l13 (-240 -240) (300 1400)) - rect(l13 (-650 300) (1800 800)) - rect(l13 (-1450 -1100) (300 300)) - rect(l13 (299 399) (2 2)) - rect(l3 (-651 -2151) (425 1500)) - ) - net(2 name(OUT) - rect(l10 (1110 5160) (180 180)) - rect(l10 (-180 920) (180 180)) - rect(l10 (-180 -730) (180 180)) - rect(l10 (-180 -4120) (180 180)) - rect(l10 (-180 370) (180 180)) - rect(l13 (-240 -790) (300 4790)) - rect(l13 (-151 -2501) (2 2)) - rect(l1 (-226 1049) (425 1500)) - rect(l6 (-425 -4890) (425 950)) - ) - net(3 name(VSS) - rect(l10 (410 1770) (180 180)) - rect(l10 (-180 370) (180 180)) - rect(l13 (-240 -1300) (300 1360)) - rect(l13 (-650 -2160) (1800 800)) - rect(l13 (-851 -401) (2 2)) - rect(l8 (-651 859) (425 950)) - ) - net(4 - rect(l4 (-100 4500) (2000 3500)) - ) - net(5 name(IN) - rect(l5 (725 2860) (250 1940)) - rect(l5 (-525 -1850) (300 300)) - rect(l5 (-25 1550) (250 2000)) - rect(l5 (-250 -2000) (250 2000)) - rect(l5 (-250 -5390) (250 1450)) - rect(l10 (-465 150) (180 180)) - rect(l13 (-91 -91) (2 2)) - rect(l13 (-151 -151) (300 300)) - ) - net(6 name(SUBSTRATE)) - - # Outgoing pins and their connections to nets - pin(1 name(VDD)) - pin(2 name(OUT)) - pin(3 name(VSS)) - pin(4) - pin(5 name(IN)) - pin(6 name(SUBSTRATE)) - - # Devices and their connections - device(1 D$PMOS$2 - location(850 5800) - param(L 0.25) - param(W 1.5) - param(AS 0.6375) - param(AD 0.6375) - param(PS 3.85) - param(PD 3.85) - terminal(S 1) - terminal(G 5) - terminal(D 2) - terminal(B 4) - ) - device(2 D$NMOS$2 - location(850 2135) - param(L 0.25) - param(W 0.95) - param(AS 0.40375) - param(AD 0.40375) - param(PS 2.75) - param(PD 2.75) - terminal(S 3) - terminal(G 5) - terminal(D 2) - terminal(B 6) - ) - - ) - circuit(RINGO - - # Circuit boundary - rect((0 350) (25800 7650)) - - # Nets with their geometries - net(1 - rect(l13 (4040 2950) (610 300)) - ) - net(2 - rect(l13 (5550 2950) (900 300)) - ) - net(3 - rect(l13 (7350 2950) (900 300)) - ) - net(4 - rect(l13 (9150 2950) (900 300)) - ) - net(5 - rect(l13 (10950 2950) (900 300)) - ) - net(6 - rect(l13 (12750 2950) (900 300)) - ) - net(7 - rect(l13 (14550 2950) (900 300)) - ) - net(8 - rect(l13 (16350 2950) (900 300)) - ) - net(9 - rect(l13 (18150 2950) (900 300)) - ) - net(10 - rect(l13 (19950 2950) (900 300)) - ) - net(11 name(FB) - rect(l13 (21750 2950) (900 300)) - rect(l13 (-19530 590) (320 320)) - rect(l13 (17820 -320) (320 320)) - rect(l14 (-18400 -260) (200 200)) - rect(l14 (17940 -200) (200 200)) - rect(l15 (-18040 -300) (17740 400)) - rect(l15 (-17921 -201) (2 2)) - rect(l15 (-221 -201) (400 400)) - rect(l15 (17740 -400) (400 400)) - ) - net(12 name(VDD) - rect(l4 (500 4500) (1400 3500)) - rect(l4 (-1900 -3500) (600 3500)) - rect(l4 (23300 -3500) (1400 3500)) - rect(l4 (-100 -3500) (600 3500)) - rect(l10 (-24690 -1240) (180 180)) - rect(l10 (-180 370) (180 180)) - rect(l10 (-180 -1280) (180 180)) - rect(l10 (23220 370) (180 180)) - rect(l10 (-180 370) (180 180)) - rect(l10 (-180 -1280) (180 180)) - rect(l13 (-21741 859) (2 2)) - rect(l13 (-2351 -451) (1200 800)) - rect(l13 (-750 -1450) (300 1400)) - rect(l13 (-101 -351) (2 2)) - rect(l13 (-1251 -401) (600 800)) - rect(l13 (23400 -800) (1200 800)) - rect(l13 (-750 -1450) (300 1400)) - rect(l13 (-101 -351) (2 2)) - rect(l13 (549 -401) (600 800)) - rect(l11 (-24850 -1500) (500 1500)) - rect(l11 (22900 -1500) (500 1500)) - ) - net(13 name(OUT) - rect(l13 (23440 3840) (320 320)) - rect(l14 (-260 -260) (200 200)) - rect(l15 (-101 -101) (2 2)) - rect(l15 (-201 -201) (400 400)) - ) - net(14 name(ENABLE) - rect(l13 (2440 2940) (320 320)) - rect(l14 (-260 -260) (200 200)) - rect(l15 (-101 -101) (2 2)) - rect(l15 (-201 -201) (400 400)) - ) - net(15 name(VSS) - rect(l10 (1110 1610) (180 180)) - rect(l10 (-180 -1280) (180 180)) - rect(l10 (-180 370) (180 180)) - rect(l10 (23220 370) (180 180)) - rect(l10 (-180 -1280) (180 180)) - rect(l10 (-180 370) (180 180)) - rect(l13 (-21741 -391) (2 2)) - rect(l13 (-1901 -401) (300 1400)) - rect(l13 (-750 -1450) (1200 800)) - rect(l13 (-551 -401) (2 2)) - rect(l13 (-1251 -401) (600 800)) - rect(l13 (23850 -750) (300 1400)) - rect(l13 (-750 -1450) (1200 800)) - rect(l13 (-551 -401) (2 2)) - rect(l13 (549 -401) (600 800)) - rect(l12 (-24850 -800) (500 1500)) - rect(l12 (22900 -1500) (500 1500)) - ) - - # Outgoing pins and their connections to nets - pin(11 name(FB)) - pin(12 name(VDD)) - pin(13 name(OUT)) - pin(14 name(ENABLE)) - pin(15 name(VSS)) - - # Subcircuits and their connections - circuit(1 ND2X1 location(1800 0) - pin(0 12) - pin(1 1) - pin(2 15) - pin(3 12) - pin(4 11) - pin(5 14) - pin(6 15) - ) - circuit(2 INVX1 location(4200 0) - pin(0 12) - pin(1 2) - pin(2 15) - pin(3 12) - pin(4 1) - pin(5 15) - ) - circuit(3 INVX1 location(6000 0) - pin(0 12) - pin(1 3) - pin(2 15) - pin(3 12) - pin(4 2) - pin(5 15) - ) - circuit(4 INVX1 location(7800 0) - pin(0 12) - pin(1 4) - pin(2 15) - pin(3 12) - pin(4 3) - pin(5 15) - ) - circuit(5 INVX1 location(9600 0) - pin(0 12) - pin(1 5) - pin(2 15) - pin(3 12) - pin(4 4) - pin(5 15) - ) - circuit(6 INVX1 location(11400 0) - pin(0 12) - pin(1 6) - pin(2 15) - pin(3 12) - pin(4 5) - pin(5 15) - ) - circuit(7 INVX1 location(13200 0) - pin(0 12) - pin(1 7) - pin(2 15) - pin(3 12) - pin(4 6) - pin(5 15) - ) - circuit(8 INVX1 location(15000 0) - pin(0 12) - pin(1 8) - pin(2 15) - pin(3 12) - pin(4 7) - pin(5 15) - ) - circuit(9 INVX1 location(16800 0) - pin(0 12) - pin(1 9) - pin(2 15) - pin(3 12) - pin(4 8) - pin(5 15) - ) - circuit(10 INVX1 location(18600 0) - pin(0 12) - pin(1 10) - pin(2 15) - pin(3 12) - pin(4 9) - pin(5 15) - ) - circuit(11 INVX1 location(20400 0) - pin(0 12) - pin(1 11) - pin(2 15) - pin(3 12) - pin(4 10) - pin(5 15) - ) - circuit(12 INVX1 location(22200 0) - pin(0 12) - pin(1 13) - pin(2 15) - pin(3 12) - pin(4 11) - pin(5 15) - ) - - ) -) - -# Reference netlist -reference( - - # Device class section - class(PMOS MOS4) - class(NMOS MOS4) - - # Circuit section - # Circuits are the hierarchical building blocks of the netlist. - circuit(ND2X1 - - # Nets - net(1 name(VDD)) - net(2 name(OUT)) - net(3 name(VSS)) - net(4 name(NWELL)) - net(5 name(B)) - net(6 name(A)) - net(7 name(BULK)) - net(8 name('1')) - - # Outgoing pins and their connections to nets - pin(1 name(VDD)) - pin(2 name(OUT)) - pin(3 name(VSS)) - pin(4 name(NWELL)) - pin(5 name(B)) - pin(6 name(A)) - pin(7 name(BULK)) - - # Devices and their connections - device(1 PMOS - name($1) - param(L 0.25) - param(W 1.5) - param(AS 0) - param(AD 0) - param(PS 0) - param(PD 0) - terminal(S 2) - terminal(G 6) - terminal(D 1) - terminal(B 4) - ) - device(2 PMOS - name($2) - param(L 0.25) - param(W 1.5) - param(AS 0) - param(AD 0) - param(PS 0) - param(PD 0) - terminal(S 1) - terminal(G 5) - terminal(D 2) - terminal(B 4) - ) - device(3 NMOS - name($3) - param(L 0.25) - param(W 0.95) - param(AS 0) - param(AD 0) - param(PS 0) - param(PD 0) - terminal(S 3) - terminal(G 6) - terminal(D 8) - terminal(B 7) - ) - device(4 NMOS - name($4) - param(L 0.25) - param(W 0.95) - param(AS 0) - param(AD 0) - param(PS 0) - param(PD 0) - terminal(S 8) - terminal(G 5) - terminal(D 2) - terminal(B 7) - ) - - ) - circuit(INVX1 - - # Nets - net(1 name(VDD)) - net(2 name(OUT)) - net(3 name(VSS)) - net(4 name(NWELL)) - net(5 name(IN)) - net(6 name(BULK)) - - # Outgoing pins and their connections to nets - pin(1 name(VDD)) - pin(2 name(OUT)) - pin(3 name(VSS)) - pin(4 name(NWELL)) - pin(5 name(IN)) - pin(6 name(BULK)) - - # Devices and their connections - device(1 PMOS - name($1) - param(L 0.25) - param(W 1.5) - param(AS 0) - param(AD 0) - param(PS 0) - param(PD 0) - terminal(S 1) - terminal(G 5) - terminal(D 2) - terminal(B 4) - ) - device(2 NMOS - name($2) - param(L 0.25) - param(W 0.95) - param(AS 0) - param(AD 0) - param(PS 0) - param(PD 0) - terminal(S 3) - terminal(G 5) - terminal(D 2) - terminal(B 6) - ) - - ) - circuit(RINGO - - # Nets - net(1 name(VSS)) - net(2 name(VDD)) - net(3 name(FB)) - net(4 name(ENABLE)) - net(5 name(OUT)) - net(6 name('1')) - net(7 name('2')) - net(8 name('3')) - net(9 name('4')) - net(10 name('5')) - net(11 name('6')) - net(12 name('7')) - net(13 name('8')) - net(14 name('9')) - net(15 name('10')) - - # Outgoing pins and their connections to nets - pin(1 name(VSS)) - pin(2 name(VDD)) - pin(3 name(FB)) - pin(4 name(ENABLE)) - pin(5 name(OUT)) - - # Subcircuits and their connections - circuit(1 ND2X1 name($1) - pin(0 2) - pin(1 6) - pin(2 1) - pin(3 2) - pin(4 3) - pin(5 4) - pin(6 1) - ) - circuit(2 INVX1 name($2) - pin(0 2) - pin(1 7) - pin(2 1) - pin(3 2) - pin(4 6) - pin(5 1) - ) - circuit(3 INVX1 name($3) - pin(0 2) - pin(1 8) - pin(2 1) - pin(3 2) - pin(4 7) - pin(5 1) - ) - circuit(4 INVX1 name($4) - pin(0 2) - pin(1 9) - pin(2 1) - pin(3 2) - pin(4 8) - pin(5 1) - ) - circuit(5 INVX1 name($5) - pin(0 2) - pin(1 10) - pin(2 1) - pin(3 2) - pin(4 9) - pin(5 1) - ) - circuit(6 INVX1 name($6) - pin(0 2) - pin(1 11) - pin(2 1) - pin(3 2) - pin(4 10) - pin(5 1) - ) - circuit(7 INVX1 name($7) - pin(0 2) - pin(1 12) - pin(2 1) - pin(3 2) - pin(4 11) - pin(5 1) - ) - circuit(8 INVX1 name($8) - pin(0 2) - pin(1 13) - pin(2 1) - pin(3 2) - pin(4 12) - pin(5 1) - ) - circuit(9 INVX1 name($9) - pin(0 2) - pin(1 14) - pin(2 1) - pin(3 2) - pin(4 13) - pin(5 1) - ) - circuit(10 INVX1 name($10) - pin(0 2) - pin(1 15) - pin(2 1) - pin(3 2) - pin(4 14) - pin(5 1) - ) - circuit(11 INVX1 name($11) - pin(0 2) - pin(1 3) - pin(2 1) - pin(3 2) - pin(4 15) - pin(5 1) - ) - circuit(12 INVX1 name($12) - pin(0 2) - pin(1 5) - pin(2 1) - pin(3 2) - pin(4 3) - pin(5 1) - ) - - ) -) - -# Cross reference -xref( - circuit(INVX1 INVX1 match - xref( - net(4 4 match) - net(5 5 match) - net(2 2 match) - net(6 6 match) - net(1 1 match) - net(3 3 match) - pin(3 3 match) - pin(4 4 match) - pin(1 1 match) - pin(5 5 match) - pin(0 0 match) - pin(2 2 match) - device(2 2 match) - device(1 1 match) - ) - ) - circuit(ND2X1 ND2X1 nomatch - xref( - net(4 8 mismatch) - net(5 4 mismatch) - net(7 6 match) - net(6 5 match) - net(2 2 mismatch) - net(8 7 mismatch) - net(1 1 mismatch) - net(3 3 mismatch) - pin(3 3 match) - pin(5 5 match) - pin(4 4 match) - pin(1 1 match) - pin(6 6 match) - pin(0 0 match) - pin(2 2 match) - device(4 4 match) - device(3 3 mismatch) - device(2 2 match) - device(1 1 mismatch) - ) - ) - circuit(RINGO RINGO match - xref( - net(1 6 match) - net(10 15 match) - net(2 7 match) - net(3 8 match) - net(4 9 match) - net(5 10 match) - net(6 11 match) - net(7 12 match) - net(8 13 match) - net(9 14 match) - net(14 4 match) - net(11 3 match) - net(13 5 match) - net(12 2 match) - net(15 1 match) - pin(3 3 match) - pin(0 2 match) - pin(2 4 match) - pin(1 1 match) - pin(4 0 match) - circuit(2 2 match) - circuit(3 3 match) - circuit(4 4 match) - circuit(5 5 match) - circuit(6 6 match) - circuit(7 7 match) - circuit(8 8 match) - circuit(9 9 match) - circuit(10 10 match) - circuit(11 11 match) - circuit(12 12 match) - circuit(1 1 match) - ) - ) -) From 5cb1f63c632ec7ad97eb10c1d7d292c98badffd1 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 23 Jun 2020 21:56:04 +0200 Subject: [PATCH 6/7] Updated testdata --- src/db/db/dbNetlistCompare.cc | 334 ++++++++++++--------- src/db/unit_tests/dbNetlistCompareTests.cc | 6 +- testdata/lvs/ringo_simple_dmos.lvsdb.1 | 6 +- 3 files changed, 200 insertions(+), 146 deletions(-) diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc index 579c6700a..a7547e73d 100644 --- a/src/db/db/dbNetlistCompare.cc +++ b/src/db/db/dbNetlistCompare.cc @@ -952,9 +952,9 @@ namespace db struct CompareNodePtr { - bool operator() (const NetGraphNode *a, const NetGraphNode *b) const + bool operator() (const std::pair &a, const std::pair &b) const { - return *a < *b; + return *a.first < *b.first; } }; @@ -1117,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 (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); + 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); private: std::vector m_nodes; @@ -1490,7 +1490,8 @@ NetGraphNode::edge_equal (const db::Net *a, const db::Net *b) */ struct NodeRange { - NodeRange (size_t _num, std::vector::iterator _n1, std::vector::iterator _nn1, std::vector::iterator _n2, std::vector::iterator _nn2) + NodeRange (size_t _num, std::vector >::iterator _n1, std::vector >::iterator _nn1, + std::vector >::iterator _n2, std::vector >::iterator _nn2) : num (_num), n1 (_n1), nn1 (_nn1), n2 (_n2), nn2 (_nn2) { // .. nothing yet .. @@ -1502,7 +1503,7 @@ struct NodeRange } size_t num; - std::vector::iterator n1, nn1, n2, nn2; + std::vector >::iterator n1, nn1, n2, nn2; }; // -------------------------------------------------------------------------------------------------------------------- @@ -1644,33 +1645,47 @@ 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) +static bool edges_are_compatible (const NetGraphNode::edge_type &e, const NetGraphNode::edge_type &e_other, const DeviceEquivalenceTracker &device_eq, const SubCircuitEquivalenceTracker &sc_eq) { - while (t != tt && t_other != tt_other) { + std::vector::const_iterator t1 = e.first.begin (), tt1 = e.first.end (); + std::vector::const_iterator t2 = e_other.first.begin (), tt2 = e_other.first.end (); - tl_assert (*t == *t_other); + std::vector p1, p2; - if (t->is_for_subcircuit ()) { + while (t1 != tt1 && t2 != tt2) { - const db::SubCircuit *other = sc_eq.other (t->subcircuit_pair ().first); - if (other && other != t_other->subcircuit_pair ().first) { - return false; + std::vector::const_iterator t10 = t1, t20 = t2; + + p1.clear (); + while (t1 != tt1 && *t1 == *t10) { + if (t1->is_for_subcircuit ()) { + p1.push_back ((void *) sc_eq.other (t1->subcircuit_pair ().first)); + } else { + p1.push_back ((void *) device_eq.other (t1->device_pair ().first)); } - - } else { - - const db::Device *other = device_eq.other (t->device_pair ().first); - if (other && other != t_other->device_pair ().first) { - return false; - } - + ++t1; } - ++t; - ++t_other; + p2.clear (); + while (t2 != tt2 && *t2 == *t20) { + if (t2->is_for_subcircuit ()) { + p2.push_back ((void *) (sc_eq.other (t2->subcircuit_pair ().first) ? t2->subcircuit_pair ().first : 0)); + } else { + p2.push_back ((void *) (device_eq.other (t2->device_pair ().first) ? t2->device_pair ().first : 0)); + } + ++t2; + } + + std::sort (p1.begin (), p1.end ()); + std::sort (p2.begin (), p2.end ()); + + if (p1 != p2) { + return false; + } } + tl_assert (t1 == tt1 && t2 == tt2); return true; } @@ -1679,10 +1694,10 @@ NetGraph::derive_node_identities_for_edges (NetGraphNode::edge_iterator e, NetGr { size_t new_nodes = 0; - std::vector nodes; + std::vector > nodes; nodes.reserve (ee - e); - std::vector other_nodes; + std::vector > other_nodes; other_nodes.reserve (ee - e); tl_assert (e->first == e_other->first); @@ -1707,19 +1722,10 @@ NetGraph::derive_node_identities_for_edges (NetGraphNode::edge_iterator e, NetGr } tl::info << ""; } - nodes.push_back (nn); + nodes.push_back (std::make_pair (nn, i)); } } - // 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; @@ -1738,7 +1744,7 @@ NetGraph::derive_node_identities_for_edges (NetGraphNode::edge_iterator e, NetGr } tl::info << ""; } - other_nodes.push_back (nn); + other_nodes.push_back (std::make_pair (nn, i)); } } @@ -1763,7 +1769,7 @@ NetGraph::derive_node_identities_for_edges (NetGraphNode::edge_iterator e, NetGr // 1:1 pairing is less strict if (nodes.size () > 1 || other_nodes.size () > 1) { for (size_t i = 0; i < nodes.size (); ++i) { - if (! (*nodes[i] == *other_nodes[i])) { + if (! (*nodes[i].first == *other_nodes[i].first)) { if (options ()->debug_netcompare) { tl::info << indent(depth) << "=> rejected branch."; } @@ -1777,7 +1783,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 (e, ee, e_other, ee_other, nodes, other_nodes, depth, n_branch, tentative, with_ambiguous, data); + size_t bt_count = derive_node_identities_from_node_set (nodes, other_nodes, depth, n_branch, tentative, with_ambiguous, data); if (bt_count == failed_match) { if (tentative) { @@ -1934,10 +1940,10 @@ namespace { struct SortNodeByNet { public: - bool operator() (const NetGraphNode *a, const NetGraphNode *b) const + bool operator() (const std::pair &a, const std::pairb) const { - tl_assert (a->net () && b->net ()); - return name_compare (a->net ()->name (), b->net ()->name ()) < 0; + tl_assert (a.first->net () && b.first->net ()); + return name_compare (a.first->net ()->name (), b.first->net ()->name ()) < 0; } }; @@ -1948,12 +1954,12 @@ static void sort_node_range_by_best_match (NodeRange &nr) std::stable_sort (nr.n1, nr.nn1, SortNodeByNet ()); std::stable_sort (nr.n2, nr.nn2, SortNodeByNet ()); - std::vector nomatch1, nomatch2; + std::vector > nomatch1, nomatch2; nomatch1.reserve (nr.nn1 - nr.n1); nomatch2.reserve (nr.nn2 - nr.n2); - std::vector::const_iterator i = nr.n1, j = nr.n2; - std::vector::iterator iw = nr.n1, jw = nr.n2; + std::vector >::const_iterator i = nr.n1, j = nr.n2; + std::vector >::iterator iw = nr.n1, jw = nr.n2; SortNodeByNet compare; @@ -2034,16 +2040,16 @@ public: }; template -static std::string log_text_for_equivalence (); +inline std::string log_text_for_equivalence (); template <> -static std::string log_text_for_equivalence () +inline std::string log_text_for_equivalence () { return "enforcing device equivalence"; } template <> -static std::string log_text_for_equivalence () +inline std::string log_text_for_equivalence () { return "enforcing subcircuit equivalence"; } @@ -2125,16 +2131,24 @@ class DeviceMapperForTargetNode : public generic_mapper_for_target_node { public: - DeviceMapperForTargetNode (NetGraphNode::edge_iterator e, NetGraphNode::edge_iterator ee) + DeviceMapperForTargetNode () : 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)); - } + // .. nothing yet .. + } + + void insert (const NetGraphNode::edge_type &e) + { + if (e.first.empty ()) { + // happens initially + return; + } + + size_t ni = e.second.first; + std::set > &dev = for_node_nc (ni); + for (std::vector::const_iterator j = e.first.begin (); j != e.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)); } } } @@ -2144,16 +2158,24 @@ class SubCircuitMapperForTargetNode : public generic_mapper_for_target_node { public: - SubCircuitMapperForTargetNode (NetGraphNode::edge_iterator e, NetGraphNode::edge_iterator ee) + SubCircuitMapperForTargetNode () : 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)); - } + // .. nothing yet .. + } + + void insert (const NetGraphNode::edge_type &e) + { + if (e.first.empty ()) { + // happens initially + return; + } + + size_t ni = e.second.first; + std::set > &sc = for_node_nc (ni); + for (std::vector::const_iterator j = e.first.begin (); j != e.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)); } } } @@ -2162,7 +2184,7 @@ public: } size_t -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) +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) { std::string indent_s; if (options ()->debug_netcompare) { @@ -2179,21 +2201,41 @@ NetGraph::derive_node_identities_from_node_set (NetGraphNode::edge_iterator e, N return failed_match; } - DeviceMapperForTargetNode dm (e, ee); - DeviceMapperForTargetNode dm_other (e_other, ee_other); + DeviceMapperForTargetNode dm; + SubCircuitMapperForTargetNode scm; + for (std::vector >::const_iterator i = nodes.begin (); i != nodes.end (); ++i) { + dm.insert (*i->second); + scm.insert (*i->second); + } - SubCircuitMapperForTargetNode scm (e, ee); - SubCircuitMapperForTargetNode scm_other (e_other, ee_other); + DeviceMapperForTargetNode dm_other; + SubCircuitMapperForTargetNode scm_other; + for (std::vector >::const_iterator i = other_nodes.begin (); i != other_nodes.end (); ++i) { + dm_other.insert (*i->second); + scm_other.insert (*i->second); + } if (nodes.size () == 1 && other_nodes.size () == 1) { - if (! nodes.front ()->has_any_other () && ! other_nodes.front ()->has_any_other ()) { + const NetGraphNode *n = nodes.front ().first; + const NetGraphNode *n_other = other_nodes.front ().first; + + // reject the transition if the edges provide a contradiction to already established equivalences + + if (! edges_are_compatible (*nodes.front ().second, *other_nodes.front ().second, *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; + + } else if (! n->has_any_other () && ! n_other->has_any_other ()) { // a single candiate: just take this one -> this may render // inexact matches, but further propagates net pairing - size_t ni = node_index_for_net (nodes.front ()->net ()); - size_t other_ni = data->other->node_index_for_net (other_nodes.front ()->net ()); + size_t ni = node_index_for_net (n->net ()); + size_t other_ni = data->other->node_index_for_net (n_other->net ()); TentativeNodeMapping::map_pair (tentative, this, ni, data->other, other_ni); if (! tentative) { @@ -2202,14 +2244,14 @@ NetGraph::derive_node_identities_from_node_set (NetGraphNode::edge_iterator e, N } if (options ()->debug_netcompare) { - tl::info << indent_s << "deduced match (singular): " << nodes.front ()->net ()->expanded_name () << " vs. " << other_nodes.front ()->net ()->expanded_name (); + tl::info << indent_s << "deduced match (singular): " << n->net ()->expanded_name () << " vs. " << n_other->net ()->expanded_name (); } if (data->logger && ! tentative) { if (! (node (ni) == data->other->node (other_ni))) { // this is a mismatch but we continue, because that is the only candidate - data->logger->net_mismatch (nodes.front ()->net (), other_nodes.front ()->net ()); + data->logger->net_mismatch (n->net (), n_other->net ()); } else { - data->logger->match_nets (nodes.front ()->net (), other_nodes.front ()->net ()); + data->logger->match_nets (n->net (), n_other->net ()); } } @@ -2224,14 +2266,14 @@ NetGraph::derive_node_identities_from_node_set (NetGraphNode::edge_iterator e, N new_nodes += 1; - } else if (nodes.front ()->has_unknown_other ()) { + } else if (n->has_unknown_other ()) { // accept this solution as the pairing is possible - } else if (nodes.front ()->has_other ()) { + } else if (n->has_other ()) { // this decision leads to a contradiction - if (data->other->node_index_for_net (other_nodes.front ()->net ()) != nodes.front ()->other_net_index ()) { + if (data->other->node_index_for_net (n_other->net ()) != n->other_net_index ()) { return failed_match; } @@ -2250,38 +2292,38 @@ NetGraph::derive_node_identities_from_node_set (NetGraphNode::edge_iterator e, N std::vector node_ranges; - std::vector::iterator n1 = nodes.begin (); - std::vector::iterator n2 = other_nodes.begin (); + std::vector >::iterator n1 = nodes.begin (); + std::vector >::iterator n2 = other_nodes.begin (); while (n1 != nodes.end () && n2 != other_nodes.end ()) { - if ((*n1)->has_any_other ()) { + if (n1->first->has_any_other ()) { ++n1; continue; - } else if ((*n2)->has_any_other ()) { + } else if (n2->first->has_any_other ()) { ++n2; continue; } - if (**n1 < **n2) { + if (*n1->first < *n2->first) { ++n1; continue; - } else if (**n2 < **n1) { + } else if (*n2->first < *n1->first) { ++n2; continue; } - std::vector::iterator nn1 = n1, nn2 = n2; + std::vector >::iterator nn1 = n1, nn2 = n2; size_t num = 1; ++nn1; ++nn2; while (nn1 != nodes.end () && nn2 != other_nodes.end ()) { - if ((*nn1)->has_any_other ()) { + if (nn1->first->has_any_other ()) { ++nn1; - } else if ((*nn2)->has_any_other ()) { + } else if (nn2->first->has_any_other ()) { ++nn2; - } else if (! (**nn1 == **n1) || ! (**nn2 == **n2)) { + } else if (! (*nn1->first == *n1->first) || ! (*nn2->first == *n2->first)) { break; } else { ++num; @@ -2314,9 +2356,9 @@ NetGraph::derive_node_identities_from_node_set (NetGraphNode::edge_iterator e, N // node ranges might have changed - adjust to real count and skip leading pairs assigned already while (nr->n1 != nr->nn1 && nr->n2 != nr->nn2) { - if ((*nr->n1)->has_any_other ()) { + if (nr->n1->first->has_any_other ()) { ++nr->n1; - } else if ((*nr->n2)->has_any_other ()) { + } else if (nr->n2->first->has_any_other ()) { ++nr->n2; } else { break; @@ -2324,12 +2366,12 @@ NetGraph::derive_node_identities_from_node_set (NetGraphNode::edge_iterator e, N } nr->num = 0; - std::vector::const_iterator i1 = nr->n1, i2 = nr->n2; + std::vector >::const_iterator i1 = nr->n1, i2 = nr->n2; while (i1 != nr->nn1 && i2 != nr->nn2) { - if ((*i1)->has_any_other ()) { + if (i1->first->has_any_other ()) { ++i1; - } else if ((*i2)->has_any_other ()) { + } else if (i2->first->has_any_other ()) { ++i2; } else { ++nr->num; @@ -2344,14 +2386,14 @@ NetGraph::derive_node_identities_from_node_set (NetGraphNode::edge_iterator e, N } else if (nr->num == 1) { - if (! (*nr->n1)->has_any_other () && ! (*nr->n2)->has_any_other ()) { + if (! nr->n1->first->has_any_other () && ! nr->n2->first->has_any_other ()) { // in tentative mode, reject this choice if both nets are named and // their names differ -> this favors net matching by name - if (tentative && ! data->dont_consider_net_names && net_names_are_different ((*nr->n1)->net (), (*nr->n2)->net ())) { + if (tentative && ! data->dont_consider_net_names && net_names_are_different (nr->n1->first->net (), nr->n2->first->net ())) { if (options ()->debug_netcompare) { - tl::info << indent_s << "rejecting pair as names are not identical: " << (*nr->n1)->net ()->expanded_name () << " vs. " << (*nr->n2)->net ()->expanded_name (); + tl::info << indent_s << "rejecting pair as names are not identical: " << nr->n1->first->net ()->expanded_name () << " vs. " << nr->n2->first->net ()->expanded_name (); } return failed_match; } @@ -2359,8 +2401,8 @@ NetGraph::derive_node_identities_from_node_set (NetGraphNode::edge_iterator e, N // A single candiate: just take this one -> this may render // inexact matches, but further propagates net pairing - size_t ni = node_index_for_net ((*nr->n1)->net ()); - size_t other_ni = data->other->node_index_for_net ((*nr->n2)->net ()); + size_t ni = node_index_for_net (nr->n1->first->net ()); + size_t other_ni = data->other->node_index_for_net (nr->n2->first->net ()); TentativeNodeMapping::map_pair (tentative, this, ni, data->other, other_ni); if (! tentative) { @@ -2369,14 +2411,14 @@ NetGraph::derive_node_identities_from_node_set (NetGraphNode::edge_iterator e, N } if (options ()->debug_netcompare) { - tl::info << indent_s << "deduced match (singular): " << (*nr->n1)->net ()->expanded_name () << " vs. " << (*nr->n2)->net ()->expanded_name (); + tl::info << indent_s << "deduced match (singular): " << nr->n1->first->net ()->expanded_name () << " vs. " << nr->n2->first->net ()->expanded_name (); } if (data->logger && ! tentative) { if (! (node (ni) == data->other->node (other_ni))) { // this is a mismatch, but we continue with this - data->logger->net_mismatch ((*nr->n1)->net (), (*nr->n2)->net ()); + data->logger->net_mismatch (nr->n1->first->net (), nr->n2->first->net ()); } else { - data->logger->match_nets ((*nr->n1)->net (), (*nr->n2)->net ()); + data->logger->match_nets (nr->n1->first->net (), nr->n2->first->net ()); } } @@ -2390,14 +2432,14 @@ NetGraph::derive_node_identities_from_node_set (NetGraphNode::edge_iterator e, N new_nodes = bt_count; } - } else if ((*nr->n1)->has_unknown_other ()) { + } else if (nr->n1->first->has_unknown_other ()) { // accept any other net - } else if ((*nr->n1)->has_other ()) { + } else if (nr->n1->first->has_other ()) { // this decision leads to a contradiction - if (data->other->node_index_for_net ((*nr->n2)->net ()) != (*nr->n1)->other_net_index ()) { + if (data->other->node_index_for_net (nr->n2->first->net ()) != nr->n1->first->other_net_index ()) { return failed_match; } @@ -2437,48 +2479,56 @@ NetGraph::derive_node_identities_from_node_set (NetGraphNode::edge_iterator e, N TentativeNodeMapping tn2unknown; // collect and mark the ambiguity combinations to consider - std::vector::const_iterator> iters1, iters2; + std::vector >::const_iterator> iters1, iters2; - for (std::vector::const_iterator i1 = nr->n1; i1 != nr->nn1; ++i1) { - if (! (*i1)->has_any_other ()) { + for (std::vector >::const_iterator i1 = nr->n1; i1 != nr->nn1; ++i1) { + if (! i1->first->has_any_other ()) { iters1.push_back (i1); - size_t ni = node_index_for_net ((*i1)->net ()); + size_t ni = node_index_for_net (i1->first->net ()); TentativeNodeMapping::map_to_unknown (&tn2unknown, this, ni); } } - for (std::vector::const_iterator i2 = nr->n2; i2 != nr->nn2; ++i2) { - if (! (*i2)->has_any_other ()) { + for (std::vector >::const_iterator i2 = nr->n2; i2 != nr->nn2; ++i2) { + if (! i2->first->has_any_other ()) { iters2.push_back (i2); - size_t other_ni = data->other->node_index_for_net ((*i2)->net ()); + size_t other_ni = data->other->node_index_for_net (i2->first->net ()); TentativeNodeMapping::map_to_unknown (&tn2unknown, data->other, other_ni); } } - for (std::vector::const_iterator>::const_iterator ii1 = iters1.begin (); ii1 != iters1.end (); ++ii1) { + for (std::vector >::const_iterator>::const_iterator ii1 = iters1.begin (); ii1 != iters1.end (); ++ii1) { - std::vector::const_iterator i1 = *ii1; + std::vector >::const_iterator i1 = *ii1; bool any = false; - for (std::vector::const_iterator>::const_iterator ii2 = iters2.begin (); ii2 != iters2.end (); ++ii2) { + for (std::vector >::const_iterator>::const_iterator ii2 = iters2.begin (); ii2 != iters2.end (); ++ii2) { - std::vector::const_iterator i2 = *ii2; + std::vector >::const_iterator i2 = *ii2; - if (seen.find (*i2) != seen.end ()) { + if (seen.find (i2->first) != seen.end ()) { continue; } - size_t ni = node_index_for_net ((*i1)->net ()); - size_t other_ni = data->other->node_index_for_net ((*i2)->net ()); + // try this candidate in tentative mode + if (options ()->debug_netcompare) { + tl::info << indent_s << "trying in tentative mode: " << i1->first->net ()->expanded_name () << " vs. " << i2->first->net ()->expanded_name (); + } + + if (! edges_are_compatible (*i1->second, *i2->second, *data->device_equivalence, *data->subcircuit_equivalence)) { + if (options ()->debug_netcompare) { + tl::info << indent_s << "=> rejected because edges are incompatible with already established device or subcircuit equivalences"; + } + continue; + } + + size_t ni = node_index_for_net (i1->first->net ()); + size_t other_ni = data->other->node_index_for_net (i2->first->net ()); TentativeNodeMapping tn; TentativeNodeMapping::map_pair_from_unknown (&tn, this, ni, data->other, other_ni); - // try this candidate in tentative mode - if (options ()->debug_netcompare) { - tl::info << indent_s << "trying in tentative mode: " << (*i1)->net ()->expanded_name () << " vs. " << (*i2)->net ()->expanded_name (); - } size_t bt_count = derive_node_identities (ni, depth + 1, nr->num * n_branch, &tn, with_ambiguous, data); if (bt_count != failed_match) { @@ -2492,14 +2542,14 @@ NetGraph::derive_node_identities_from_node_set (NetGraphNode::edge_iterator e, N // there is already a known pair, so we can mark *i2 and the previous *i2 as equivalent // (makes them ambiguous) - equivalent_other_nodes.same (*i2, pairs.back ().second); + equivalent_other_nodes.same (i2->first, pairs.back ().second); } else { // identified a new pair new_nodes += bt_count + 1; - pairs.push_back (std::make_pair (*i1, *i2)); - seen.insert (*i2); + pairs.push_back (std::make_pair (i1->first, i2->first)); + seen.insert (i2->first); any = true; } @@ -3220,29 +3270,32 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, // derive new identities through topology: first collect all nets with the same topological signature - std::vector nodes, other_nodes; + std::vector > nodes, other_nodes; + + std::vector no_edges; + no_edges.push_back (NetGraphNode::edge_type ()); nodes.reserve (g1.end () - g1.begin ()); for (db::NetGraph::node_iterator i1 = g1.begin (); i1 != g1.end (); ++i1) { if (! i1->has_other () && i1->net ()) { - nodes.push_back (i1.operator-> ()); + nodes.push_back (std::make_pair (i1.operator-> (), no_edges.begin ())); } } other_nodes.reserve (g2.end () - g2.begin ()); for (db::NetGraph::node_iterator i2 = g2.begin (); i2 != g2.end (); ++i2) { if (! i2->has_other () && i2->net ()) { - other_nodes.push_back (i2.operator-> ()); + other_nodes.push_back (std::make_pair (i2.operator-> (), no_edges.begin ())); } } if (nodes.empty () || other_nodes.empty ()) { // active mismatched nodes give an error - for (std::vector::const_iterator n = nodes.begin (); n != nodes.end () && good; ++n) { - good = is_passive_net ((*n)->net (), c12_circuit_and_pin_mapping); + for (std::vector >::const_iterator n = nodes.begin (); n != nodes.end () && good; ++n) { + good = is_passive_net (n->first->net (), c12_circuit_and_pin_mapping); } - for (std::vector::const_iterator n = other_nodes.begin (); n != other_nodes.end () && good; ++n) { - good = is_passive_net ((*n)->net (), c22_circuit_and_pin_mapping); + for (std::vector >::const_iterator n = other_nodes.begin (); n != other_nodes.end () && good; ++n) { + good = is_passive_net (n->first->net (), c22_circuit_and_pin_mapping); } // this assumes that we don't gain anything here. Stop now. break; @@ -3261,9 +3314,7 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, data.device_equivalence = &device_equivalence; data.logger = mp_logger; - 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); + size_t ni = g1.derive_node_identities_from_node_set (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) { @@ -4059,12 +4110,15 @@ NetlistComparer::join_symmetric_nets (db::Circuit *circuit) // nodes are identical if the attached devices and circuits are of the same kind and with the same parameters // and connect to other nodes in identical configurations. - std::vector nodes; + std::vector > nodes; + + std::vector no_edges; + no_edges.push_back (NetGraphNode::edge_type ()); nodes.reserve (graph.end () - graph.begin ()); for (db::NetGraph::node_iterator i = graph.begin (); i != graph.end (); ++i) { if (! i->has_other () && i->net ()) { - nodes.push_back (i.operator-> ()); + nodes.push_back (std::make_pair (i.operator-> (), no_edges.begin ())); } } @@ -4074,18 +4128,18 @@ NetlistComparer::join_symmetric_nets (db::Circuit *circuit) tl::equivalence_clusters identical_nodes; - for (std::vector::const_iterator np = nodes.begin (); np + 1 != nodes.end (); ++np) { - if (*np[0] == *np[1]) { - identical_nodes.same (np[0], np[1]); + for (std::vector >::const_iterator np = nodes.begin (); np + 1 != nodes.end (); ++np) { + if (*np[0].first == *np[1].first) { + identical_nodes.same (np[0].first, np[1].first); } } std::vector > symmetry_groups; std::set visited; - for (std::vector::const_iterator np = nodes.begin (); np != nodes.end (); ++np) { + for (std::vector >::const_iterator np = nodes.begin (); np != nodes.end (); ++np) { - size_t node_id = graph.node_index_for_net (np[0]->net ()); + size_t node_id = graph.node_index_for_net (np[0].first->net ()); if (visited.find (node_id) != visited.end ()) { continue; } diff --git a/src/db/unit_tests/dbNetlistCompareTests.cc b/src/db/unit_tests/dbNetlistCompareTests.cc index 934394ec9..8d50548aa 100644 --- a/src/db/unit_tests/dbNetlistCompareTests.cc +++ b/src/db/unit_tests/dbNetlistCompareTests.cc @@ -2552,8 +2552,8 @@ TEST(17_InherentlyAmbiguousDecoder) "match_ambiguous_nets NQ1 NQ1\n" "match_ambiguous_nets NQ2 NQ2\n" "match_nets NQ3 NQ3\n" - "match_ambiguous_nets NA NA\n" - "match_ambiguous_nets NB NB\n" + "match_nets NA NA\n" + "match_nets NB NB\n" "match_nets B B\n" "match_nets A A\n" "match_pins $0 $1\n" @@ -3576,7 +3576,7 @@ TEST(23_NodesRemovedWithError) "pin_mismatch (null) BULK\n" "pin_mismatch (null) $6\n" "match_subcircuits $1 $1\n" - "subcircuit_mismatch $2 $2\n" + "match_subcircuits $2 $2\n" "end_circuit INV2PAIR INV2PAIR NOMATCH\n" "circuit_skipped RINGO RINGO" ); diff --git a/testdata/lvs/ringo_simple_dmos.lvsdb.1 b/testdata/lvs/ringo_simple_dmos.lvsdb.1 index 47ac96fa8..5af17e7b3 100644 --- a/testdata/lvs/ringo_simple_dmos.lvsdb.1 +++ b/testdata/lvs/ringo_simple_dmos.lvsdb.1 @@ -850,7 +850,7 @@ xref( device(1 1 match) ) ) - circuit(ND2X1 ND2X1 nomatch + circuit(ND2X1 ND2X1 match xref( net(4 8 mismatch) net(5 4 mismatch) @@ -867,10 +867,10 @@ xref( pin(6 6 match) pin(0 0 match) pin(2 2 match) + device(3 3 match) device(4 4 match) - device(3 3 mismatch) + device(1 1 match) device(2 2 match) - device(1 1 mismatch) ) ) circuit(RINGO RINGO match From fed563c6d442b22108266da3636f57eca5ecfd73 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 23 Jun 2020 22:43:31 +0200 Subject: [PATCH 7/7] Finalization of the net compare algorithm change This patch will allow the algorithm to consider device and subcircuit equivalences during tentative evaluation too. --- src/db/db/dbNetlistCompare.cc | 427 +++++++++++++++++++--------------- 1 file changed, 235 insertions(+), 192 deletions(-) diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc index a7547e73d..9787d2ca3 100644 --- a/src/db/db/dbNetlistCompare.cc +++ b/src/db/db/dbNetlistCompare.cc @@ -354,6 +354,12 @@ public: return inserted1.second; } + void unmap (const Obj *a, const Obj *b) + { + m_eq.erase (a); + m_eq.erase (b); + } + const Obj *other (const Obj *o) const { typename std::map::const_iterator i = m_eq.find (o); @@ -1508,6 +1514,158 @@ struct NodeRange // -------------------------------------------------------------------------------------------------------------------- +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 +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, std::vector > &mapped) + { + 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 + mapped.push_back (std::make_pair (i10->second, i20->second)); + } + } + + } + + } + +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 () + : generic_mapper_for_target_node () + { + // .. nothing yet .. + } + + void insert (const NetGraphNode::edge_type &e) + { + if (e.first.empty ()) { + // happens initially + return; + } + + size_t ni = e.second.first; + std::set > &dev = for_node_nc (ni); + for (std::vector::const_iterator j = e.first.begin (); j != e.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 () + : generic_mapper_for_target_node () + { + // .. nothing yet .. + } + + void insert (const NetGraphNode::edge_type &e) + { + if (e.first.empty ()) { + // happens initially + return; + } + + size_t ni = e.second.first; + std::set > &sc = for_node_nc (ni); + for (std::vector::const_iterator j = e.first.begin (); j != e.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)); + } + } + } +}; + /** * @brief An audit object which allows reverting tentative node assignments */ @@ -1525,26 +1683,46 @@ public: for (std::vector >::const_iterator i = m_to_undo_to_unknown.begin (); i != m_to_undo_to_unknown.end (); ++i) { i->first->identify (i->second, unknown_id); } + for (std::vector > >::const_iterator i = m_to_undo_devices.begin (); i != m_to_undo_devices.end (); ++i) { + i->first->unmap (i->second.first, i->second.second); + } + for (std::vector > >::const_iterator i = m_to_undo_subcircuits.begin (); i != m_to_undo_subcircuits.end (); ++i) { + i->first->unmap (i->second.first, i->second.second); + } } - static void map_pair (TentativeNodeMapping *nm, NetGraph *g1, size_t n1, NetGraph *g2, size_t n2) + static void map_pair (TentativeNodeMapping *nm, NetGraph *g1, size_t n1, NetGraph *g2, size_t n2, + const DeviceMapperForTargetNode &dm1, const DeviceMapperForTargetNode &dm2, DeviceEquivalenceTracker &device_eq, + const SubCircuitMapperForTargetNode &scm1, const SubCircuitMapperForTargetNode &scm2, SubCircuitEquivalenceTracker &subcircuit_eq, + size_t depth) { g1->identify (n1, n2); g2->identify (n2, n1); + if (nm) { nm->keep (g1, n1); nm->keep (g2, n2); } + + derive_device_equivalence (nm, n1, n2, dm1, dm2, device_eq, depth); + derive_subcircuit_equivalence (nm, n1, n2, scm1, scm2, subcircuit_eq, depth); } - static void map_pair_from_unknown (TentativeNodeMapping *nm, NetGraph *g1, size_t n1, NetGraph *g2, size_t n2) + static void map_pair_from_unknown (TentativeNodeMapping *nm, NetGraph *g1, size_t n1, NetGraph *g2, size_t n2, + const DeviceMapperForTargetNode &dm1, const DeviceMapperForTargetNode &dm2, DeviceEquivalenceTracker &device_eq, + const SubCircuitMapperForTargetNode &scm1, const SubCircuitMapperForTargetNode &scm2, SubCircuitEquivalenceTracker &subcircuit_eq, + size_t depth) { g1->identify (n1, n2); g2->identify (n2, n1); + if (nm) { nm->keep_for_unknown (g1, n1); nm->keep_for_unknown (g2, n2); } + + derive_device_equivalence (nm, n1, n2, dm1, dm2, device_eq, depth); + derive_subcircuit_equivalence (nm, n1, n2, scm1, scm2, subcircuit_eq, depth); } static void map_to_unknown (TentativeNodeMapping *nm, NetGraph *g1, size_t n1) @@ -1555,8 +1733,48 @@ public: } } + static void derive_device_equivalence (TentativeNodeMapping *nm, size_t n1, size_t n2, + const DeviceMapperForTargetNode &dm1, const DeviceMapperForTargetNode &dm2, DeviceEquivalenceTracker &device_eq, size_t depth) + { + std::vector > device_map; + DeviceMapperForTargetNode::derive_mapping (dm1, dm2, n1, n2, device_map); + + for (std::vector >::const_iterator dd = device_map.begin (); dd != device_map.end (); ++dd) { + if (device_eq.map (dd->first, dd->second)) { + if (nm) { + nm->keep (&device_eq, dd->first, dd->second); + } else { + if (options ()->debug_netcompare) { + tl::info << indent(depth) << "enforcing device equivalence: " << dd->first->expanded_name () << " vs. " << dd->second->expanded_name (); + } + } + } + } + } + + static void derive_subcircuit_equivalence (TentativeNodeMapping *nm, size_t n1, size_t n2, + const SubCircuitMapperForTargetNode &scm1, const SubCircuitMapperForTargetNode &scm2, SubCircuitEquivalenceTracker &subcircuit_eq, size_t depth) + { + std::vector > subcircuit_map; + SubCircuitMapperForTargetNode::derive_mapping (scm1, scm2, n1, n2, subcircuit_map); + + for (std::vector >::const_iterator cc = subcircuit_map.begin (); cc != subcircuit_map.end (); ++cc) { + if (subcircuit_eq.map (cc->first, cc->second)) { + if (nm) { + nm->keep (&subcircuit_eq, cc->first, cc->second); + } else { + if (options ()->debug_netcompare) { + tl::info << indent(depth) << "enforcing subcircuit equivalence: " << cc->first->expanded_name () << " vs. " << cc->second->expanded_name (); + } + } + } + } + } + private: std::vector > m_to_undo, m_to_undo_to_unknown; + std::vector > > m_to_undo_devices; + std::vector > > m_to_undo_subcircuits; void keep (NetGraph *g1, size_t n1) { @@ -1567,6 +1785,16 @@ private: { m_to_undo_to_unknown.push_back (std::make_pair (g1, n1)); } + + void keep (DeviceEquivalenceTracker *dt, const db::Device *a, const db::Device *b) + { + m_to_undo_devices.push_back (std::make_pair (dt, std::make_pair (a, b))); + } + + void keep (SubCircuitEquivalenceTracker *dt, const db::SubCircuit *a, const db::SubCircuit *b) + { + m_to_undo_subcircuits.push_back (std::make_pair (dt, std::make_pair (a, b))); + } }; // -------------------------------------------------------------------------------------------------------------------- @@ -2008,181 +2236,6 @@ 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 -inline std::string log_text_for_equivalence (); - -template <> -inline std::string log_text_for_equivalence () -{ - return "enforcing device equivalence"; -} - -template <> -inline 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 () - : generic_mapper_for_target_node () - { - // .. nothing yet .. - } - - void insert (const NetGraphNode::edge_type &e) - { - if (e.first.empty ()) { - // happens initially - return; - } - - size_t ni = e.second.first; - std::set > &dev = for_node_nc (ni); - for (std::vector::const_iterator j = e.first.begin (); j != e.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 () - : generic_mapper_for_target_node () - { - // .. nothing yet .. - } - - void insert (const NetGraphNode::edge_type &e) - { - if (e.first.empty ()) { - // happens initially - return; - } - - size_t ni = e.second.first; - std::set > &sc = for_node_nc (ni); - for (std::vector::const_iterator j = e.first.begin (); j != e.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) { @@ -2237,11 +2290,7 @@ NetGraph::derive_node_identities_from_node_set (std::vectornet ()); size_t other_ni = data->other->node_index_for_net (n_other->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); - } + TentativeNodeMapping::map_pair (tentative, this, ni, data->other, other_ni, dm, dm_other, *data->device_equivalence, scm, scm_other, *data->subcircuit_equivalence, depth); if (options ()->debug_netcompare) { tl::info << indent_s << "deduced match (singular): " << n->net ()->expanded_name () << " vs. " << n_other->net ()->expanded_name (); @@ -2404,11 +2453,7 @@ NetGraph::derive_node_identities_from_node_set (std::vectorn1->first->net ()); size_t other_ni = data->other->node_index_for_net (nr->n2->first->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); - } + TentativeNodeMapping::map_pair (tentative, this, ni, data->other, other_ni, dm, dm_other, *data->device_equivalence, scm, scm_other, *data->subcircuit_equivalence, depth); if (options ()->debug_netcompare) { tl::info << indent_s << "deduced match (singular): " << nr->n1->first->net ()->expanded_name () << " vs. " << nr->n2->first->net ()->expanded_name (); @@ -2527,7 +2572,7 @@ NetGraph::derive_node_identities_from_node_set (std::vectorother->node_index_for_net (i2->first->net ()); TentativeNodeMapping tn; - TentativeNodeMapping::map_pair_from_unknown (&tn, this, ni, data->other, other_ni); + TentativeNodeMapping::map_pair_from_unknown (&tn, this, ni, data->other, other_ni, dm, dm_other, *data->device_equivalence, scm, scm_other, *data->subcircuit_equivalence, depth); size_t bt_count = derive_node_identities (ni, depth + 1, nr->num * n_branch, &tn, with_ambiguous, data); @@ -2579,9 +2624,7 @@ 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 (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); + TentativeNodeMapping::map_pair (0, this, ni, data->other, other_ni, dm, dm_other, *data->device_equivalence, scm, scm_other, *data->subcircuit_equivalence, depth); if (options ()->debug_netcompare) { if (equivalent_other_nodes.has_attribute (p->second)) { @@ -2619,7 +2662,7 @@ 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); + TentativeNodeMapping::map_pair (tentative, this, ni, data->other, other_ni, dm, dm_other, *data->device_equivalence, scm, scm_other, *data->subcircuit_equivalence, depth); }