From eb8abaf5a58457308cb35e1493a13df89e735446 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 9 Dec 2018 00:54:08 +0100 Subject: [PATCH] Some refactoring of net processor - introduced concept of root cluster - recursive shape iterator for clusters --- src/db/db/dbHierNetworkProcessor.cc | 232 +++++++++++++----- src/db/db/dbHierNetworkProcessor.h | 133 +++++++++- .../unit_tests/dbHierNetworkProcessorTests.cc | 6 +- testdata/algo/hc_test_au10.gds | Bin 3484 -> 3406 bytes testdata/algo/hc_test_au11.gds | Bin 15224 -> 16666 bytes testdata/algo/hc_test_au2.gds | Bin 3182 -> 2422 bytes testdata/algo/hc_test_au3.gds | Bin 3324 -> 2564 bytes testdata/algo/hc_test_au4.gds | Bin 3418 -> 2658 bytes testdata/algo/hc_test_au5.gds | Bin 2516 -> 2516 bytes testdata/algo/hc_test_au6.gds | Bin 3812 -> 3964 bytes testdata/algo/hc_test_au7.gds | Bin 5390 -> 4174 bytes testdata/algo/hc_test_au8.gds | Bin 6282 -> 4458 bytes testdata/algo/hc_test_au9.gds | Bin 2636 -> 1798 bytes 13 files changed, 313 insertions(+), 58 deletions(-) diff --git a/src/db/db/dbHierNetworkProcessor.cc b/src/db/db/dbHierNetworkProcessor.cc index 6bad4c7fb..c33724a66 100644 --- a/src/db/db/dbHierNetworkProcessor.cc +++ b/src/db/db/dbHierNetworkProcessor.cc @@ -682,8 +682,8 @@ public: /** * @brief Constructor */ - hc_receiver (const db::Layout &layout, db::connected_clusters &cell_clusters, hier_clusters &tree, const cell_clusters_box_converter &cbc, const db::Connectivity &conn) - : mp_layout (&layout), mp_tree (&tree), mp_cbc (&cbc), mp_conn (&conn) + hc_receiver (const db::Layout &layout, const db::Cell &cell, db::connected_clusters &cell_clusters, hier_clusters &tree, const cell_clusters_box_converter &cbc, const db::Connectivity &conn) + : mp_layout (&layout), mp_cell (&cell), mp_tree (&tree), mp_cbc (&cbc), mp_conn (&conn) { mp_cell_clusters = &cell_clusters; } @@ -739,6 +739,7 @@ public: private: const db::Layout *mp_layout; + const db::Cell *mp_cell; db::connected_clusters *mp_cell_clusters; hier_clusters *mp_tree; const cell_clusters_box_converter *mp_cbc; @@ -930,7 +931,7 @@ private: /** * @brief Handles a local clusters vs. the clusters of a specific child instance * @param c1 The local cluster - * @param ci2 The cell index of the child cell + * @param ci2 The cell index of the cell investigated * @param p2 The instantiation path to the child cell (last element is the instance to ci2) * @param t2 The accumulated transformation of the path */ @@ -1022,10 +1023,40 @@ private: ClusterInstance ci (id, *p); if (p == path.begin ()) { + + // if we're attaching to a child which is root yet, we need to promote the + // cluster to the parent in all places + connected_clusters &child_cc = mp_tree->clusters_per_cell (p->inst_ptr.cell_index ()); + if (child_cc.is_root (id)) { + + const db::Cell &child_cell = mp_layout->cell (p->inst_ptr.cell_index ()); + for (db::Cell::parent_inst_iterator pi = child_cell.begin_parent_insts (); ! pi.at_end (); ++pi) { + + connected_clusters &parent_cc = mp_tree->clusters_per_cell (pi->parent_cell_index ()); + for (db::CellInstArray::iterator pii = pi->child_inst ().begin (); ! pii.at_end (); ++pii) { + + ClusterInstance ci2 (id, db::InstElement (pi->child_inst (), pii)); + if (mp_cell->cell_index () != pi->parent_cell_index () || ci != ci2) { + + id_type id_dummy = parent_cc.insert_dummy (); + parent_cc.add_connection (id_dummy, ci2); + + } + + } + + } + + child_cc.reset_root (id); + + } + return ci; + } - connected_clusters &target_cc = mp_tree->clusters_per_cell (p [-1].inst_ptr.cell_index ()); + db::cell_index_type pci = p [-1].inst_ptr.cell_index (); + connected_clusters &target_cc = mp_tree->clusters_per_cell (pci); id_type parent_cluster = target_cc.find_cluster_with_connection (ci); if (parent_cluster > 0) { @@ -1035,13 +1066,43 @@ private: } else { + id_type id_new = 0; + + // if we're attaching to a child which is root yet, we need to promote the + // cluster to the parent in all places + connected_clusters &child_cc = mp_tree->clusters_per_cell (p->inst_ptr.cell_index ()); + if (child_cc.is_root (id)) { + + const db::Cell &child_cell = mp_layout->cell (p->inst_ptr.cell_index ()); + for (db::Cell::parent_inst_iterator pi = child_cell.begin_parent_insts (); ! pi.at_end (); ++pi) { + + connected_clusters &parent_cc = mp_tree->clusters_per_cell (pi->parent_cell_index ()); + for (db::CellInstArray::iterator pii = pi->child_inst ().begin (); ! pii.at_end (); ++pii) { + + id_type id_dummy = parent_cc.insert_dummy (); + ClusterInstance ci2 (id, db::InstElement (pi->child_inst (), pii)); + parent_cc.add_connection (id_dummy, ci2); + + if (pci == pi->parent_cell_index () && ci == ci2) { + id_new = id_dummy; + } + + } + + } + + child_cc.reset_root (id); + + } + // no parent -> create vertical connector - id = target_cc.insert_dummy (); - target_cc.add_connection (id, ci); + id = id_new; + tl_assert (id != 0); } } + } }; @@ -1165,7 +1226,7 @@ hier_clusters::build_hier_connections (cell_clusters_box_converter &cbc, c // NOTE: this is a receiver for both the child-to-child and // local to child interactions. - hc_receiver rec (layout, local, *this, cbc, conn); + hc_receiver rec (layout, cell, local, *this, cbc, conn); cell_inst_clusters_box_converter cibc (cbc); // The box scanner needs pointers so we have to first store the instances @@ -1241,70 +1302,131 @@ hier_clusters::clusters_per_cell (db::cell_index_type cell_index) return c->second; } -template -static -void put_or_propagate (const hier_clusters &hc, incoming_cluster_connections &inc, size_t cluster_id, const local_cluster &cluster, db::Layout &layout, db::cell_index_type ci, const std::map &lm, const db::ICplxTrans &trans) +template void insert_transformed (db::Layout &layout, db::Shapes &shapes, const Shape &s, const Trans &t); + +template void insert_transformed (db::Layout &layout, db::Shapes &shapes, const db::PolygonRef &s, const Trans &t) { - db::Cell &target_cell = layout.cell (ci); - - if (cluster_id > 0 && inc.has_incoming (ci, cluster_id)) { - - typedef std::pair reference_type; - std::map references; - - for (db::Cell::parent_inst_iterator pi = target_cell.begin_parent_insts (); ! pi.at_end (); ++pi) { - db::Instance i = pi->child_inst (); - for (db::CellInstArray::iterator ii = i.cell_inst ().begin (); ! ii.at_end (); ++ii) { - references.insert (std::make_pair (reference_type ((*pi).parent_cell_index (), db::InstElement (i, ii)), false)); - } - } - - const typename incoming_cluster_connections::incoming_connections &connections = inc.incoming (ci, cluster_id); - for (typename incoming_cluster_connections::incoming_connections::const_iterator x = connections.begin (); x != connections.end (); ++x) { - typename std::map::iterator r = references.find (reference_type (x->parent_cell (), x->inst ())); - if (r != references.end () && ! r->second) { - put_or_propagate (hc, inc, x->parent_cluster_id (), cluster, layout, r->first.first, lm, r->first.second.complex_trans () * trans); - r->second = true; - } - } - - for (typename std::map::const_iterator r = references.begin (); r != references.end (); ++r) { - if (! r->second) { - put_or_propagate (hc, inc, 0, cluster, layout, r->first.first, lm, r->first.second.complex_trans () * trans); - } - } - - } else { - - for (typename std::map::const_iterator m = lm.begin (); m != lm.end (); ++m) { - db::Shapes shapes; - for (typename local_cluster::shape_iterator s = cluster.begin (m->first); ! s.at_end (); ++s) { - shapes.insert (*s); - } - tl::ident_map pm; - target_cell.shapes (m->second).insert_transformed (shapes, trans, pm); - } - + db::Polygon poly = s.obj (); + poly.transform (s.trans ()); + if (! t.is_unity ()) { + poly.transform (t); } + shapes.insert (db::PolygonRef (poly, layout.shape_repository ())); } template void -hier_clusters::return_to_hierarchy (db::Layout &layout, db::Cell &cell, const std::map &lm) const +hier_clusters::return_to_hierarchy (db::Layout &layout, const std::map &lm) const { - incoming_cluster_connections inc (layout, cell, *this); - for (db::Layout::bottom_up_iterator c = layout.begin_bottom_up (); c != layout.end_bottom_up (); ++c) { + const db::connected_clusters &cc = clusters_per_cell (*c); - for (typename db::connected_clusters::const_iterator lc = cc.begin (); lc != cc.end (); ++lc) { - put_or_propagate (*this, inc, lc->id (), *lc, layout, *c, lm, db::ICplxTrans ()); + db::Cell &target_cell = layout.cell (*c); + + for (typename db::connected_clusters::all_iterator lc = cc.begin_all (); ! lc.at_end (); ++lc) { + + if (cc.is_root (*lc)) { + + for (typename std::map::const_iterator m = lm.begin (); m != lm.end (); ++m) { + + db::Shapes &shapes = target_cell.shapes (m->second); + + for (recursive_cluster_shape_iterator si (*this, m->first, *c, *lc); ! si.at_end (); ++si) { + insert_transformed (layout, shapes, *si, si.trans ()); + } + + } + + } + } + } } // explicit instantiations template class DB_PUBLIC hier_clusters; +// ------------------------------------------------------------------------------ +// recursive_cluster_shape_iterator implementation + +template +recursive_cluster_shape_iterator::recursive_cluster_shape_iterator (const hier_clusters &hc, unsigned int layer, db::cell_index_type ci, typename local_cluster::id_type id) + : mp_hc (&hc), m_layer (layer), m_id (id) +{ + down (ci, id, db::ICplxTrans ()); + + while (m_shape_iter.at_end () && ! m_conn_iter_stack.empty ()) { + next_conn (); + } +} + +template +recursive_cluster_shape_iterator &recursive_cluster_shape_iterator::operator++ () +{ + ++m_shape_iter; + + while (m_shape_iter.at_end () && ! m_conn_iter_stack.empty ()) { + next_conn (); + } + + return *this; +} + +template +void recursive_cluster_shape_iterator::next_conn () +{ + if (m_conn_iter_stack.back ().first != m_conn_iter_stack.back ().second) { + + const ClusterInstance &cli = *m_conn_iter_stack.back ().first; + down (cli.inst ().inst_ptr.cell_index (), cli.id (), cli.inst ().complex_trans ()); + + } else { + + while (m_conn_iter_stack.back ().first == m_conn_iter_stack.back ().second) { + + up (); + if (m_conn_iter_stack.empty ()) { + return; + } + + ++m_conn_iter_stack.back ().first; + + } + + } +} + +template +void recursive_cluster_shape_iterator::up () +{ + m_conn_iter_stack.pop_back (); + m_trans_stack.pop_back (); + m_cell_index_stack.pop_back (); +} + +template +void recursive_cluster_shape_iterator::down (db::cell_index_type ci, typename db::local_cluster::id_type id, const db::ICplxTrans &t) +{ + const connected_clusters &clusters = mp_hc->clusters_per_cell (ci); + const typename connected_clusters::connections_type &conn = clusters.connections_for_cluster (id); + + if (! m_trans_stack.empty ()) { + m_trans_stack.push_back (m_trans_stack.back () * t); + } else { + m_trans_stack.push_back (t); + } + + m_cell_index_stack.push_back (ci); + m_conn_iter_stack.push_back (std::make_pair (conn.begin (), conn.end ())); + + const local_cluster &cluster = mp_hc->clusters_per_cell (cell_index ()).cluster_by_id (cluster_id ()); + m_shape_iter = cluster.begin (m_layer); +} + +// explicit instantiations +template class DB_PUBLIC recursive_cluster_shape_iterator; + // ------------------------------------------------------------------------------ // incoming_cluster_connections implementation diff --git a/src/db/db/dbHierNetworkProcessor.h b/src/db/db/dbHierNetworkProcessor.h index e102a5d26..2442298cb 100644 --- a/src/db/db/dbHierNetworkProcessor.h +++ b/src/db/db/dbHierNetworkProcessor.h @@ -229,6 +229,7 @@ template class DB_PUBLIC local_clusters { public: + typedef typename local_cluster::id_type id_type; typedef typename local_cluster::box_type box_type; typedef db::box_tree, local_cluster_box_convert > tree_type; typedef typename tree_type::touching_iterator touching_iterator; @@ -372,6 +373,14 @@ public: return m_id == other.m_id && m_inst == other.m_inst; } + /** + * @brief Inequality + */ + bool operator!= (const ClusterInstance &other) const + { + return ! operator== (other); + } + /** * @brief Less operator */ @@ -434,12 +443,20 @@ private: /** * @brief Local clusters with connections to clusters from child cells + * + * Clusters can get connected. There are incoming connections (from above the hierarchy) + * and outgoing connections (down to a child cell). + * + * "root" clusters are some that don't have incoming connections. There are only + * root clusters or clusters which are connected from every parent cell. There are no + * "half connected" clusters. */ template class DB_PUBLIC connected_clusters : public local_clusters { public: + typedef typename local_clusters::id_type id_type; typedef std::list connections_type; typedef typename local_clusters::box_type box_type; typedef connected_clusters_iterator all_iterator; @@ -507,11 +524,29 @@ public: return m_connections.end (); } + /** + * @brief Returns true, if the given cluster ID is a root cluster + */ + bool is_root (id_type id) const + { + return m_connected_clusters.find (id) == m_connected_clusters.end (); + } + + /** + * @brief Resets the root status of a cluster + * CAUTION: don't call this method unless you know what you're doing. + */ + void reset_root (id_type id) + { + m_connected_clusters.insert (id); + } + private: template friend class connected_clusters_iterator; - std::map::id_type, connections_type> m_connections; + std::map m_connections; std::map::id_type> m_rev_connections; + std::set m_connected_clusters; }; template @@ -573,7 +608,7 @@ public: * The backannotation process usually involves propagation of shapes up in the hierarchy * to resolve variants. */ - void return_to_hierarchy (db::Layout &layout, db::Cell &cell, const std::map &lm) const; + void return_to_hierarchy (db::Layout &layout, const std::map &lm) const; /** * @brief Clears this collection @@ -589,6 +624,100 @@ private: std::map > m_per_cell_clusters; }; +/** + * @brief A recursive shape iterator for the shapes of a cluster + * + * This iterator will deliver the shapes of a cluster including the shapes for the + * connected child clusters. + * + * This iterator applies to one layer. + */ +template +class DB_PUBLIC recursive_cluster_shape_iterator +{ +public: + typedef T value_type; + typedef const T &reference; + typedef const T *pointer; + + /** + * @brief Constructor + */ + recursive_cluster_shape_iterator (const hier_clusters &hc, unsigned int layer, db::cell_index_type ci, typename local_cluster::id_type id); + + /** + * @brief Returns a value indicating whether there are any more shapes + */ + bool at_end () const + { + return m_shape_iter.at_end (); + } + + /** + * @brief Returns the shape (untransformed) + */ + reference operator* () const + { + return *m_shape_iter; + } + + /** + * @brief Returns the shape pointer (untransformed) + */ + pointer operator-> () const + { + return m_shape_iter.operator-> (); + } + + /** + * @brief Returns the transformation applicable for transforming the shape to the root cluster + */ + const db::ICplxTrans &trans () const + { + return m_trans_stack.back (); + } + + /** + * @brief Returns the cell index the shape lives in + */ + db::cell_index_type cell_index () const + { + return m_cell_index_stack.back (); + } + + /** + * @brief Returns the id of the current cluster + */ + typename db::local_cluster::id_type cluster_id () const + { + if (m_conn_iter_stack.size () <= 1) { + return m_id; + } else { + return m_conn_iter_stack [m_conn_iter_stack.size () - 2].first->id (); + } + } + + /** + * @brief Increment operator + */ + recursive_cluster_shape_iterator &operator++ (); + +private: + typedef typename db::connected_clusters::connections_type connections_type; + + const hier_clusters *mp_hc; + std::vector m_trans_stack; + std::vector m_cell_index_stack; + std::vector > m_conn_iter_stack; + typename db::local_cluster::shape_iterator m_shape_iter; + unsigned int m_layer; + typename db::local_cluster::id_type m_id; + + void next_conn (); + void up (); + void down (db::cell_index_type ci, typename db::local_cluster::id_type id, const db::ICplxTrans &t); +}; + /** * @brief A connection to a cluster from a parent cluster */ diff --git a/src/db/unit_tests/dbHierNetworkProcessorTests.cc b/src/db/unit_tests/dbHierNetworkProcessorTests.cc index d527e4b7d..90bc2701d 100644 --- a/src/db/unit_tests/dbHierNetworkProcessorTests.cc +++ b/src/db/unit_tests/dbHierNetworkProcessorTests.cc @@ -515,6 +515,10 @@ static void run_hc_test (tl::TestBase *_this, const std::string &file, const std const db::connected_clusters &clusters = hc.clusters_per_cell (*td); for (db::connected_clusters::all_iterator c = clusters.begin_all (); ! c.at_end (); ++c) { + if (! clusters.is_root (*c)) { + continue; + } + net_layers.push_back (std::make_pair (0, ly.insert_layer ())); unsigned int lout = net_layers.back ().second; @@ -601,7 +605,7 @@ static void run_hc_test_with_backannotation (tl::TestBase *_this, const std::str lm[l1] = ly.insert_layer (db::LayerProperties (101, 0)); lm[l2] = ly.insert_layer (db::LayerProperties (102, 0)); lm[l3] = ly.insert_layer (db::LayerProperties (103, 0)); - hc.return_to_hierarchy (ly, ly.cell (*ly.begin_top_down ()), lm); + hc.return_to_hierarchy (ly, lm); CHECKPOINT(); db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/" + au_file); diff --git a/testdata/algo/hc_test_au10.gds b/testdata/algo/hc_test_au10.gds index d7c92fb935d018da10d349f0310b76a1a850054f..66499fd67d8879d97fbdace91b5088c7905ab957 100644 GIT binary patch delta 631 zcmaixy-Nad7{|YNzMP~&CT!%2lJgfsz99w=W4#cQfZYqS@z--sGEkHUOz1D8jAif`B) zn0D&HilNe8OPyL_=X@w_I2mi+qwc)AaXv%TDY^V?0);A(P<*GldJmy^zG3VKs$T7= delta 328 zcmX>nHAh;BfsKKQDS|VI%I=wjkDYOP<6;2^58?zZgv_3R4 zy}$G8@0^=^Q$K$8L#G!4;Pd67+wlc|hA6ZEz%$VD=-;P$`;z|^kH6d#1n6#lY~fn`8CaRAbF*lxX7!(Q1@;0j_z+YI7WYZcEM5Chx~}OPc^qCy1`q ztv1I*-Bu zdC6EaX18m8!g#~joy_4^i5O0{t6v!F#+N!YpELes?C;e4sIjarM!Syf9Iks)2Pa$L z?$c`EGjPVL09KnfrLmOm8f>V`WdNFI!4W&6T=#*e=2#d=HP#G=0GxZ^h`}S^j3hiY z$Jf(aYWD5}NS*{o>{{XfSM$^y5AH|}|Mh53hvu{=QF@u?J8hMo^t#(qL*3LK?MalL zri-4^)6^cfr-qvGPVGsQo(`uyrKj;ux2J}h$-MR?N>5Y&cuG%`dFkoY=aGJ*@_C~B zCH3zbKOKG|tIhA1q!(VFA-cRw^at07b^f+~Tk+H!7k10uy!O%=eo8{>pKCNmmx-)4ui@SB4n4MP{eYKTI>Y0cBf7%3Pqn$|9s9z5eaJ8D zms=;tx7u7Dex&BuQ@^h0L`0cHt<6&=qSs|>S>Ah#A602wl!5%V?y0#9#9g{Juk#RP z4(ohytIT6<9PV`)hkIn%P^PgquT!|gH(sW3CvS5*4fhtWv^Wic4v^|Eiv7GC& zF%j3#6UKStJ>%#$y)p&&;<^ce!=D5(CGK=&4wutQmN8DZp=OB1$j+eXL#r@#CSq5l5t#-_S z^ETfttIbmqA#S>%NGEO*7mFUupzgL^}cf77U)-cL?$q$SD6@Ol8Z6v z|7X&&?SWFm7TroJ<)Jac=LF2cGK_`z_cSa(U)ahe9kPv9!zPtfovxrGQk@NoM`E@9 zxHjwb21BEKe+%A0Z`7n|L#IWRdkVkcq{jPQ_zb&s-lt$58iq+TBPuOLt(q6`8%~Y! zehuJv&B8K_HSsj%l<5 bAE967{TjT6PKEbzcmhjGSgHH~lEi)hOOfCr diff --git a/testdata/algo/hc_test_au2.gds b/testdata/algo/hc_test_au2.gds index 86ba92af2e58005b024b12fee6646d1c2bc99925..73576e4f40883305ee0ec8b4f929dcb762ec2a79 100644 GIT binary patch delta 114 zcmaDS@l8mHfsKKQDS|=WfHGx9PlfQsz)yZZ|U?r2wfOI081mo+8uZ$s#$y$ss)+z*x u$ylFFn~8yuflY_a*^q%nkb!}Poq<7y6{j0FF>A6hzL~7UVmvvPQxX7*Wh?yv diff --git a/testdata/algo/hc_test_au3.gds b/testdata/algo/hc_test_au3.gds index c1998d1e48d9d6630451916beead0e3003bd2a3e..54b1e4e9511a066a2dbeb80564c44ae571341f68 100644 GIT binary patch delta 110 zcmew(*&?FEz{bGD6u}_F$i)7Lfro*EL5M+%K^~bsQAt%8i}1#%4kkHv1_l{coH{rE QVBO9(`7AT{Y08eQVssI20 delta 215 zcmZn>`6H>sz{bGD6u}_F$i)7Lfro*GL6m`=!3dc>QAt%8i}1#%4yMT)I7KFwsZXBI zsXB3+`ebDe3C5R`vlxwm0?L!WFlvG%CYv#V6-+Jz()R2UjISoXGKMfFYXOylg(j~; wu$YYX*|eD$7#Y}f*qjX+SOgguSlAgDWLR;!a1--(HpbVJb6AWgzvh$#09Pk3J^%m! diff --git a/testdata/algo/hc_test_au4.gds b/testdata/algo/hc_test_au4.gds index 57d1aa7c0b610f89035a3f55f25b1bdc0a53555e..37e140f06d0ac1820ca041cc9ceb6dcff0670972 100644 GIT binary patch delta 102 zcmca5^+-gCfsKKQDS|B(h4x{ym>%)7rGypBA0zfu2f%v!#5H4`W&Jmw$0D{7Y3uTY_yR6j! zFaePm%OeiAB!xF&tn6V2Kz9*|kpbe1D=ED0j+I@9SS*D|H0y|+oTTuPl(pzh%>x8# zd@Ldbr=yZIE`J||X~lMmpMX}Ms`3*Mg>Q?_+A3nR0zh=40LGf6@XgAov%b%dN_^Yp z^9$0^`Fq)uPCGZ$hJB2KJ;b|hN#UI+C2v<)s)$JJULn3WB!zd1lB(h4nvqp`;up=ysr-VI<5-0zn*fyng(hzS)2frV zF{$gbX)`e}GO+2eIU6#t2r@9Rurn~ou;O&vB<8u3WqElwPvX&I+P*z@Z_6Jbs9VhQg(f z&`?bc4Gj{}+y@Biyq;cefp*~D-{rZ_dCzmsd(O*`*&Hkw#tt$*!+u2w4&sPm<@fhR zt`Hw1-|U_mc^k->6KBG*tc{xN*hv|;vhu<276TuE-2#ZgTOhLLk#)P(6Zu8ua{#lg z88`z%9X0QVteb7^Ra<~)07Pf?@58!iDDMJ*JHT4k3?HgB5&)BROKwNfqr~B;u1s`3 zf#lF5Ro4G?ig;dCRf9+gQ~MrS2jr$bJMKi~vAtI;3BXqYh~gTkH9fNKtMtT-{Bqo4 z^%C%R0b+7mxz#F6*8N>}&#S|uL8N%)zDL#pc9-sfm~s$PPr$O;43qU(pWM}eTcm7M zlNf&1nVGCpvqtU$WiwxNc4`-8X0mR|lW2NWo3goedIO0qy$+Lgx6Vl@8(k$LHHR`Y nS+`pgn{X7&&HaC^<$LHrE+yPSe(KGT!)RjAbgzV^CJBLWY*Kg^ delta 1246 zcmbu8zfTlF6vw|iyX>9b9(OFi$qIU~dx&;-l~V90P*4yISmB` z1u@1@XrQ#X!qQmT(GfxnMzo-~lKIX!4i}CBZ1ywzeecb@@5{`$`)}qd2qDBW5>Mog z5Fx-Q#xZqy-KwO6J>*Z%HifMFajWrAzVxSC2Sh4gc~!-#?06|$d3N=|twc@!43b_4zV)Bh&Jgws0FTQ)FgOE5iQ({TVB|euY4s?PFZ}WDI`J8Z z+Wt9sp3dn`CwJvx@B!M$F# z$SY~PU(!4zD%d)}}P+kW}PNV$Q(dy-Oom$#4gCH*tk7XQ$iR)DU zMol9R9VqXSn%iGmJ!(4^TpBX109`;HPah8q0)noj%>ojsmTv$mn7Y@H%q!V@oVqKNv`rFuWnRP_`h%YG`i|;@HD#WZtyg^ i>XiBac^X-MLmn22``d-RK>oQqvi~lBB*L5;VSo!?X4NkM diff --git a/testdata/algo/hc_test_au8.gds b/testdata/algo/hc_test_au8.gds index 4cd9a66a5347520e55f6814f4c47268b5c712805..587bff467e7ce81473259903deb52d0a21ae39ac 100644 GIT binary patch delta 665 zcmaKqKTE?v7>9qkT<=2v#MBsDp%sZWP${UzQKYNlDu|1VV+RKZaq7@P#Km4efRhwl zlq`M(5#9U%BAuN403zONJfqNh5T4`VckjLLk<*peFoXbOJE&Mpz90_=J|m_B0&N~o1 zr=+s3_fyu_4bvi0bESin#sg|oR!2RiI+ok&Dp!c=9IzSykzWJN{glRAjUJy-dpf-| z0PHS649YsKZ!$FA?wa(xemh!3YH_ij(s;n6>kmLtCy1pdU|A1jXne6hcA(3AIQ#$K Y5l_4KEWQYaOm)0+JoE-!=o6gd6I6j=XaE2J literal 6282 zcmbuDKWr685XQ&vpC8V{7-NEEo)RYk#S)eh0#Y0aMTAg*Vks$HAVlGUf`Wp=g$oxh zC`d=)B2p+^L<&U;3KtY9T%d@8B83YVgdqO`#~5RR0TT?H@4LCl-s$m@iEQcVXU*Pz zw>Pspv%6A}LgAFuTMDgnQj?PGk#{Bczf=pA!IQ^Cx{Bq`zxejkuYUP)?X%<8Kbrjh z^pMocxo5K)QmItFJSe5ANM(CLTBOom5Rv|lVhEde?I+UGpZ%Ggl+sRlbN_H9gx9qY z!WEHXuSmJeXm+xB|ED7%JgJ93ZjObpu@PzZC-vt2pWj0N@es(Tvm)DuBhCI~JlDSv zzaL{=f+x-@OM~ct10R~w>|pl$GyOwYKM}%TDR-hquI%3{Y6@0yk3$S!0NK11#v6M6e;q}joS(IN4mDim{Cg`Y(_r;&-k-Q6fS-$a@nbZK>-!3%zX z9=IJ@X3tEd*+G{Uy-{08d?LFpLH8)WH>KIZ1}#SfP#@nAfz$dfNg}X+9QpaWM&O@k zlNMO{ec3FxnvD%BYk5?wYx^uR^)(Tr*};Z!r?JUt6)$ooB13`I!x|T(*+G{Uzi#^p z{YJ)^V=?Y4Q2mxc2Lsg1>6;eM+-~F0Gbz_eGF&rOhcF?7T-A$rz{YF0JqHZPm4{zdMHvc`!&Vw!1rkvImYg0~Zi?u1I zMF((h^UrFM(d^*=^>?*W8TuNjIaVil9Q*v4q?#liZ$lyMteiZQ**WCu*0$lKQe>Y! z$hd_tHxhbsLs(z!<>^Mcc#`SEHCsxc4@Og=|JJRep-MF-P%dm+!;+7#f32#go%}#o> zm|u0ylDIXIHu&F|oY1x1F)qCsxHq6&zR22#_@y*E=+Y{8VIH8akgMl0uD(dKgD$P& zQV0)^!bc!|*7|Ft*+G{UZx7anxu0b`xnGPlJLuBlcz$Q>!24&p?}#)z=+M%elRG8l z9Fi~nW;FYql27ZwAo2pfk9^#x`Os+gmFD~P+>b;m&UDE8!y}ofRTvZ>D92aw|ku^ixeOk=J^bff)p*h-U zcFbYdoOn5JME0ISAMhQl%U8!E&A#`PPm8y{%<*LXBI{A4+1u89TAWusm-Y6vx2o|p fn!U#rNBDeJYa-b`0^g5CvQ}z)j(#EI6z{bGD6u}_F$i)7Lfro*EL6|{^K@*uhQAt%8n{bqu96JMp3@c8Jn*|s< Mm{>xntW zhHTnQ42%pMI&9AVetrxrf(#5S>