From fb2611632d7c17bd5a1b9178e75178424571e815 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 17 Dec 2019 21:16:29 +0100 Subject: [PATCH 1/6] Some performance improvement of net extractor. --- src/db/db/dbHierNetworkProcessor.cc | 30 +++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/db/db/dbHierNetworkProcessor.cc b/src/db/db/dbHierNetworkProcessor.cc index c19f12dc1..8f5f74fda 100644 --- a/src/db/db/dbHierNetworkProcessor.cc +++ b/src/db/db/dbHierNetworkProcessor.cc @@ -1023,15 +1023,21 @@ connected_clusters::join_cluster_with (typename local_cluster::id_type id, // handle the connections by translating - const connections_type &to_join = connections_for_cluster (with_id); - connections_type &target = m_connections [id]; - target.insert (target.end (), to_join.begin (), to_join.end ()); + typename std::map::id_type, connections_type>::iterator tc = m_connections.find (with_id); + if (tc != m_connections.end ()) { + + connections_type &to_join = tc->second; + + for (connections_type::const_iterator c = to_join.begin (); c != to_join.end (); ++c) { + m_rev_connections [*c] = id; + } + + connections_type &target = m_connections [id]; + target.splice (target.end (), to_join, to_join.begin (), to_join.end ()); + + m_connections.erase (tc); - for (connections_type::const_iterator c = to_join.begin (); c != to_join.end (); ++c) { - m_rev_connections [*c] = id; } - - m_connections.erase (with_id); } template @@ -1773,11 +1779,8 @@ private: const ClusterInstance &k2 = ic->second; // Note: "with_self" is false as we're going to create a connected cluster anyway - mp_tree->propagate_cluster_inst (*mp_layout, *mp_cell, k1, mp_cell->cell_index (), false); - mp_tree->propagate_cluster_inst (*mp_layout, *mp_cell, k2, mp_cell->cell_index (), false); - - id_type x1 = mp_cell_clusters->find_cluster_with_connection (k1); - id_type x2 = mp_cell_clusters->find_cluster_with_connection (k2); + id_type x1 = mp_tree->propagate_cluster_inst (*mp_layout, *mp_cell, k1, mp_cell->cell_index (), false); + id_type x2 = mp_tree->propagate_cluster_inst (*mp_layout, *mp_cell, k2, mp_cell->cell_index (), false); if (x1 == 0) { @@ -2228,9 +2231,8 @@ hier_clusters::build_hier_connections (cell_clusters_box_converter &cbc, c } else { // ensures the cluster is propagated so we can connect it with another - propagate_cluster_inst (layout, cell, *i, cell.cell_index (), false); + size_t other_id = propagate_cluster_inst (layout, cell, *i, cell.cell_index (), false); - size_t other_id = local.find_cluster_with_connection (*i); if (other_id == gcid) { // shouldn't happen, but duplicate instances may trigger this } else if (other_id) { From a9bd037b584950adf40aacd7629c79764a96cde9 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 17 Dec 2019 22:23:43 +0100 Subject: [PATCH 2/6] Some code cleanup with performance impact --- src/db/db/dbBoxScanner.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/db/db/dbBoxScanner.h b/src/db/db/dbBoxScanner.h index eefd7df5a..32ab34bc0 100644 --- a/src/db/db/dbBoxScanner.h +++ b/src/db/db/dbBoxScanner.h @@ -419,7 +419,6 @@ private: for (iterator_type j = c; j < i; ++j) { if (bs_boxes_overlap (bc (*i->first), bc (*j->first), enl)) { if (seen.insert (std::make_pair (i->first, j->first)).second) { - seen.insert (std::make_pair (j->first, i->first)); rec.add (i->first, i->second, j->first, j->second); if (rec.stop ()) { return false; From fcba0018bae64c7ae4bf85c0364b670f93f775e8 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 17 Dec 2019 22:38:17 +0100 Subject: [PATCH 3/6] Enhanced progress estimation of box scanner - no progress jumping back and forth. --- src/db/db/dbBoxScanner.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/db/db/dbBoxScanner.h b/src/db/db/dbBoxScanner.h index 32ab34bc0..95b1270ec 100644 --- a/src/db/db/dbBoxScanner.h +++ b/src/db/db/dbBoxScanner.h @@ -415,6 +415,11 @@ private: } while (f != future && bc (*f->first).left () == xx); } while (f != future && f - c < min_box_size); + if (m_report_progress) { + // Note: there is no better estimation of the progress than "current" ... + progress->set (current - m_pp.begin ()); + } + for (iterator_type i = f0; i != f; ++i) { for (iterator_type j = c; j < i; ++j) { if (bs_boxes_overlap (bc (*i->first), bc (*j->first), enl)) { @@ -430,10 +435,6 @@ private: x = xx; - if (m_report_progress) { - progress->set (f - m_pp.begin ()); - } - } y = yy; From 297f37a63a53635b29e8369622764d84c176c8c4 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 18 Dec 2019 01:10:16 +0100 Subject: [PATCH 4/6] Huge performance improvement for a specific array element interaction. Reason: duplicate cluster interactions spoiled performance. --- src/db/db/dbHierNetworkProcessor.cc | 29 ++++++++++++++-- src/lay/lay/layMainWindow.cc | 27 +++------------ src/lay/lay/layProgressWidget.cc | 51 ++++++++++++++++++++--------- src/lay/lay/layProgressWidget.h | 11 ++++--- src/tl/tl/tlProgress.cc | 12 ++++--- src/tl/tl/tlProgress.h | 2 +- 6 files changed, 82 insertions(+), 50 deletions(-) diff --git a/src/db/db/dbHierNetworkProcessor.cc b/src/db/db/dbHierNetworkProcessor.cc index 8f5f74fda..1bb053cbc 100644 --- a/src/db/db/dbHierNetworkProcessor.cc +++ b/src/db/db/dbHierNetworkProcessor.cc @@ -1167,6 +1167,11 @@ public: : cluster_id (_cluster_id), other_ci (_other_ci) { } + bool operator== (const ClusterInstanceInteraction &other) const + { + return cluster_id == other.cluster_id && other_ci == other.other_ci; + } + size_t cluster_id; ClusterInstance other_ci; }; @@ -1211,6 +1216,7 @@ public: db::ICplxTrans t; consider_cluster_instance_pair (*c1, *i2, t, ic); + ic.unique (); m_ci_interactions.splice (m_ci_interactions.end (), ic, ic.begin (), ic.end ()); } @@ -1411,6 +1417,8 @@ private: for (std::list >::iterator i = ii_interactions.begin (); i != ii_interactions.end (); ++i) { propagate_cluster_inst (i->second, i2.cell_index (), i2t, i2.prop_id ()); } + + ii_interactions.unique (); interacting_clusters.splice (interacting_clusters.end (), ii_interactions, ii_interactions.begin (), ii_interactions.end ()); } @@ -1436,6 +1444,8 @@ private: for (std::list >::iterator i = ii_interactions.begin (); i != ii_interactions.end (); ++i) { propagate_cluster_inst (i->first, i1.cell_index (), i1t, i1.prop_id ()); } + + ii_interactions.unique (); interacting_clusters.splice (interacting_clusters.end (), ii_interactions, ii_interactions.begin (), ii_interactions.end ()); } @@ -1448,15 +1458,28 @@ private: } - cluster_instance_pair_list_type &cached = (*mp_instance_interaction_cache) [ii_key]; - cached = interacting_clusters; + // remove duplicates (after doing a quick unique before) + // NOTE: duplicates may happen due to manifold child/child interactions which boil down to + // identical parent cluster interactions. + std::vector > sorted_interactions; + sorted_interactions.reserve (interacting_clusters.size ()); + sorted_interactions.insert (sorted_interactions.end (), interacting_clusters.begin (), interacting_clusters.end ()); + interacting_clusters.clear (); + std::sort (sorted_interactions.begin (), sorted_interactions.end ()); + sorted_interactions.erase (std::unique (sorted_interactions.begin (), sorted_interactions.end ()), sorted_interactions.end ()); + + // return the list of unique interactions + interacting_clusters.insert (interacting_clusters.end (), sorted_interactions.begin (), sorted_interactions.end ()); // normalize transformations in cache db::ICplxTrans i1ti = i1t.inverted (), i2ti = i2t.inverted (); - for (std::list >::iterator i = cached.begin (); i != cached.end (); ++i) { + for (std::vector >::iterator i = sorted_interactions.begin (); i != sorted_interactions.end (); ++i) { i->first.transform (i1ti); i->second.transform (i2ti); } + + cluster_instance_pair_list_type &cached = (*mp_instance_interaction_cache) [ii_key]; + cached.insert (cached.end (), sorted_interactions.begin (), sorted_interactions.end ()); } /** diff --git a/src/lay/lay/layMainWindow.cc b/src/lay/lay/layMainWindow.cc index 0a3924964..682f20c84 100644 --- a/src/lay/lay/layMainWindow.cc +++ b/src/lay/lay/layMainWindow.cc @@ -136,19 +136,9 @@ public: } } - void set_can_cancel (bool f) + void set_progress (tl::Progress *progress) { - mp_progress_widget->set_can_cancel (f); - } - - void set_text (const std::string &text) - { - mp_progress_widget->set_text (text); - } - - void set_value (double v, const std::string &value) - { - mp_progress_widget->set_value (v, value); + mp_progress_widget->set_progress (progress); } void add_widget (QWidget *widget) @@ -4732,23 +4722,14 @@ MainWindow::progress_get_widget () const bool MainWindow::update_progress (tl::Progress *progress) { - bool can_cancel = progress->can_cancel (); - std::string text = progress->desc (); - std::string value = progress->formatted_value (); - double v = progress->value (); - if (mp_progress_dialog) { - mp_progress_dialog->set_can_cancel (can_cancel); - mp_progress_dialog->set_text (text); - mp_progress_dialog->set_value (v, value); + mp_progress_dialog->set_progress (progress); return true; } else if (isVisible () && mp_progress_widget) { - mp_progress_widget->set_can_cancel (can_cancel); - mp_progress_widget->set_text (text); - mp_progress_widget->set_value (v, value); + mp_progress_widget->set_progress (progress); return true; } else { diff --git a/src/lay/lay/layProgressWidget.cc b/src/lay/lay/layProgressWidget.cc index 09ce42b5a..7b924b1d4 100644 --- a/src/lay/lay/layProgressWidget.cc +++ b/src/lay/lay/layProgressWidget.cc @@ -43,7 +43,7 @@ public: QSize sizeHint () const { - return QSize (m_width, 1); + return QSize (m_width, 20); } QSize minimumSizeHint () const @@ -165,12 +165,16 @@ ProgressWidget::ProgressWidget (ProgressReporter *pr, QWidget *parent, bool full layout->addWidget (progress_bar_frame, 0, col, 1, 1); layout->setColumnStretch(col++, 2); - QHBoxLayout *pbf_layout = new QHBoxLayout (progress_bar_frame); + QVBoxLayout *pbf_layout = new QVBoxLayout (progress_bar_frame); progress_bar_frame->setLayout (pbf_layout); pbf_layout->setMargin (0); - mp_progress_bar = new ProgressBarWidget (progress_bar_frame); - pbf_layout->addWidget (mp_progress_bar); + mp_progress_bar1 = new ProgressBarWidget (progress_bar_frame); + pbf_layout->addWidget (mp_progress_bar1); + mp_progress_bar2 = new ProgressBarWidget (progress_bar_frame); + pbf_layout->addWidget (mp_progress_bar2); + mp_progress_bar3 = new ProgressBarWidget (progress_bar_frame); + pbf_layout->addWidget (mp_progress_bar3); layout->addItem (new QSpacerItem (8, 8, QSizePolicy::Fixed, QSizePolicy::Fixed), 0, col++, 1, 1); @@ -218,21 +222,38 @@ ProgressWidget::remove_widget () } void -ProgressWidget::set_can_cancel (bool f) +ProgressWidget::set_progress (tl::Progress *progress) { - mp_cancel_button->setEnabled (f); -} + bool can_cancel = false; + std::string text; -void -ProgressWidget::set_text (const std::string &text) -{ + if (progress) { + can_cancel = progress->can_cancel (); + text = progress->desc (); + } + + mp_cancel_button->setEnabled (can_cancel); mp_label->setText (tl::to_qstring (text)); -} -void -ProgressWidget::set_value (double v, const std::string &value) -{ - mp_progress_bar->set_value (v, value); + lay::ProgressBarWidget *progress_bars[] = { mp_progress_bar1, mp_progress_bar2, mp_progress_bar3 }; + + for (size_t i = 0; i < sizeof (progress_bars) / sizeof (progress_bars[0]); ++i) { + + lay::ProgressBarWidget *pb = progress_bars[i]; + pb->setVisible (progress != 0); + + if (progress) { + + std::string value = progress->formatted_value (); + double v = progress->value (); + pb->set_value (v, value); + + progress = progress->next (); + + } + + } + } void diff --git a/src/lay/lay/layProgressWidget.h b/src/lay/lay/layProgressWidget.h index 976e799fd..66446cea5 100644 --- a/src/lay/lay/layProgressWidget.h +++ b/src/lay/lay/layProgressWidget.h @@ -37,6 +37,11 @@ class QLabel; class QToolButton; class QGridLayout; +namespace tl +{ + class Progress; +} + namespace lay { @@ -50,9 +55,7 @@ Q_OBJECT public: ProgressWidget (ProgressReporter *pr, QWidget *parent, bool full_width = false); - void set_text (const std::string &text); - void set_value (double v, const std::string &value); - void set_can_cancel (bool f); + void set_progress (tl::Progress *progress); void add_widget (QWidget *widget); void remove_widget (); QWidget *get_widget () const; @@ -64,7 +67,7 @@ public slots: private: QLabel *mp_label; - ProgressBarWidget *mp_progress_bar; + ProgressBarWidget *mp_progress_bar1, *mp_progress_bar2, *mp_progress_bar3; QWidget *mp_widget; int m_widget_col; QGridLayout *mp_layout; diff --git a/src/tl/tl/tlProgress.cc b/src/tl/tl/tlProgress.cc index 4a8fbf85e..031bf22f7 100644 --- a/src/tl/tl/tlProgress.cc +++ b/src/tl/tl/tlProgress.cc @@ -148,8 +148,7 @@ Progress::set_desc (const std::string &d) } } -void -Progress::test (bool force_yield) +bool Progress::test(bool force_yield) { if (++m_interval_count >= m_yield_interval || force_yield) { @@ -180,6 +179,10 @@ Progress::test (bool force_yield) throw tl::BreakException (); } + return true; + + } else { + return false; } } @@ -222,8 +225,9 @@ RelativeProgress & RelativeProgress::set (size_t count, bool force_yield) { m_count = count; - test (force_yield || m_count - m_last_count >= m_unit); - m_last_count = m_count; + if (test (force_yield || m_count - m_last_count >= m_unit)) { + m_last_count = m_count; + } return *this; } diff --git a/src/tl/tl/tlProgress.h b/src/tl/tl/tlProgress.h index d5a3fb2b8..40323dd94 100644 --- a/src/tl/tl/tlProgress.h +++ b/src/tl/tl/tlProgress.h @@ -203,7 +203,7 @@ protected: * This method must be called by the derived class. * If "force_yield" is true, the events are always processed. */ - void test (bool force_yield = false); + bool test (bool force_yield = false); /** * @brief This method needs to be called by all derived classes after initialization has happened From d9236a398f932929a36f7c244da833f25649ea66 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 18 Dec 2019 02:19:15 +0100 Subject: [PATCH 5/6] Multiple progress bars enabled. --- src/lay/lay/layProgressWidget.cc | 46 +++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/src/lay/lay/layProgressWidget.cc b/src/lay/lay/layProgressWidget.cc index 7b924b1d4..58d8306c9 100644 --- a/src/lay/lay/layProgressWidget.cc +++ b/src/lay/lay/layProgressWidget.cc @@ -25,6 +25,7 @@ #include #include +#include #include @@ -34,22 +35,15 @@ namespace lay // -------------------------------------------------------------------- class ProgressBarWidget - : public QWidget + : public QWidget { public: ProgressBarWidget (QWidget *parent, const char *name = ""); void set_value (double v, const std::string &value); - QSize sizeHint () const - { - return QSize (m_width, 20); - } - - QSize minimumSizeHint () const - { - return QSize (m_width, 1); - } + QSize sizeHint () const; + QSize minimumSizeHint () const; private: double m_value; @@ -69,6 +63,7 @@ ProgressBarWidget::ProgressBarWidget (QWidget *parent, const char *name) { setObjectName (QString::fromUtf8 (name)); setMinimumSize (64, 10); + setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding); } void @@ -90,6 +85,19 @@ ProgressBarWidget::set_value (double v, const std::string &value) } } +QSize +ProgressBarWidget::sizeHint () const +{ + QFontMetrics fm (font ()); + return QSize (m_width, fm.height () + 2); +} + +QSize +ProgressBarWidget::minimumSizeHint () const +{ + return QSize (m_width, 1); +} + void ProgressBarWidget::paintEvent (QPaintEvent *) { @@ -161,20 +169,21 @@ ProgressWidget::ProgressWidget (ProgressReporter *pr, QWidget *parent, bool full QFrame *progress_bar_frame = new QFrame (bar_frame); progress_bar_frame->setFrameStyle (QFrame::Box | QFrame::Plain); - progress_bar_frame->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Preferred); + progress_bar_frame->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding); layout->addWidget (progress_bar_frame, 0, col, 1, 1); layout->setColumnStretch(col++, 2); - QVBoxLayout *pbf_layout = new QVBoxLayout (progress_bar_frame); + QGridLayout *pbf_layout = new QGridLayout (progress_bar_frame); progress_bar_frame->setLayout (pbf_layout); pbf_layout->setMargin (0); + pbf_layout->setSpacing (0); mp_progress_bar1 = new ProgressBarWidget (progress_bar_frame); - pbf_layout->addWidget (mp_progress_bar1); + pbf_layout->addWidget (mp_progress_bar1, 0, 0, 1, 1); mp_progress_bar2 = new ProgressBarWidget (progress_bar_frame); - pbf_layout->addWidget (mp_progress_bar2); + pbf_layout->addWidget (mp_progress_bar2, 1, 0, 1, 1); mp_progress_bar3 = new ProgressBarWidget (progress_bar_frame); - pbf_layout->addWidget (mp_progress_bar3); + pbf_layout->addWidget (mp_progress_bar3, 2, 0, 1, 1); layout->addItem (new QSpacerItem (8, 8, QSizePolicy::Fixed, QSizePolicy::Fixed), 0, col++, 1, 1); @@ -240,20 +249,25 @@ ProgressWidget::set_progress (tl::Progress *progress) for (size_t i = 0; i < sizeof (progress_bars) / sizeof (progress_bars[0]); ++i) { lay::ProgressBarWidget *pb = progress_bars[i]; - pb->setVisible (progress != 0); if (progress) { + pb->show (); + std::string value = progress->formatted_value (); double v = progress->value (); pb->set_value (v, value); progress = progress->next (); + } else { + pb->hide (); } } + // according to the doc this should not be required, but without, the progress bar does not resize + mp_progress_bar1->parentWidget ()->updateGeometry (); } void From 6a474377029751c50c0a8c46d608cde24cd93452 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 18 Dec 2019 17:28:46 +0100 Subject: [PATCH 6/6] Updated test data. --- .../algo/device_extract_au2_with_rec_nets.gds | Bin 38230 -> 38242 bytes .../algo/device_extract_au3_with_rec_nets.gds | Bin 46966 -> 46974 bytes .../algo/device_extract_au4_with_rec_nets.gds | Bin 49526 -> 49534 bytes .../device_extract_au5_flattened_circuits.gds | Bin 114198 -> 114206 bytes .../algo/device_extract_au5_with_rec_nets.gds | Bin 70670 -> 70678 bytes testdata/algo/hc_test_au11.gds | Bin 16666 -> 16666 bytes testdata/algo/hc_test_au12.gds | Bin 16598 -> 16598 bytes testdata/algo/l2n_writer_au_2.gds | Bin 13334 -> 13330 bytes testdata/python/dbLayoutToNetlist.py | 20 +++++++++--------- testdata/ruby/dbLayoutToNetlist.rb | 20 +++++++++--------- 10 files changed, 20 insertions(+), 20 deletions(-) diff --git a/testdata/algo/device_extract_au2_with_rec_nets.gds b/testdata/algo/device_extract_au2_with_rec_nets.gds index 89fccd17aa168abac5607ab13515d949113cffbf..a92ab674427c406b3518e33a225d34b70170aab9 100644 GIT binary patch delta 863 zcmcb%is{iRCM5s_Qwo73_=Wo4B`wZ?1@UM!q|kPVzCOJx{FPC@-9ZK z;+t17$ueTou=y4<4hb$+UhF!w*zRJLm@LJC-EJ<=xX$mX@&dswi# ztw!K6c8MaqOYtg8W=V;)6W>-2LNKJPi#dC#rZ&*4N|R zT%nRqq#nb`69vRKOKB2ohdEgNAKm5HeX`ByA$EyX<~Stg+2D|vs_Qwo74EziXK#~!eJyA(j7@KfZELP!Dcd-di-o=Pj zeDf+MSw?IcHs4~#A;HDUi(Q8n+g+>@lchMY+s(yU$%NJJY224tuu9YjJjO0jB)XDQ z6-y{F2(hsR`MHL~2YLFr`^T$z8g6!w-^)UjQlrTZ@?x89;1g?b#2~YjzeOJ4GxJJjyNQG+~no32I{^P91s_Qwo73_=Wo4B`wZ?1@UM!q|kPVzCOJx{FPC@-9Z~ z;;WeEV^hC5hFO*ot3(eA4v9Uiyx4WzVY`b}V)7Xd>~7k_iB){_8m>wvtZuU4z087D zLQd#0b_o&j&%CNwLX|;?jV;K}H6%XB)6d;MUd7XL@&`S!%}%PzS=6y97eP~QXuts0 zprS>r21AC;AN2MTX}USY^jF5qv3qNY#Y5~8Gi-54^f=*=XmH0NQQ|WnYl7UYRs_Qwo74EziXK#~!eJyA(j7@KfZELP!Dcd-di-o=Pr zd==AtZ0a}1Fv~JxmFQu?A+d**7rTx-Ymszk% z$O%2hE+HcRnO7A{s4@t#u?6|LhQtSX`nmhZt9Y7D7SIyg?4-J!g(&4_n+3G?5~tK0 zY%-Vrauzjg4iQ0fh@tUhel79M?~IpY_t6TAhu9_N*y50w;Dke>#T|!4h0lDfX>qew z(Hfr3VU6!OC+`*EotzNKviVwFKGWpCqTHJUx_|OvjhmQR{mfV;{>`1wj#XmA()rlq zKWPPaiOC|Xv8V21tFb5I$=}v2#A@}bwQ5X^#*-B{s4<#PS|>4i!#Zwe6;Cq+({ys5 QgyiJgGQ6AfHVCi-0EKU%ApigX diff --git a/testdata/algo/device_extract_au4_with_rec_nets.gds b/testdata/algo/device_extract_au4_with_rec_nets.gds index 95a6a3156e73e702ac78eae697c545accd13c4f9..6ecb584315efdbb8445a4357c72714b296ae84e7 100644 GIT binary patch delta 984 zcmey?#Qd*`S&4y-fr%-CL57iu{V@X%gAjutgE#{Ud!mx6FgD?+SggXQ?qU<3yo(XL z_$sFP*wk;1VU}gYD$&D&Lt+mrFLoVw*zRJLn0$r_Ir*-^7-soCDyE;k39jzZNe@wSzs&n z_EbFi)3$|JtzNcWjfv5Gvf>W0$-8$7G8)2J20)hNWS(8TjFy`ncA2pQ00nER AM*si- delta 989 zcmey@#Qd#^S&4y-fr%-CL57iu{V@X%13v=;0|$czGJB$usxUU;s93DRr|x1Cp1g|@ zyZ9=m`PkHNj$xK%#46Flfv9j9o%R{4=jAmQZC7Vq**Pa}9|P^7M1}k5}8)<`6^U$^2U4o8K8P$L^yQ77wvY%(2BGF~JFkM2kBPi3*?jT3Ewb zt9*^%=CJPfoRjy8@J>#MW7&MIBcEyVUs3MO0aJhSVbv3}q@Nk9#J}b9*|AD&SU(?o z{3mU~E-_hTEB4fVY%BIeJo($Ug;=d#wOx&g(Ri}rE;UB;NjoGaZ`i@jtm0{gV46Sbv04@F4h$ zU>S78g8?bxA&2Uk3>ME)1oI!*DuSn?@z8@IjlS6=(9~H-J-zq6?|bvUVdgz)xSls$ zVa2659Osn~IMi>7PZ?1B%AnGfFNB8!lJe^dTA!?L=KHQ{!;%JNz~#!MPfTSqlj(`G z*~nzl?Dv22?2}1%Z<882y&bwwQ~NbqZ^oz|BXsOfjMgybG3uj)E^mvXUc-7_)Z^sw z7{q7}V;-Zx%NT2MV(!_?)!sZ9^mu5Ht*hdI7-0w9?WDVcp4hZSjS^P+C$T8>#nvq< zj_2&cbI=)^771EoC6Neko&&vlO9*df)8HQIo2(rBDkt7g*bqw@8)EU24e|7HF)1B> z>P5-Vs(0ZKZA1wjpK~&DuLI_tEZqV=b7`dvbTg{a@w}5&uc4%tKs^F7i$Fip0%-wq zZBP(ksSS4AgI227J9C7u8=W}_(gIj>5EKNk=KN0&-m-eLGY0{=)tMviFMu@%K|ug( z&W?M0X6@aEMmI;iX71zffb=QmRTA6~*|uZ&@pH*iKq@Sq8I021unTZlLeqaAfC oLXs_*FvL!m(T`Dvqe6(4AiG!rKNwqby`?NwK!YUzQh~$jUzIk9mjD0& delta 1053 zcmbRDhi%#)HYEl&1}3Hm1{p>s_Qwo74EziX3@i+W$n1$qs=`==H%9R?V-w$8#azg% zibVs15F1;NpKC~bkf)!!f4qvP>1F}Jvs^?eHJdCTD7INjW;=1p&B4m~)VFh~VRMKG znnMhYCttiLzM08rI~P_Tow0d{UE+W{4v8&6I3!lY;*gk=G2ara<$jCS2yU+0_Fj1M zSq0wB-!>OBP4-pg-du9(r!ZFa4fozDAPqK6aUTO1NYuXycM;GQlNN zV#_#RAFB)0av9gKPp;agx4og9@u2YJ{l9p(pDST3W|}_Nnvr|EPd6j>sM;PepD~^t ztC6RcG2Z3ICNq84CPrUu65FLVGqy4^8c$!ag;9kO7|NR&RT+VC1ENf~3vOkM2T2~> f#;69AEZEE_F+E@_BR8{(rx^;*bo+~KjArZr4cX5N diff --git a/testdata/algo/device_extract_au5_with_rec_nets.gds b/testdata/algo/device_extract_au5_with_rec_nets.gds index 365498e935aac0fa4a0a9562ec28d390db802ac7..1c310db0bad043961bbfaa6c4ed4e4e9b5d48db0 100644 GIT binary patch delta 935 zcmeBM!7^tJZ1X+Y?ObZul#8G#H#C?$-%fn<1r1`=8-mpzGA35N z`R4g{=eV%?sloFhc8QV@91^Hi_*sm>B0XVU_V>#UV5O4?82)RJnZ}2P5{h zH2oeYqc2ul?6?@!m>A8c-{)c!n|_;{QGm(N5Se2D;z&-Pz|F|b3`#g>1SBVK7vbIh JkB3o!9RO4pp5*`l delta 913 zcmbQXf~9W-ixLAH0~1pOgA5}R`(p+k27U$x1`Y;3WcEZQRbgzxQL)&BH=c@R#3sJk ziV3^Kd9yS~jd)V({*Rh6E7OTYMJ6w0M+I@z*k{PQ+1iv?*Dwfb- z5MpBs@^cM|5AyVL_m5ZcG@ZP`SZwn>+3j3JDK`TvzobE=a`Vj_jL&kZVRMKGnnMhY zC$Bda-@MCiI~P_TwRk?nE>RJJLn0?0heSda4vCP``IcBMXIsBUaI?|j_rjBNoq0E} zJ5bCtd96G5W}WLlg|Vu)cpcAyRbtiW`+V3Ww$EW=oX><+#*Y<;%rp*0tSNH)CJsjI z>1g^RPDWp>mN;=SsxdJdPyfixC^r2(52FC1`E&zrMrCFdPcs<9bo&DyMl*H*BhZiO diff --git a/testdata/algo/hc_test_au11.gds b/testdata/algo/hc_test_au11.gds index f24149b23653216abc6f58f089954b20ebe9ef09..51611f9e7cd97476bcde9f71bdaeef56c8aa1d05 100644 GIT binary patch delta 568 zcmbQ$#5k*oF^YkWfr%-CL57iu{V@X%gAjutgE#{Un}LIg&BxP;fkA|s)y}cg-22$_ z50)-F^cT#I3Sp38MNx}v#>A*VaU4c&Jk-yGOKx%o^Nq=6W{#83vT#p61f}`RA^a#P zy$ni!g3@*t5cw`BeGN)0SvqdkWtZTZ9B;_Gxx?Tc>*PF3$I1TY+>>`fX*MeeKL|?C zgVL{{w3#(Tz6na7gVItqj+570@=ngMu?N#zAoL_#2-gQn&w$cTptOM) zW>L3f-uz$r2h(I*E#A#exSw|wH#vj(#^f{`$H`||xF>Id(*K~emn}qm z8kBwnrS25oNBU78fvQ{r)sIGqU(Oo5;%Q)zt1b&>HU^`za@Jli)1n_O1-kl`Ybslr_?TW zN&h|cSy9DjQ2k7;3&%RvORxd8fc^r0K?PWY-NW3o@Em@@nP7tM1_T`j z`Q8%@h4{P)Z=o~HJq^q76DCJ^--8d(8{wYUtp)^LLuHiD^Y941!pSJ_+fn_G4+*N{ ztZLkI@Cvq!aZkY#Y(Q8?TWz&^1{EP9`hlvCUanSeB$C@U2CkG@YT*bz; zm(bP~p`;=x*2ViFEWr^U_jOo=u5Rv&@Eq3kaG!+x@C^ogfA^4}6LQ+u)5`>_wkb=-2+iUSu zN@?=IW5HepFLM#`AXpH3C?37GUPbUGw1;leOAr5=%dmX!pZ|X|`(~%vZl;;aIA3LP ziE9@u#D>@)i?E0Pf49<^dkEKGKzz22FgX&G)1id*kGM&Da$jq^m<8c%SXCXjR(|R> z9BZ-ieA$|!UAYRAM`e?=a6kRv1z7(iC#b?5SmO%r`mGPYQhq|8Ujcl|nu_^%wE=ym zHO%)locr|-_KyZJ{}6=!;!p6I3>&KTUqfEkV{{OHN$+*H^Bcw1z&j3wU&1jukLna3 zaOqV4hBV@4Xcnf6h3Iby?pPg71yF%LCdOW&dAjS(lU4Nwi76Um@qq7ZV4;q(J92g} zE$PO{j8EFiQmMMkdOBv+i3v@vXh~-E*4s z_baES;J(kPGUS&j7jfaFBa(6Jxr?+r9;4Ry{O#9c=jhG-F&eab>Flnq)l*ma=a-pB zebZK^1o^QKAI@TZ6LWEtol#JL2tB|BT6=twKo{u^d}n~>o=`GthwlcosPT9czWF{iZgED;GJNbBP2EKWrf z`+~DSqawm>9fYEjI5>82Q8x#{O>8M%8x@D=l5aYm=Xsy!{l0rYzKzw#t3^^s6jx|m z5Y?}gpd=BcY4ZQ?N5#@n1b1#g_~Ug1b3=e~-W0I@q-gL9sZj>WbWBkij_=l;Zo|6N zy0~mr`Kjc=*fGiAE2_p<#Tw)vNI7nahxvne3i6_i+rATlf0sW)pD!`IO<%$Id!-9~ zPOBJyrQ+OYhp>M-j`8(4^bdC9ixO)@w84|@sDr*{Ncu`*`H5W)9znKjheP&i?h7mgOm zD$#f>@^VmOUwJTu_8={5`B66_t-ZA1Ez=-}{WQ;McP+O{eAY74vm3@JJcQSU6we!-NN%eSS1&}>-H!BIG^>%^^9b&n>7bh6Trnl&(eD49)C_MO z&+@~GW`9}jK$f%y$Yy(PR@3MkYFGHlM23^4ChD4Rl@=iWCIZ*XSbr1a!De|*MghUl z2~2Qj@+~Zwnp%TbieK7JLeu|DV>n^FW1oQz7p7Z+P~lxW&%f+~Pz!}dc7`Z1EQN1P MZ^