From 08e6df238b6aa3adf484c3ff61f6e5eb1f9bd568 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 25 Jun 2020 00:53:56 +0200 Subject: [PATCH 1/5] WIP: bugfixes, enhancements for netlist compare --- src/db/db/dbNetlistCompare.cc | 240 ++++++++++++++++++++-------------- 1 file changed, 141 insertions(+), 99 deletions(-) diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc index 9787d2ca3..69637e00f 100644 --- a/src/db/db/dbNetlistCompare.cc +++ b/src/db/db/dbNetlistCompare.cc @@ -1920,8 +1920,6 @@ static bool edges_are_compatible (const NetGraphNode::edge_type &e, const NetGra 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) { - size_t new_nodes = 0; - std::vector > nodes; nodes.reserve (ee - e); @@ -1930,100 +1928,114 @@ NetGraph::derive_node_identities_for_edges (NetGraphNode::edge_iterator e, NetGr tl_assert (e->first == e_other->first); - if (options ()->debug_netcompare) { - tl::info << indent(depth) << "considering transitions:"; - } - - bool first = true; - for (NetGraphNode::edge_iterator i = e; i != ee; ++i) { if (i->second.first != net_index) { const NetGraphNode *nn = &node (i->second.first); - if (options ()->debug_netcompare) { - if (first) { - tl::info << indent (depth) << " here: " << (node (net_index).net () ? node (net_index).net ()->expanded_name ().c_str () : "(null)") << " ->"; - first = false; - } - tl::info << indent (depth) << " " << (nn->net () ? nn->net ()->expanded_name ().c_str() : "(null)") << " via: " << tl::noendl; - for (std::vector::const_iterator t = i->first.begin (); t != i->first.end(); ++t) { - tl::info << (t != i->first.begin () ? "; " : "") << t->to_string() << tl::noendl; - } - tl::info << ""; + if (! nn->has_other ()) { + nodes.push_back (std::make_pair (nn, i)); } - nodes.push_back (std::make_pair (nn, i)); } } if (! nodes.empty ()) { // if non-ambiguous, non-assigned - first = true; - for (NetGraphNode::edge_iterator i = e_other; i != ee_other; ++i) { if (i->second.first != other_net_index) { const NetGraphNode *nn = &data->other->node (i->second.first); - if (options ()->debug_netcompare) { - if (first) { - tl::info << indent (depth) << " there: " << (data->other->node (other_net_index).net () ? data->other->node (other_net_index).net ()->expanded_name ().c_str () : "(null)") << " ->"; - first = false; - } - tl::info << indent(depth) << " " << (nn->net() ? nn->net()->expanded_name().c_str() : "(null)") << " via: " << tl::noendl; - for (std::vector::const_iterator t = i->first.begin (); t != i->first.end(); ++t) { - tl::info << (t != i->first.begin () ? "; " : "") << t->to_string() << tl::noendl; - } - tl::info << ""; + if (! nn->has_other ()) { + other_nodes.push_back (std::make_pair (nn, i)); } - other_nodes.push_back (std::make_pair (nn, i)); } } } - if (! nodes.empty () || ! other_nodes.empty ()) { + if (nodes.empty () || other_nodes.empty ()) { + return 0; + } - std::sort (nodes.begin (), nodes.end (), CompareNodePtr ()); - std::sort (other_nodes.begin (), other_nodes.end (), CompareNodePtr ()); + std::sort (nodes.begin (), nodes.end (), CompareNodePtr ()); + std::sort (other_nodes.begin (), other_nodes.end (), CompareNodePtr ()); - // for the purpose of match evaluation we require an exact match of the node structure + size_t new_nodes = 0; - if (tentative) { + if (options ()->debug_netcompare) { - if (nodes.size () != other_nodes.size ()) { - if (options ()->debug_netcompare) { - tl::info << indent(depth) << "=> rejected branch."; - } - return failed_match; + // print transitions if requested + + tl::info << indent(depth) << "considering transitions:"; + + bool first = true; + + for (std::vector >::const_iterator i = nodes.begin (); i != nodes.end (); ++i) { + const NetGraphNode *nn = i->first; + if (first) { + tl::info << indent (depth) << " here: " << (node (net_index).net () ? node (net_index).net ()->expanded_name ().c_str () : "(null)") << " ->"; + first = false; } + tl::info << indent (depth) << " " << (nn->net () ? nn->net ()->expanded_name ().c_str() : "(null)") << " via: " << tl::noendl; + for (std::vector::const_iterator t = i->second->first.begin (); t != i->second->first.end(); ++t) { + tl::info << (t != i->second->first.begin () ? "; " : "") << t->to_string() << tl::noendl; + } + tl::info << ""; + } - // 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].first == *other_nodes[i].first)) { - if (options ()->debug_netcompare) { - tl::info << indent(depth) << "=> rejected branch."; - } - return failed_match; + first = true; + + for (std::vector >::const_iterator i = other_nodes.begin (); i != other_nodes.end (); ++i) { + const NetGraphNode *nn = i->first; + if (first) { + tl::info << indent (depth) << " there: " << (data->other->node (other_net_index).net () ? data->other->node (other_net_index).net ()->expanded_name ().c_str () : "(null)") << " ->"; + first = false; + } + tl::info << indent(depth) << " " << (nn->net() ? nn->net()->expanded_name().c_str() : "(null)") << " via: " << tl::noendl; + for (std::vector::const_iterator t = i->second->first.begin (); t != i->second->first.end(); ++t) { + tl::info << (t != i->second->first.begin () ? "; " : "") << t->to_string() << tl::noendl; + } + tl::info << ""; + } + + } + + // for the purpose of match evaluation we require an exact match of the node structure + + if (tentative) { + + if (nodes.size () != other_nodes.size ()) { + if (options ()->debug_netcompare) { + tl::info << indent(depth) << "=> rejected branch."; + } + return failed_match; + } + + // 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].first == *other_nodes[i].first)) { + if (options ()->debug_netcompare) { + tl::info << indent(depth) << "=> rejected branch."; } + return failed_match; } } - } - // 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); + // 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 - if (bt_count == failed_match) { - if (tentative) { - if (options ()->debug_netcompare) { - tl::info << indent(depth) << "=> rejected branch."; - } - return bt_count; + 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) { + if (options ()->debug_netcompare) { + tl::info << indent(depth) << "=> rejected branch."; } - } else { - new_nodes += bt_count; + return bt_count; } - + } else { + new_nodes += bt_count; } if (options ()->debug_netcompare) { @@ -2055,16 +2067,6 @@ NetGraph::derive_node_identities (size_t net_index, size_t depth, size_t n_branc size_t other_net_index = n->other_net_index (); NetGraphNode *n_other = & data->other->node (other_net_index); - if (options ()->debug_netcompare) { - if (! tentative) { - tl::info << indent(depth) << "deducing from pair: " << n->net ()->expanded_name () << " vs. " << n_other->net ()->expanded_name (); - } else { - tl::info << indent(depth) << "tentatively deducing from pair: " << n->net ()->expanded_name () << " vs. " << n_other->net ()->expanded_name (); - } - } - - size_t new_nodes = 0; - NetGraphNode nn, nn_other; // If there are subcircuits on the graph we temporarily create edges from our node to the other nodes of @@ -2082,6 +2084,28 @@ NetGraph::derive_node_identities (size_t net_index, size_t depth, size_t n_branc } + bool any = false; + for (NetGraphNode::edge_iterator e = n->begin (); e != n->end () && ! any; ++e) { + any = ! node (e->second.first).has_other (); + } + for (NetGraphNode::edge_iterator e = n_other->begin (); e != n_other->end () && ! any; ++e) { + any = ! data->other->node (e->second.first).has_other (); + } + if (! any) { + // all target nodes are satisfied - skip + return 0; + } + + size_t new_nodes = 0; + + if (options ()->debug_netcompare) { + if (! tentative) { + tl::info << indent(depth) << "deducing from pair: " << n->net ()->expanded_name () << " vs. " << n_other->net ()->expanded_name (); + } else { + tl::info << indent(depth) << "tentatively deducing from pair: " << n->net ()->expanded_name () << " vs. " << n_other->net ()->expanded_name (); + } + } + // non-ambiguous paths to non-assigned nodes create a node identity on the // end of this path @@ -2304,13 +2328,16 @@ NetGraph::derive_node_identities_from_node_set (std::vectorfirst->has_any_other ()) { + if (n1->first->has_other ()) { ++n1; continue; - } else if (n2->first->has_any_other ()) { + } else if (n2->first->has_other ()) { ++n2; continue; } @@ -2368,9 +2395,9 @@ NetGraph::derive_node_identities_from_node_set (std::vectorfirst->has_any_other ()) { + if (nn1->first->has_other ()) { ++nn1; - } else if (nn2->first->has_any_other ()) { + } else if (nn2->first->has_other ()) { ++nn2; } else if (! (*nn1->first == *n1->first) || ! (*nn2->first == *n2->first)) { break; @@ -2405,9 +2432,9 @@ NetGraph::derive_node_identities_from_node_set (std::vectorn1 != nr->nn1 && nr->n2 != nr->nn2) { - if (nr->n1->first->has_any_other ()) { + if (nr->n1->first->has_other ()) { ++nr->n1; - } else if (nr->n2->first->has_any_other ()) { + } else if (nr->n2->first->has_other ()) { ++nr->n2; } else { break; @@ -2418,9 +2445,9 @@ NetGraph::derive_node_identities_from_node_set (std::vector >::const_iterator i1 = nr->n1, i2 = nr->n2; while (i1 != nr->nn1 && i2 != nr->nn2) { - if (i1->first->has_any_other ()) { + if (i1->first->has_other ()) { ++i1; - } else if (i2->first->has_any_other ()) { + } else if (i2->first->has_other ()) { ++i2; } else { ++nr->num; @@ -2435,7 +2462,14 @@ NetGraph::derive_node_identities_from_node_set (std::vectornum == 1) { - if (! nr->n1->first->has_any_other () && ! nr->n2->first->has_any_other ()) { + if (! edges_are_compatible (*nr->n1->second, *nr->n2->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 (! 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 @@ -2467,16 +2501,20 @@ NetGraph::derive_node_identities_from_node_set (std::vectorn1->first->has_unknown_other ()) { // accept any other net @@ -2936,6 +2974,7 @@ NetlistComparer::compare (const db::Netlist *a, const db::Netlist *b) const if (all_subcircuits_verified (ca, verified_circuits_a) && all_subcircuits_verified (cb, verified_circuits_b)) { if (options ()->debug_netcompare) { + tl::info << "----------------------------------------------------------------------"; tl::info << "treating circuit: " << ca->name () << " vs. " << cb->name (); } if (mp_logger) { @@ -3038,8 +3077,6 @@ compute_device_key (const db::Device &device, const db::NetGraph &g, bool strict k.push_back (std::make_pair (terminal_id, net_id)); } - std::sort (k.begin (), k.end ()); - return k; } @@ -3074,8 +3111,6 @@ compute_subcircuit_key (const db::SubCircuit &subcircuit, const db::NetGraph &g, } - std::sort (k.begin (), k.end ()); - return true; } @@ -3260,9 +3295,9 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, // two passes: one without ambiguities, the second one with - bool good; + bool good = false; - for (int pass = 0; pass < 2; ++pass) { + for (int pass = 0; pass < 2 /*&& ! good*/; ++pass) { if (options ()->debug_netcompare) { if (pass > 0) { @@ -3366,6 +3401,9 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, } if (new_identities == 0) { + if (options ()->debug_netcompare) { + tl::info << "Stopped with " << nodes.size () << "/" << other_nodes.size () << " nodes left unresolved."; + } good = false; break; } @@ -3660,6 +3698,8 @@ NetlistComparer::do_device_assignment (const db::Circuit *c1, const db::NetGraph } } + std::sort (k.begin (), k.end ()); + if (! mapped) { if (mp_logger) { unmatched_a.push_back (std::make_pair (k, std::make_pair (d.operator-> (), device_cat))); @@ -3860,6 +3900,8 @@ NetlistComparer::do_subcircuit_assignment (const db::Circuit *c1, const db::NetG } } + std::sort (k.begin (), k.end ()); + if (! mapped) { if (mp_logger) { mp_logger->subcircuit_mismatch (sc.operator-> (), 0); From b4732d818d90c0ab93ccfeac8f659781ef13617e Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 26 Jun 2020 00:22:30 +0200 Subject: [PATCH 2/5] WIP: proper checking of device and subcircuit topologiy - don't entirely rely on the equivalence deduction. --- src/db/db/dbNetlistCompare.cc | 393 +++++++++++++++++++++++----------- src/db/db/dbNetlistCompare.h | 21 ++ 2 files changed, 284 insertions(+), 130 deletions(-) diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc index 69637e00f..5d8227a3a 100644 --- a/src/db/db/dbNetlistCompare.cc +++ b/src/db/db/dbNetlistCompare.cc @@ -616,13 +616,14 @@ class NetGraph; struct CompareData { CompareData () - : other (0), max_depth (0), max_n_branch (0), dont_consider_net_names (false), logger (0), + : other (0), max_depth (0), max_n_branch (0), depth_first (true), dont_consider_net_names (false), logger (0), circuit_pin_mapper (0), subcircuit_equivalence (0), device_equivalence (0) { } NetGraph *other; size_t max_depth; size_t max_n_branch; + bool depth_first; bool dont_consider_net_names; NetlistCompareLogger *logger; CircuitPinMapper *circuit_pin_mapper; @@ -2328,16 +2329,15 @@ NetGraph::derive_node_identities_from_node_set (std::vectordepth_first || tentative) { size_t bt_count = derive_node_identities (ni, depth + 1, n_branch, tentative, with_ambiguous, data); if (bt_count == failed_match) { - return failed_match; + if (tentative) { + return failed_match; + } + } else { + new_nodes += bt_count; } - - new_nodes += bt_count; - } new_nodes += 1; @@ -2501,16 +2501,15 @@ NetGraph::derive_node_identities_from_node_set (std::vectordepth_first || tentative) { size_t bt_count = derive_node_identities (ni, depth + 1, n_branch, tentative, with_ambiguous, data); if (bt_count == failed_match) { - return failed_match; + if (tentative) { + return failed_match; + } + } else { + new_nodes += bt_count; } - - new_nodes += bt_count; - } new_nodes += 1; @@ -2733,6 +2732,7 @@ NetlistComparer::NetlistComparer (NetlistCompareLogger *logger) m_max_depth = 50; m_max_n_branch = 500; + m_depth_first = true; m_dont_consider_net_names = false; } @@ -3080,6 +3080,42 @@ compute_device_key (const db::Device &device, const db::NetGraph &g, bool strict return k; } +static std::vector > +compute_device_key_for_this (const db::Device &device, const db::NetGraph &g, bool strict, bool &mapped) +{ + std::vector > k = compute_device_key (device, g, strict); + + mapped = true; + for (std::vector >::iterator i = k.begin (); i != k.end (); ++i) { + if (! g.begin () [i->second].has_other ()) { + i->second = invalid_id; // normalization + mapped = false; + } + } + + std::sort (k.begin (), k.end ()); + return k; +} + +static std::vector > +compute_device_key_for_other (const db::Device &device, const db::NetGraph &g, bool strict, bool &mapped) +{ + std::vector > k = compute_device_key (device, g, strict); + + mapped = true; + for (std::vector >::iterator i = k.begin (); i != k.end (); ++i) { + if (! g.begin () [i->second].has_other ()) { + i->second = invalid_id; // normalization + mapped = false; + } else { + i->second = g.begin () [i->second].other_net_index (); + } + } + + std::sort (k.begin (), k.end ()); + return k; +} + static bool compute_subcircuit_key (const db::SubCircuit &subcircuit, const db::NetGraph &g, const std::map *circuit_map, const CircuitPinMapper *pin_map, std::vector > &k) { @@ -3114,6 +3150,46 @@ compute_subcircuit_key (const db::SubCircuit &subcircuit, const db::NetGraph &g, return true; } +static std::vector > +compute_subcircuit_key_for_this (const db::SubCircuit &subcircuit, const db::NetGraph &g, const std::map *circuit_map, const CircuitPinMapper *pin_map, bool &mapped) +{ + std::vector > k; + if (! compute_subcircuit_key (subcircuit, g, circuit_map, pin_map, k)) { + k.clear (); + } + + mapped = true; + for (std::vector >::iterator i = k.begin (); i != k.end () && mapped; ++i) { + if (! g.begin () [i->second].has_other ()) { + mapped = false; + } + } + + std::sort (k.begin (), k.end ()); + return k; +} + +static std::vector > +compute_subcircuit_key_for_other (const db::SubCircuit &subcircuit, const db::NetGraph &g, const std::map *circuit_map, const CircuitPinMapper *pin_map, bool &mapped) +{ + std::vector > k; + if (! compute_subcircuit_key (subcircuit, g, circuit_map, pin_map, k)) { + k.clear (); + } + + mapped = true; + for (std::vector >::iterator i = k.begin (); i != k.end (); ++i) { + if (! g.begin () [i->second].has_other ()) { + mapped = false; + } else { + i->second = g.begin () [i->second].other_net_index (); + } + } + + std::sort (k.begin (), k.end ()); + return k; +} + namespace { inline double size_dist (size_t a, size_t b) @@ -3297,7 +3373,7 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, bool good = false; - for (int pass = 0; pass < 2 /*&& ! good*/; ++pass) { + for (int pass = 0; pass < 2 && ! good; ++pass) { if (options ()->debug_netcompare) { if (pass > 0) { @@ -3324,6 +3400,7 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, data.other = &g2; data.max_depth = m_max_depth; data.max_n_branch = m_max_n_branch; + data.depth_first = m_depth_first; data.dont_consider_net_names = m_dont_consider_net_names; data.circuit_pin_mapper = &circuit_pin_mapper; data.subcircuit_equivalence = &subcircuit_equivalence; @@ -3375,6 +3452,9 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, 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); } + if (options ()->debug_netcompare) { + tl::info << "Stopped with " << nodes.size () << "/" << other_nodes.size () << " nodes left unresolved " << (good ? "(accepted)" : "(not accepted)"); + } // this assumes that we don't gain anything here. Stop now. break; } @@ -3416,6 +3496,9 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, for (db::NetGraph::node_iterator i = g1.begin (); i != g1.end (); ++i) { if (! i->has_other ()) { + if (options ()->debug_netcompare) { + tl::info << "Unresolved net from left: " << i->net ()->expanded_name () << " " << (good ? "(accepted)" : "(not accepted)"); + } if (mp_logger) { if (good) { mp_logger->match_nets (i->net (), 0); @@ -3432,6 +3515,9 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, for (db::NetGraph::node_iterator i = g2.begin (); i != g2.end (); ++i) { if (! i->has_other ()) { + if (options ()->debug_netcompare) { + tl::info << "Unresolved net from right: " << i->net ()->expanded_name () << " " << (good ? "(accepted)" : "(not accepted)"); + } if (mp_logger) { if (good) { mp_logger->match_nets (0, i->net ()); @@ -3672,6 +3758,69 @@ NetlistComparer::do_device_assignment (const db::Circuit *c1, const db::NetGraph typedef std::vector >, std::pair > > unmatched_list; unmatched_list unmatched_a, unmatched_b; + // check mapping of devices whose equivalence is established topologically + + for (db::Circuit::const_device_iterator d = c1->begin_devices (); d != c1->end_devices (); ++d) { + + if (! device_filter.filter (d.operator-> ())) { + continue; + } + + const db::Device *d_other = device_eq.other (d.operator-> ()); + if (! d_other) { + continue; + } + + size_t device_cat = device_categorizer.cat_for_device (d.operator-> ()); + if (! device_cat) { + // device is ignored + continue; + } + + size_t device_cat_other = device_categorizer.cat_for_device (d_other); + if (! device_cat_other) { + // device is ignored + continue; + } + + bool mapped1 = true, mapped2 = true; + std::vector > k = compute_device_key_for_this (*d, g1, device_categorizer.is_strict_device_category (device_cat), mapped1); + std::vector > k_other = compute_device_key_for_other (*d_other, g2, device_categorizer.is_strict_device_category (device_cat_other), mapped2); + + if (! mapped1 || ! mapped2 || k != k_other) { + + // topological mismatch + if (mp_logger) { + mp_logger->device_mismatch (d.operator-> (), d_other); + } + good = false; + + } else { + + db::DeviceCompare dc; + + if (! dc.equals (std::make_pair (d.operator-> (), device_cat), std::make_pair (d_other, device_cat_other))) { + if (device_cat != device_cat_other) { + if (mp_logger) { + mp_logger->match_devices_with_different_device_classes (d.operator-> (), d_other); + } + good = false; + } else { + if (mp_logger) { + mp_logger->match_devices_with_different_parameters (d.operator-> (), d_other); + } + good = false; + } + } else { + if (mp_logger) { + mp_logger->match_devices (d.operator-> (), d_other); + } + } + + } + + } + for (db::Circuit::const_device_iterator d = c1->begin_devices (); d != c1->end_devices (); ++d) { if (! device_filter.filter (d.operator-> ())) { @@ -3688,17 +3837,8 @@ NetlistComparer::do_device_assignment (const db::Circuit *c1, const db::NetGraph continue; } - std::vector > k = compute_device_key (*d, g1, device_categorizer.is_strict_device_category (device_cat)); - bool mapped = true; - for (std::vector >::iterator i = k.begin (); i != k.end (); ++i) { - if (! g1.begin () [i->second].has_other ()) { - i->second = invalid_id; // normalization - mapped = false; - } - } - - std::sort (k.begin (), k.end ()); + std::vector > k = compute_device_key_for_this (*d, g1, device_categorizer.is_strict_device_category (device_cat), mapped); if (! mapped) { if (mp_logger) { @@ -3718,52 +3858,37 @@ 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 continue; } - const db::Device *c1_device = device_eq.other (d.operator-> ()); + const db::Device *c1_device = 0; size_t c1_device_cat = 0; - if (c1_device) { + bool mapped = true; + std::vector > k = compute_device_key_for_other (*d, g2, device_categorizer.is_strict_device_category (device_cat), mapped); - c1_device_cat = device_categorizer.cat_for_device (c1_device); + 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 { - std::vector > k = compute_device_key (*d, g2, device_categorizer.is_strict_device_category (device_cat)); + c1_device = dm->second.first; + c1_device_cat = dm->second.second; - 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); - - } + device_map.erase (dm); } @@ -3878,6 +4003,42 @@ NetlistComparer::do_subcircuit_assignment (const db::Circuit *c1, const db::NetG std::multimap >, std::pair > subcircuit_map; + for (db::Circuit::const_subcircuit_iterator sc = c1->begin_subcircuits (); sc != c1->end_subcircuits (); ++sc) { + + size_t sc_cat = circuit_categorizer.cat_for_subcircuit (sc.operator-> ()); + if (! sc_cat) { + // subcircuit is ignored + continue; + } + + const db::SubCircuit *sc_other = subcircuit_eq.other (sc.operator-> ()); + if (! sc_other) { + continue; + } + + size_t sc_cat_other = circuit_categorizer.cat_for_subcircuit (sc_other); + if (! sc_cat_other) { + // subcircuit is ignored + continue; + } + + bool mapped1 = true, mapped2 = true; + std::vector > k = compute_subcircuit_key_for_this (*sc, g1, &c12_circuit_and_pin_mapping, &circuit_pin_mapper, mapped1); + std::vector > k_other = compute_subcircuit_key_for_other (*sc_other, g2, &c22_circuit_and_pin_mapping, &circuit_pin_mapper, mapped2); + + if (! mapped1 || ! mapped2 || k != k_other || sc_cat != sc_cat_other) { + if (mp_logger) { + mp_logger->subcircuit_mismatch (sc.operator-> (), sc_other); + } + good = false; + } else { + if (mp_logger) { + mp_logger->match_subcircuits (sc.operator-> (), sc_other); + } + } + + } + for (db::Circuit::const_subcircuit_iterator sc = c1->begin_subcircuits (); sc != c1->end_subcircuits (); ++sc) { size_t sc_cat = circuit_categorizer.cat_for_subcircuit (sc.operator-> ()); @@ -3890,24 +4051,15 @@ NetlistComparer::do_subcircuit_assignment (const db::Circuit *c1, const db::NetG continue; } - std::vector > k; - bool valid = compute_subcircuit_key (*sc, g1, &c12_circuit_and_pin_mapping, &circuit_pin_mapper, k); - bool mapped = true; - for (std::vector >::iterator i = k.begin (); i != k.end () && mapped; ++i) { - if (! g1.begin () [i->second].has_other ()) { - mapped = false; - } - } - - std::sort (k.begin (), k.end ()); + std::vector > k = compute_subcircuit_key_for_this (*sc, g1, &c12_circuit_and_pin_mapping, &circuit_pin_mapper, mapped); if (! mapped) { if (mp_logger) { mp_logger->subcircuit_mismatch (sc.operator-> (), 0); } good = false; - } else if (valid) { + } else if (! k.empty ()) { // TODO: report devices which cannot be distiguished topologically? subcircuit_map.insert (std::make_pair (k, std::make_pair (sc.operator-> (), sc_cat))); } @@ -3925,87 +4077,68 @@ NetlistComparer::do_subcircuit_assignment (const db::Circuit *c1, const db::NetG continue; } - const db::SubCircuit *c1_subcircuit = subcircuit_eq.other (sc.operator-> ()); + if (subcircuit_eq.other (sc.operator-> ())) { + continue; + } - if (c1_subcircuit) { + bool mapped = true; + std::vector > k = compute_subcircuit_key_for_other (*sc, g2, &c22_circuit_and_pin_mapping, &circuit_pin_mapper, mapped); + + std::multimap >, std::pair >::iterator scm = subcircuit_map.find (k); + + if (! mapped || scm == subcircuit_map.end () || scm->first != k) { if (mp_logger) { - mp_logger->match_subcircuits (c1_subcircuit, sc.operator-> ()); + unmatched_b.push_back (std::make_pair (k, sc.operator-> ())); } + good = false; } else { - std::vector > k; - compute_subcircuit_key (*sc, g2, &c22_circuit_and_pin_mapping, &circuit_pin_mapper, k); + db::SubCircuitCompare scc; - 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::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; } } - std::sort (k.begin (), k.end ()); + if (! found) { - std::multimap >, std::pair >::iterator scm = subcircuit_map.find (k); + if (nscm == 1) { - if (! mapped || scm == subcircuit_map.end ()) { + // 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 (mp_logger) { - unmatched_b.push_back (std::make_pair (k, sc.operator-> ())); } + good = false; } else { - 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; - } + if (mp_logger) { + mp_logger->match_subcircuits (scm->second.first, sc.operator-> ()); } - 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); - - } + // 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 d9748d36d..2edd6062c 100644 --- a/src/db/db/dbNetlistCompare.h +++ b/src/db/db/dbNetlistCompare.h @@ -287,6 +287,26 @@ public: return m_max_n_branch; } + /** + * @brief Sets a value indicating depth-first traversal + * + * With depth first (the default), the algorithm looks for further identities before moving to another + * node. With breadth first (false), the algorithm will work in "waves" rather than digging deerly + * into the direction of a node. + */ + void set_depth_first (bool df) + { + m_depth_first = df; + } + + /** + * @brief Gets a value indicating depth-first traversal + */ + bool depth_first () const + { + return m_depth_first; + } + /** * @brief Gets the list of circuits without matching circuit in the other netlist * The result can be used to flatten these circuits prior to compare. @@ -341,6 +361,7 @@ protected: double m_res_threshold; size_t m_max_n_branch; size_t m_max_depth; + bool m_depth_first; bool m_dont_consider_net_names; }; From 3a680eb167290786c47607698b0e16e57cb9b196 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 26 Jun 2020 01:01:11 +0200 Subject: [PATCH 3/5] WIP: preserving the order of device and subcircuit assignments for test data reuse --- src/db/db/dbNetlistCompare.cc | 294 +++++++++++++++------------------- 1 file changed, 126 insertions(+), 168 deletions(-) diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc index 5d8227a3a..18fa58682 100644 --- a/src/db/db/dbNetlistCompare.cc +++ b/src/db/db/dbNetlistCompare.cc @@ -3151,11 +3151,12 @@ compute_subcircuit_key (const db::SubCircuit &subcircuit, const db::NetGraph &g, } static std::vector > -compute_subcircuit_key_for_this (const db::SubCircuit &subcircuit, const db::NetGraph &g, const std::map *circuit_map, const CircuitPinMapper *pin_map, bool &mapped) +compute_subcircuit_key_for_this (const db::SubCircuit &subcircuit, const db::NetGraph &g, const std::map *circuit_map, const CircuitPinMapper *pin_map, bool &mapped, bool &valid) { + valid = true; std::vector > k; if (! compute_subcircuit_key (subcircuit, g, circuit_map, pin_map, k)) { - k.clear (); + valid = false; } mapped = true; @@ -3170,11 +3171,12 @@ compute_subcircuit_key_for_this (const db::SubCircuit &subcircuit, const db::Net } static std::vector > -compute_subcircuit_key_for_other (const db::SubCircuit &subcircuit, const db::NetGraph &g, const std::map *circuit_map, const CircuitPinMapper *pin_map, bool &mapped) +compute_subcircuit_key_for_other (const db::SubCircuit &subcircuit, const db::NetGraph &g, const std::map *circuit_map, const CircuitPinMapper *pin_map, bool &mapped, bool &valid) { + valid = true; std::vector > k; if (! compute_subcircuit_key (subcircuit, g, circuit_map, pin_map, k)) { - k.clear (); + valid = false; } mapped = true; @@ -3760,67 +3762,6 @@ NetlistComparer::do_device_assignment (const db::Circuit *c1, const db::NetGraph // check mapping of devices whose equivalence is established topologically - for (db::Circuit::const_device_iterator d = c1->begin_devices (); d != c1->end_devices (); ++d) { - - if (! device_filter.filter (d.operator-> ())) { - continue; - } - - const db::Device *d_other = device_eq.other (d.operator-> ()); - if (! d_other) { - continue; - } - - size_t device_cat = device_categorizer.cat_for_device (d.operator-> ()); - if (! device_cat) { - // device is ignored - continue; - } - - size_t device_cat_other = device_categorizer.cat_for_device (d_other); - if (! device_cat_other) { - // device is ignored - continue; - } - - bool mapped1 = true, mapped2 = true; - std::vector > k = compute_device_key_for_this (*d, g1, device_categorizer.is_strict_device_category (device_cat), mapped1); - std::vector > k_other = compute_device_key_for_other (*d_other, g2, device_categorizer.is_strict_device_category (device_cat_other), mapped2); - - if (! mapped1 || ! mapped2 || k != k_other) { - - // topological mismatch - if (mp_logger) { - mp_logger->device_mismatch (d.operator-> (), d_other); - } - good = false; - - } else { - - db::DeviceCompare dc; - - if (! dc.equals (std::make_pair (d.operator-> (), device_cat), std::make_pair (d_other, device_cat_other))) { - if (device_cat != device_cat_other) { - if (mp_logger) { - mp_logger->match_devices_with_different_device_classes (d.operator-> (), d_other); - } - good = false; - } else { - if (mp_logger) { - mp_logger->match_devices_with_different_parameters (d.operator-> (), d_other); - } - good = false; - } - } else { - if (mp_logger) { - mp_logger->match_devices (d.operator-> (), d_other); - } - } - - } - - } - for (db::Circuit::const_device_iterator d = c1->begin_devices (); d != c1->end_devices (); ++d) { if (! device_filter.filter (d.operator-> ())) { @@ -3858,10 +3799,6 @@ 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 @@ -3871,24 +3808,56 @@ NetlistComparer::do_device_assignment (const db::Circuit *c1, const db::NetGraph const db::Device *c1_device = 0; size_t c1_device_cat = 0; - bool mapped = true; - std::vector > k = compute_device_key_for_other (*d, g2, device_categorizer.is_strict_device_category (device_cat), mapped); + const db::Device *d_this = device_eq.other (d.operator-> ()); + if (d_this) { + + size_t device_cat_this = device_categorizer.cat_for_device (d_this); + if (! device_cat_this) { + // device is ignored + continue; + } + + bool mapped1 = true, mapped2 = true; + std::vector > k_this = compute_device_key_for_this (*d_this, g1, device_categorizer.is_strict_device_category (device_cat_this), mapped1); + std::vector > k = compute_device_key_for_other (*d, g2, device_categorizer.is_strict_device_category (device_cat), mapped2); + + if (! mapped1 || ! mapped2 || k != k_this) { + + // topological mismatch + if (mp_logger) { + mp_logger->device_mismatch (d_this, d.operator-> ()); + } + good = false; + + } else { + + c1_device = d_this; + c1_device_cat = device_cat_this; - 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; + bool mapped = true; + std::vector > k = compute_device_key_for_other (*d, g2, device_categorizer.is_strict_device_category (device_cat), mapped); - device_map.erase (dm); + 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); + + } } @@ -4003,42 +3972,6 @@ NetlistComparer::do_subcircuit_assignment (const db::Circuit *c1, const db::NetG std::multimap >, std::pair > subcircuit_map; - for (db::Circuit::const_subcircuit_iterator sc = c1->begin_subcircuits (); sc != c1->end_subcircuits (); ++sc) { - - size_t sc_cat = circuit_categorizer.cat_for_subcircuit (sc.operator-> ()); - if (! sc_cat) { - // subcircuit is ignored - continue; - } - - const db::SubCircuit *sc_other = subcircuit_eq.other (sc.operator-> ()); - if (! sc_other) { - continue; - } - - size_t sc_cat_other = circuit_categorizer.cat_for_subcircuit (sc_other); - if (! sc_cat_other) { - // subcircuit is ignored - continue; - } - - bool mapped1 = true, mapped2 = true; - std::vector > k = compute_subcircuit_key_for_this (*sc, g1, &c12_circuit_and_pin_mapping, &circuit_pin_mapper, mapped1); - std::vector > k_other = compute_subcircuit_key_for_other (*sc_other, g2, &c22_circuit_and_pin_mapping, &circuit_pin_mapper, mapped2); - - if (! mapped1 || ! mapped2 || k != k_other || sc_cat != sc_cat_other) { - if (mp_logger) { - mp_logger->subcircuit_mismatch (sc.operator-> (), sc_other); - } - good = false; - } else { - if (mp_logger) { - mp_logger->match_subcircuits (sc.operator-> (), sc_other); - } - } - - } - for (db::Circuit::const_subcircuit_iterator sc = c1->begin_subcircuits (); sc != c1->end_subcircuits (); ++sc) { size_t sc_cat = circuit_categorizer.cat_for_subcircuit (sc.operator-> ()); @@ -4051,15 +3984,15 @@ NetlistComparer::do_subcircuit_assignment (const db::Circuit *c1, const db::NetG continue; } - bool mapped = true; - std::vector > k = compute_subcircuit_key_for_this (*sc, g1, &c12_circuit_and_pin_mapping, &circuit_pin_mapper, mapped); + bool mapped = true, valid = true; + std::vector > k = compute_subcircuit_key_for_this (*sc, g1, &c12_circuit_and_pin_mapping, &circuit_pin_mapper, mapped, valid); if (! mapped) { if (mp_logger) { mp_logger->subcircuit_mismatch (sc.operator-> (), 0); } good = false; - } else if (! k.empty ()) { + } else if (valid) { // TODO: report devices which cannot be distiguished topologically? subcircuit_map.insert (std::make_pair (k, std::make_pair (sc.operator-> (), sc_cat))); } @@ -4077,68 +4010,93 @@ NetlistComparer::do_subcircuit_assignment (const db::Circuit *c1, const db::NetG continue; } - if (subcircuit_eq.other (sc.operator-> ())) { - continue; - } + const db::SubCircuit *sc_this = subcircuit_eq.other (sc.operator-> ()); + if (sc_this) { - bool mapped = true; - std::vector > k = compute_subcircuit_key_for_other (*sc, g2, &c22_circuit_and_pin_mapping, &circuit_pin_mapper, mapped); - - std::multimap >, std::pair >::iterator scm = subcircuit_map.find (k); - - if (! mapped || scm == subcircuit_map.end () || scm->first != k) { - - if (mp_logger) { - unmatched_b.push_back (std::make_pair (k, sc.operator-> ())); + size_t sc_cat_this = circuit_categorizer.cat_for_subcircuit (sc_this); + if (! sc_cat_this) { + // subcircuit is ignored + continue; + } + + bool mapped1 = true, mapped2 = true; + bool valid1 = true, valid2 = true; + std::vector > k_this = compute_subcircuit_key_for_this (*sc_this, g1, &c12_circuit_and_pin_mapping, &circuit_pin_mapper, mapped1, valid1); + std::vector > k = compute_subcircuit_key_for_other (*sc, g2, &c22_circuit_and_pin_mapping, &circuit_pin_mapper, mapped2, valid2); + + if (! valid1 || ! valid2 || ! mapped1 || ! mapped2 || k_this != k || sc_cat != sc_cat_this) { + if (mp_logger) { + mp_logger->subcircuit_mismatch (sc_this, sc.operator-> ()); + } + good = false; + } else { + if (mp_logger) { + mp_logger->match_subcircuits (sc_this, sc.operator-> ()); + } } - good = false; } else { - db::SubCircuitCompare scc; + bool mapped = true, valid = true; + std::vector > k = compute_subcircuit_key_for_other (*sc, g2, &c22_circuit_and_pin_mapping, &circuit_pin_mapper, mapped, valid); - std::multimap >, std::pair >::iterator scm_start = scm; + std::multimap >, std::pair >::iterator scm = subcircuit_map.find (k); - 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; + if (! mapped || scm == subcircuit_map.end () || scm->first != k) { + + if (mp_logger) { + unmatched_b.push_back (std::make_pair (k, sc.operator-> ())); } - } - - 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-> ()); + 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); + + } } From f3c549ca73bc2db92d958888cd0a2c175d36d9bd Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 26 Jun 2020 16:33:16 +0200 Subject: [PATCH 4/5] Net compare algorithm enhancement (pre-analsysis of node connections for shortcut) --- src/db/db/dbNetlistCompare.cc | 183 ++++++++++++++++++++++++---------- 1 file changed, 129 insertions(+), 54 deletions(-) diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc index 18fa58682..7844e4f1b 100644 --- a/src/db/db/dbNetlistCompare.cc +++ b/src/db/db/dbNetlistCompare.cc @@ -617,7 +617,7 @@ struct CompareData { CompareData () : other (0), max_depth (0), max_n_branch (0), depth_first (true), dont_consider_net_names (false), logger (0), - circuit_pin_mapper (0), subcircuit_equivalence (0), device_equivalence (0) + circuit_pin_mapper (0), subcircuit_equivalence (0), device_equivalence (0), progress (0) { } NetGraph *other; @@ -629,6 +629,7 @@ struct CompareData CircuitPinMapper *circuit_pin_mapper; SubCircuitEquivalenceTracker *subcircuit_equivalence; DeviceEquivalenceTracker *device_equivalence; + tl::RelativeProgress *progress; }; // -------------------------------------------------------------------------------------------------------------------- @@ -1921,6 +1922,8 @@ static bool edges_are_compatible (const NetGraphNode::edge_type &e, const NetGra 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) { + // NOTE: we can skip edges to known nodes because we did a pre-analysis making sure those are compatible + std::vector > nodes; nodes.reserve (ee - e); @@ -2085,18 +2088,107 @@ NetGraph::derive_node_identities (size_t net_index, size_t depth, size_t n_branc } - bool any = false; - for (NetGraphNode::edge_iterator e = n->begin (); e != n->end () && ! any; ++e) { - any = ! node (e->second.first).has_other (); + // do a pre-analysis filtering out all nodes with fully satisfied edges or which provide a contradiction + + bool analysis_required = false; + + for (NetGraphNode::edge_iterator e = n->begin (); e != n->end (); ) { + + NetGraphNode::edge_iterator ee = e; + ++ee; + + while (ee != n->end () && ee->first == e->first) { + ++ee; + } + + NetGraphNode::edge_iterator e_other = n_other->find_edge (e->first); + if (e_other != n_other->end ()) { + + NetGraphNode::edge_iterator ee_other = e_other; + ++ee_other; + + while (ee_other != n_other->end () && ee_other->first == e_other->first) { + ++ee_other; + } + + std::vector nodes; + nodes.reserve (ee - e); + + std::vector other_nodes_translated; + other_nodes_translated.reserve (ee - e); + + tl_assert (e->first == e_other->first); + + for (NetGraphNode::edge_iterator i = e; i != ee; ++i) { + if (i->second.first != net_index) { + const NetGraphNode *nn = &node (i->second.first); + if (nn->has_other ()) { + nodes.push_back (nn); + } else { + analysis_required = true; + } + } + } + + for (NetGraphNode::edge_iterator i = e_other; i != ee_other; ++i) { + if (i->second.first != other_net_index) { + const NetGraphNode *nn = &data->other->node (i->second.first); + if (nn->has_other ()) { + other_nodes_translated.push_back (&node (nn->other_net_index ())); + } else { + analysis_required = true; + } + } + } + + std::sort (nodes.begin (), nodes.end ()); + std::sort (other_nodes_translated.begin (), other_nodes_translated.end ()); + + // No fit, we can shortcut + if (nodes != other_nodes_translated) { + return tentative ? failed_match : 0; + } + + } else if (tentative) { + // in tentative mode an exact match is required: no having the same edges for a node disqualifies the node + // as matching. + return failed_match; + } + + e = ee; + } - for (NetGraphNode::edge_iterator e = n_other->begin (); e != n_other->end () && ! any; ++e) { - any = ! data->other->node (e->second.first).has_other (); + + if (tentative) { + + // in tentative mode, again an exact match is required + + for (NetGraphNode::edge_iterator e_other = n_other->begin (); e_other != n_other->end (); ) { + + NetGraphNode::edge_iterator ee_other = e_other; + ++ee_other; + + while (ee_other != n_other->end () && ee_other->first == e_other->first) { + ++ee_other; + } + + NetGraphNode::edge_iterator e = n->find_edge (e_other->first); + if (e == n->end ()) { + return failed_match; + } + + e_other = ee_other; + + } + } - if (! any) { - // all target nodes are satisfied - skip + + if (! analysis_required) { return 0; } + // do a detailed analysis + size_t new_nodes = 0; if (options ()->debug_netcompare) { @@ -2139,46 +2231,12 @@ NetGraph::derive_node_identities (size_t net_index, size_t depth, size_t n_branc new_nodes += bt_count; } - } else if (tentative) { - // in tentative mode an exact match is required: no having the same edges for a node disqualifies the node - // as matching. - if (options ()->debug_netcompare) { - tl::info << indent(depth) << "=> rejected pair for missing edge."; - } - return failed_match; } e = ee; } - if (tentative) { - - // in tentative mode, again an exact match is required - - for (NetGraphNode::edge_iterator e_other = n_other->begin (); e_other != n_other->end (); ) { - - NetGraphNode::edge_iterator ee_other = e_other; - ++ee_other; - - while (ee_other != n_other->end () && ee_other->first == e_other->first) { - ++ee_other; - } - - NetGraphNode::edge_iterator e = n->find_edge (e_other->first); - if (e == n->end ()) { - if (options ()->debug_netcompare) { - tl::info << indent(depth) << "=> rejected pair for missing edge."; - } - return failed_match; - } - - e_other = ee_other; - - } - - } - if (options ()->debug_netcompare) { if (! tentative && new_nodes > 0) { tl::info << indent(depth) << "=> finished pair deduction: " << n->net ()->expanded_name () << " vs. " << n_other->net ()->expanded_name () << " with " << new_nodes << " new pairs"; @@ -2320,12 +2378,15 @@ NetGraph::derive_node_identities_from_node_set (std::vectordebug_netcompare) { 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 (n->net (), n_other->net ()); - } else { - data->logger->match_nets (n->net (), n_other->net ()); + if (! tentative) { + ++*data->progress; + if (data->logger) { + 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 (n->net (), n_other->net ()); + } else { + data->logger->match_nets (n->net (), n_other->net ()); + } } } @@ -2492,12 +2553,15 @@ NetGraph::derive_node_identities_from_node_set (std::vectordebug_netcompare) { 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->first->net (), nr->n2->first->net ()); - } else { - data->logger->match_nets (nr->n1->first->net (), nr->n2->first->net ()); + if (! tentative) { + ++*data->progress; + if (data->logger) { + if (! (node (ni) == data->other->node (other_ni))) { + // this is a mismatch, but we continue with this + data->logger->net_mismatch (nr->n1->first->net (), nr->n2->first->net ()); + } else { + data->logger->match_nets (nr->n1->first->net (), nr->n2->first->net ()); + } } } @@ -2670,6 +2734,7 @@ NetGraph::derive_node_identities_from_node_set (std::vectorfirst->net ()->expanded_name () << " vs. " << p->second->net ()->expanded_name (); } } + if (data->logger) { bool ambiguous = equivalent_other_nodes.has_attribute (p->second); if (ambiguous) { @@ -2679,6 +2744,8 @@ NetGraph::derive_node_identities_from_node_set (std::vectorprogress; + } // And seek further from these pairs @@ -2944,6 +3011,8 @@ NetlistComparer::compare (const db::Netlist *a, const db::Netlist *b) const std::map c12_pin_mapping, c22_pin_mapping; + tl::RelativeProgress progress (tl::to_string (tr ("Comparing netlists")), a->circuit_count (), 1); + for (db::Netlist::const_bottom_up_circuit_iterator c = a->begin_bottom_up (); c != a->end_bottom_up (); ++c) { const db::Circuit *ca = c.operator-> (); @@ -3007,6 +3076,8 @@ NetlistComparer::compare (const db::Netlist *a, const db::Netlist *b) const } + ++progress; + } if (mp_logger) { @@ -3371,6 +3442,8 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, int iter = 0; + tl::RelativeProgress progress (tl::to_string (tr ("Comparing circuits ")) + c1->name () + "/" + c2->name (), std::max (g1.end () - g1.begin (), g2.end () - g2.begin ()), 1); + // two passes: one without ambiguities, the second one with bool good = false; @@ -3408,6 +3481,7 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, data.subcircuit_equivalence = &subcircuit_equivalence; data.device_equivalence = &device_equivalence; data.logger = mp_logger; + data.progress = &progress; size_t ni = g1.derive_node_identities (i1 - g1.begin (), 0, 1, 0 /*not tentative*/, pass > 0 /*with ambiguities*/, &data); if (ni > 0 && ni != failed_match) { @@ -3473,6 +3547,7 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, data.subcircuit_equivalence = &subcircuit_equivalence; data.device_equivalence = &device_equivalence; data.logger = mp_logger; + data.progress = &progress; 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) { From acdca4bc7321cee2c3e63fb2723d03e0fbf407fc Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 26 Jun 2020 16:54:26 +0200 Subject: [PATCH 5/5] Updated testdata, added tests for breadth-first compare mode --- src/db/unit_tests/dbNetlistCompareTests.cc | 248 ++++++++++++++++++++- testdata/lvs/ringo_simple_dmos.lvsdb.1 | 6 +- 2 files changed, 246 insertions(+), 8 deletions(-) diff --git a/src/db/unit_tests/dbNetlistCompareTests.cc b/src/db/unit_tests/dbNetlistCompareTests.cc index 8d50548aa..718d85ffd 100644 --- a/src/db/unit_tests/dbNetlistCompareTests.cc +++ b/src/db/unit_tests/dbNetlistCompareTests.cc @@ -1147,8 +1147,8 @@ TEST(5_BufferTwoPathsDifferentDeviceClasses) "begin_circuit BUF BUF\n" "match_nets INT $10\n" "match_nets IN IN\n" - "net_mismatch OUT OUT\n" "net_mismatch INT2 $11\n" + "net_mismatch OUT OUT\n" "match_pins $0 $1\n" "match_pins $1 $3\n" "match_pins $2 $0\n" @@ -1212,8 +1212,35 @@ TEST(6_BufferTwoPathsAdditionalResistor) "begin_circuit BUF BUF\n" "net_mismatch INT $10\n" "match_nets IN IN\n" + "net_mismatch INT2 $11\n" + "match_nets OUT OUT\n" + "match_pins $0 $1\n" + "match_pins $1 $3\n" + "match_pins $2 $0\n" + "match_pins $3 $2\n" + "match_devices $1 $1\n" + "match_devices $3 $2\n" + "match_devices $5 $3\n" + "match_devices $7 $4\n" + "match_devices $2 $5\n" + "match_devices $4 $6\n" + "match_devices $6 $7\n" + "match_devices $8 $8\n" + "device_mismatch (null) $9\n" + "end_circuit BUF BUF NOMATCH" + ); + EXPECT_EQ (good, false); + + comp.set_depth_first (false); + logger.clear (); + good = comp.compare (&nl1, &nl2); + + EXPECT_EQ (logger.text (), + "begin_circuit BUF BUF\n" + "net_mismatch INT $10\n" "match_nets OUT OUT\n" "net_mismatch INT2 $11\n" + "match_nets IN IN\n" "match_pins $0 $1\n" "match_pins $1 $3\n" "match_pins $2 $0\n" @@ -1274,9 +1301,9 @@ TEST(6_BufferTwoPathsAdditionalDevices) "match_nets INT $11\n" "net_mismatch VDD VDD\n" "match_nets IN IN\n" + "net_mismatch INT2 $10\n" "net_mismatch VSS VSS\n" "net_mismatch OUT OUT\n" - "net_mismatch INT2 $10\n" "match_pins $0 $1\n" "match_pins $1 $3\n" "match_pins $2 $0\n" @@ -2679,6 +2706,57 @@ TEST(17_InherentlyAmbiguousDecoder) ); EXPECT_EQ (good, true); + + comp.set_depth_first (false); + logger.clear (); + good = comp.compare (&nl1, &nl2); + + EXPECT_EQ (logger.text (), + "begin_circuit NAND NAND\n" + "match_nets VSS VSS\n" + "match_nets INT INT\n" + "match_nets OUT OUT\n" + "match_nets VDD VDD\n" + "match_nets B B\n" + "match_nets A A\n" + "match_pins $0 $0\n" + "match_pins $1 $1\n" + "match_pins $2 $2\n" + "match_pins $3 $3\n" + "match_pins $4 $4\n" + "match_devices $1 $1\n" + "match_devices $2 $2\n" + "match_devices $3 $3\n" + "match_devices $4 $4\n" + "end_circuit NAND NAND MATCH\n" + "begin_circuit DECODER DECODER\n" + "match_nets VSS VSS\n" + "match_nets VDD VDD\n" + "match_nets NA NA\n" + "match_nets NB NB\n" + "match_nets B B\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" + "match_pins $3 $3\n" + "match_pins $4 $4\n" + "match_pins $5 $5\n" + "match_pins $6 $6\n" + "match_pins $7 $7\n" + "match_subcircuits $1 $1\n" + "match_subcircuits $2 $2\n" + "match_subcircuits $4 $3\n" + "match_subcircuits $6 $4\n" + "match_subcircuits $3 $5\n" + "match_subcircuits $5 $6\n" + "end_circuit DECODER DECODER MATCH" + ); + + EXPECT_EQ (good, true); } TEST(18_ClockTree) @@ -2794,6 +2872,67 @@ TEST(18_ClockTree) "end_circuit TXEE TXEE MATCH" ); EXPECT_EQ (good, true); + + comp.set_depth_first (false); + logger.clear (); + good = comp.compare (&nl1, &nl2); + + txt = logger.text (); + // because L/R matching is ambiguous, we need to do this to + // establish reproducability on different platforms: + txt = tl::replaced (txt, "L", "X"); + txt = tl::replaced (txt, "R", "X"); + + EXPECT_EQ (txt, + "begin_circuit INV INV\n" + "match_nets VDD VDD\n" + "match_nets OUT OUT\n" + "match_nets IN IN\n" + "match_nets VSS VSS\n" + "match_pins IN IN\n" + "match_pins OUT OUT\n" + "match_pins VDD VDD\n" + "match_pins VSS VSS\n" + "match_devices $1 $1\n" + "match_devices $2 $2\n" + "end_circuit INV INV MATCH\n" + "begin_circuit TXEE TXEE\n" + "match_nets IN IN\n" + "match_nets VSS VSS\n" + "match_nets VDD VDD\n" + "match_nets S S\n" + "match_ambiguous_nets SX SX\n" + "match_ambiguous_nets SX SX\n" + "match_ambiguous_nets SXX SXX\n" + "match_ambiguous_nets SXX SXX\n" + "match_ambiguous_nets SXXX SXXX\n" + "match_ambiguous_nets SXXX SXXX\n" + "match_ambiguous_nets SXXX SXXX\n" + "match_ambiguous_nets SXXX SXXX\n" + "match_ambiguous_nets SXX SXX\n" + "match_ambiguous_nets SXX SXX\n" + "match_ambiguous_nets SXXX SXXX\n" + "match_ambiguous_nets SXXX SXXX\n" + "match_ambiguous_nets SXXX SXXX\n" + "match_ambiguous_nets SXXX SXXX\n" + "match_subcircuits TXXX TXXX\n" + "match_subcircuits TX TX\n" + "match_subcircuits TXXX TXXX\n" + "match_subcircuits TXXX TXXX\n" + "match_subcircuits TXX TXX\n" + "match_subcircuits TXX TXX\n" + "match_subcircuits TXXX TXXX\n" + "match_subcircuits TXXX TXXX\n" + "match_subcircuits TXXX TXXX\n" + "match_subcircuits T T\n" + "match_subcircuits TXXX TXXX\n" + "match_subcircuits TX TX\n" + "match_subcircuits TXX TXX\n" + "match_subcircuits TXXX TXXX\n" + "match_subcircuits TXX TXX\n" + "end_circuit TXEE TXEE MATCH" + ); + EXPECT_EQ (good, true); } TEST(19_SymmetricCircuit) @@ -2924,8 +3063,8 @@ TEST(19_SymmetricCircuit) "match_nets $14 WELL\n" "match_nets nn2 NN2\n" "match_nets nn2_ NN2_\n" - "match_nets q0 Q0\n" - "match_nets q1 Q1\n" + "match_ambiguous_nets q0 Q0\n" + "match_ambiguous_nets q1 Q1\n" "match_nets $11 CS0\n" "match_nets q0_ Q0_\n" "match_nets $6 NET181\n" @@ -3002,6 +3141,105 @@ TEST(19_SymmetricCircuit) "end_circuit DECODE DECODE MATCH" ); EXPECT_EQ (good, true); + + comp.set_depth_first (false); + logger.clear (); + good = comp.compare (&nl1, &nl2); + + EXPECT_EQ (logger.text (), + "begin_circuit DECODE DECODE\n" + "match_nets $41 WL1_EN_\n" + "match_nets VDD VDD\n" + "match_nets $39 NET194\n" + "match_nets g0 G0\n" + "match_nets $40 HNET52\n" + "match_nets VSS VSS\n" + "match_nets $42 NET189\n" + "match_nets gtp NN3\n" + "match_nets $37 NET193\n" + "match_nets g1 G1\n" + "match_nets $44 YI\n" + "match_nets $14 WELL\n" + "match_nets nn2 NN2\n" + "match_nets nn2_ NN2_\n" + "match_ambiguous_nets q0 Q0\n" + "match_ambiguous_nets q1 Q1\n" + "match_nets $11 CS0\n" + "match_nets q0_ Q0_\n" + "match_nets $4 NET200\n" + "match_nets $13 CS1\n" + "match_nets q1_ Q1_\n" + "match_nets $9 NET175\n" + "match_nets a0 A0\n" + "match_nets a0_ A0_\n" + "match_nets $35 HNET44\n" + "match_nets $34 HNET48\n" + "match_nets $6 NET181\n" + "match_nets $8 NET215\n" + "match_nets nn1 NN1\n" + "match_nets nn1_ NN1_\n" + "match_pins VDD VDD\n" + "match_pins nn1_ NN1_\n" + "match_pins nn1 NN1\n" + "match_pins q0 Q0\n" + "match_pins q0_ Q0_\n" + "match_pins q1_ Q1_\n" + "match_pins q1 Q1\n" + "match_pins nn2 NN2\n" + "match_pins nn2_ NN2_\n" + "match_pins a0 A0\n" + "match_pins a0_ A0_\n" + "match_pins g1 G1\n" + "match_pins g0 G0\n" + "match_pins gtp NN3\n" + "match_pins VSS VSS\n" + "match_pins WELL WELL\n" + "match_devices $30 0\n" + "match_devices $29 1\n" + "match_devices $9 10\n" + "match_devices $10 11\n" + "match_devices $36 12\n" + "match_devices $35 13\n" + "match_devices $34 14\n" + "match_devices $38 15\n" + "match_devices $37 16\n" + "match_devices $33 17\n" + "match_devices $27 18\n" + "match_devices $28 19\n" + "match_devices $17 2\n" + "match_devices $31 20\n" + "match_devices $32 21\n" + "match_devices $22 22\n" + "match_devices $26 23\n" + "match_devices $23 24\n" + "match_devices $43 25\n" + "match_devices $20 26\n" + "match_devices $25 27\n" + "match_devices $15 28\n" + "match_devices $14 29\n" + "match_devices $16 3\n" + "match_devices $18 30\n" + "match_devices $21 31\n" + "match_devices $13 32\n" + "match_devices $19 33\n" + "match_devices $7 34\n" + "match_devices $8 35\n" + "match_devices $24 36\n" + "match_devices $3 37\n" + "match_devices $6 38\n" + "match_devices $4 39\n" + "match_devices $39 4\n" + "match_devices $5 40\n" + "match_devices $2 41\n" + "match_devices $1 42\n" + "match_devices $40 5\n" + "match_devices $11 6\n" + "match_devices $12 7\n" + "match_devices $41 8\n" + "match_devices $42 9\n" + "end_circuit DECODE DECODE MATCH" + ); + EXPECT_EQ (good, true); } TEST(20_BusLikeConnections) @@ -3576,7 +3814,7 @@ TEST(23_NodesRemovedWithError) "pin_mismatch (null) BULK\n" "pin_mismatch (null) $6\n" "match_subcircuits $1 $1\n" - "match_subcircuits $2 $2\n" + "subcircuit_mismatch $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 5af17e7b3..f68490049 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 match + circuit(ND2X1 ND2X1 nomatch 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(3 3 mismatch) device(4 4 match) - device(1 1 match) device(2 2 match) + device(1 1 mismatch) ) ) circuit(RINGO RINGO match