From df44c364ea6deef8422a710011652513ba6369ae Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 8 Dec 2018 01:55:02 +0100 Subject: [PATCH] WIP: network processor: net backannotation into original hierarchy. --- src/db/db/dbHierNetworkProcessor.cc | 141 ++++++++++++++++++ src/db/db/dbHierNetworkProcessor.h | 129 ++++++++++++++++ .../unit_tests/dbHierNetworkProcessorTests.cc | 72 +++++++++ testdata/algo/hc_test_au10b.gds | Bin 0 -> 3032 bytes testdata/algo/hc_test_au1b.gds | Bin 0 -> 1386 bytes testdata/algo/hc_test_au2b.gds | Bin 0 -> 2218 bytes testdata/algo/hc_test_au3b.gds | Bin 0 -> 2346 bytes testdata/algo/hc_test_au4b.gds | Bin 0 -> 2390 bytes testdata/algo/hc_test_au5b.gds | Bin 0 -> 2262 bytes testdata/algo/hc_test_au6b.gds | Bin 0 -> 3484 bytes testdata/algo/hc_test_au7b.gds | Bin 0 -> 3694 bytes testdata/algo/hc_test_au8b.gds | Bin 0 -> 3950 bytes testdata/algo/hc_test_au9b.gds | Bin 0 -> 1664 bytes 13 files changed, 342 insertions(+) create mode 100644 testdata/algo/hc_test_au10b.gds create mode 100644 testdata/algo/hc_test_au1b.gds create mode 100644 testdata/algo/hc_test_au2b.gds create mode 100644 testdata/algo/hc_test_au3b.gds create mode 100644 testdata/algo/hc_test_au4b.gds create mode 100644 testdata/algo/hc_test_au5b.gds create mode 100644 testdata/algo/hc_test_au6b.gds create mode 100644 testdata/algo/hc_test_au7b.gds create mode 100644 testdata/algo/hc_test_au8b.gds create mode 100644 testdata/algo/hc_test_au9b.gds diff --git a/src/db/db/dbHierNetworkProcessor.cc b/src/db/db/dbHierNetworkProcessor.cc index 82c1a89d7..6bad4c7fb 100644 --- a/src/db/db/dbHierNetworkProcessor.cc +++ b/src/db/db/dbHierNetworkProcessor.cc @@ -1241,7 +1241,148 @@ 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) +{ + 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); + } + + } +} + +template +void +hier_clusters::return_to_hierarchy (db::Layout &layout, db::Cell &cell, 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 ()); + } + } +} + // explicit instantiations template class DB_PUBLIC hier_clusters; +// ------------------------------------------------------------------------------ +// incoming_cluster_connections implementation + +template +incoming_cluster_connections::incoming_cluster_connections (const db::Layout &layout, const db::Cell &cell, const hier_clusters &hc) + : mp_layout (const_cast (&layout)), mp_hc (const_cast *> (&hc)) +{ + cell.collect_called_cells (m_called_cells); + m_called_cells.insert (cell.cell_index ()); +} + +template +bool +incoming_cluster_connections::has_incoming (db::cell_index_type ci, size_t cluster_id) const +{ + std::map >::const_iterator i = m_incoming.find (ci); + if (i == m_incoming.end ()) { + ensure_computed (ci); + i = m_incoming.find (ci); + tl_assert (i != m_incoming.end ()); + } + + tl_assert (i != m_incoming.end ()); + return (i->second.find (cluster_id) != i->second.end ()); +} + +template +const typename incoming_cluster_connections::incoming_connections & +incoming_cluster_connections::incoming (db::cell_index_type ci, size_t cluster_id) const +{ + std::map >::const_iterator i = m_incoming.find (ci); + if (i == m_incoming.end ()) { + ensure_computed (ci); + i = m_incoming.find (ci); + tl_assert (i != m_incoming.end ()); + } + + std::map::const_iterator ii = i->second.find (cluster_id); + if (ii != i->second.end ()) { + return ii->second; + } else { + static incoming_connections empty; + return empty; + } +} + +template +void +incoming_cluster_connections::ensure_computed (db::cell_index_type ci) const +{ + tl_assert (mp_layout.get () != 0); + m_incoming.insert (std::make_pair (ci, std::map ())); + + const db::Cell &cell = mp_layout->cell (ci); + for (db::Cell::parent_cell_iterator pc = cell.begin_parent_cells (); pc != cell.end_parent_cells (); ++pc) { + if (m_called_cells.find (*pc) != m_called_cells.end ()) { + ensure_computed_parent (*pc); + } + } + + m_called_cells.erase (ci); +} + +template +void +incoming_cluster_connections::ensure_computed_parent (db::cell_index_type ci) const +{ + ensure_computed (ci); + + const connected_clusters &cc = ((const hier_clusters *) mp_hc.get ())->clusters_per_cell (ci); + for (typename connected_clusters::connections_iterator x = cc.begin_connections (); x != cc.end_connections (); ++x) { + for (typename connected_clusters::connections_type::const_iterator xx = x->second.begin (); xx != x->second.end (); ++xx) { + m_incoming [xx->inst ().inst_ptr.cell_index ()][xx->id ()].push_back (IncomingClusterInstance (ci, x->first, xx->inst ())); + } + } +} + +// explicit instantiations +template class DB_PUBLIC incoming_cluster_connections; + } diff --git a/src/db/db/dbHierNetworkProcessor.h b/src/db/db/dbHierNetworkProcessor.h index 108b185e1..e102a5d26 100644 --- a/src/db/db/dbHierNetworkProcessor.h +++ b/src/db/db/dbHierNetworkProcessor.h @@ -443,6 +443,7 @@ public: typedef std::list connections_type; typedef typename local_clusters::box_type box_type; typedef connected_clusters_iterator all_iterator; + typedef typename std::map::id_type, connections_type>::const_iterator connections_iterator; /** * @brief Constructor @@ -488,6 +489,24 @@ public: return connected_clusters_iterator (*this); } + /** + * @brief Begin iterator for the connections + * + * The iterated object is a pair or (cluster id, connections_type). + */ + connections_iterator begin_connections () const + { + return m_connections.begin (); + } + + /** + * @brief Begin iterator for the connections + */ + connections_iterator end_connections () const + { + return m_connections.end (); + } + private: template friend class connected_clusters_iterator; @@ -519,6 +538,7 @@ template class cell_clusters_box_converter; */ template class DB_PUBLIC hier_clusters + : public tl::Object { public: typedef typename local_cluster::box_type box_type; @@ -543,6 +563,18 @@ public: */ connected_clusters &clusters_per_cell (db::cell_index_type cell_index); + /** + * @brief Writes the net shapes back to the original hierarchy + * + * The layout object is supposed to be the original layout or one with identical cell indexes. + * "lm" is a layer mapping table from the connection layer indexes to the target layer + * indexes. + * + * 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; + /** * @brief Clears this collection */ @@ -557,6 +589,103 @@ private: std::map > m_per_cell_clusters; }; +/** + * @brief A connection to a cluster from a parent cluster + */ +class DB_PUBLIC IncomingClusterInstance +{ +public: + IncomingClusterInstance (db::cell_index_type pc, size_t parent_cluster_id, const db::InstElement &inst) + : m_parent_cell (pc), m_parent_cluster_id (parent_cluster_id), m_inst (inst) + { + // .. nothing yet .. + } + + IncomingClusterInstance () + : m_parent_cell (0), m_parent_cluster_id (0), m_inst () + { + // .. nothing yet .. + } + + /** + * @brief Gets the cell index of the parent cell + */ + size_t parent_cell () const + { + return m_parent_cell; + } + + /** + * @brief Gets the cluster ID from which the cluster is connected to + * The parent cluster lives in the parent cell + */ + size_t parent_cluster_id () const + { + return m_parent_cluster_id; + } + + /** + * @brief Gets the instance path + */ + const db::InstElement &inst () const + { + return m_inst; + } + + /** + * @brief Equality + */ + bool operator== (const IncomingClusterInstance &other) const + { + return m_parent_cluster_id == other.m_parent_cluster_id && m_parent_cell == other.m_parent_cell && m_inst == other.m_inst; + } + + /** + * @brief Less operator + */ + bool operator< (const IncomingClusterInstance &other) const + { + if (m_parent_cluster_id != other.m_parent_cluster_id) { + return m_parent_cluster_id < other.m_parent_cluster_id; + } + if (m_parent_cell != other.m_parent_cell) { + return m_parent_cell < other.m_parent_cell; + } + return m_inst < other.m_inst; + } + +private: + db::cell_index_type m_parent_cell; + size_t m_parent_cluster_id; + db::InstElement m_inst; +}; + +/** + * @brief A class holding the parent relationships for clusters of cells + * + * This class can be used to quickly identify the connections made to a specific cluster from a parent cluster. + */ +template +class incoming_cluster_connections +{ +public: + typedef std::list incoming_connections; + + incoming_cluster_connections (const db::Layout &layout, const db::Cell &cell, const hier_clusters &hc); + + bool has_incoming (db::cell_index_type ci, size_t cluster_id) const; + const incoming_connections &incoming (db::cell_index_type ci, size_t cluster_id) const; + +private: + mutable std::set m_called_cells; + mutable std::map > m_incoming; + tl::weak_ptr mp_layout; + tl::weak_ptr > mp_hc; + + void ensure_computed (db::cell_index_type ci) const; + void ensure_computed_parent (db::cell_index_type ci) const; +}; + } #endif diff --git a/src/db/unit_tests/dbHierNetworkProcessorTests.cc b/src/db/unit_tests/dbHierNetworkProcessorTests.cc index fab9c5d49..d527e4b7d 100644 --- a/src/db/unit_tests/dbHierNetworkProcessorTests.cc +++ b/src/db/unit_tests/dbHierNetworkProcessorTests.cc @@ -546,57 +546,129 @@ static void run_hc_test (tl::TestBase *_this, const std::string &file, const std db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/" + au_file); } +static void run_hc_test_with_backannotation (tl::TestBase *_this, const std::string &file, const std::string &au_file) +{ + db::Layout ly; + unsigned int l1 = 0, l2 = 0, l3 = 0; + + { + db::LayerProperties p; + db::LayerMap lmap; + + p.layer = 1; + p.datatype = 0; + lmap.map (db::LDPair (p.layer, p.datatype), l1 = ly.insert_layer ()); + ly.set_properties (l1, p); + + p.layer = 2; + p.datatype = 0; + lmap.map (db::LDPair (p.layer, p.datatype), l2 = ly.insert_layer ()); + ly.set_properties (l2, p); + + p.layer = 3; + p.datatype = 0; + lmap.map (db::LDPair (p.layer, p.datatype), l3 = ly.insert_layer ()); + ly.set_properties (l3, p); + + db::LoadLayoutOptions options; + options.get_options ().layer_map = lmap; + options.get_options ().create_other_layers = false; + + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/"; + fn += file; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly, options); + } + + normalize_layer (ly, l1); + normalize_layer (ly, l2); + normalize_layer (ly, l3); + + // connect 1 to 1, 1 to 2 and 1 to 3, but *not* 2 to 3 + db::Connectivity conn; + conn.connect (l1, l1); + conn.connect (l2, l2); + conn.connect (l3, l3); + conn.connect (l1, l2); + conn.connect (l1, l3); + + db::hier_clusters hc; + hc.build (ly, ly.cell (*ly.begin_top_down ()), db::ShapeIterator::Polygons, conn); + + std::map lm; + 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); + + CHECKPOINT(); + db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/" + au_file); +} + TEST(41_HierClusters) { run_hc_test (_this, "hc_test_l1.gds", "hc_test_au1.gds"); + run_hc_test_with_backannotation (_this, "hc_test_l1.gds", "hc_test_au1b.gds"); } TEST(42_HierClusters) { run_hc_test (_this, "hc_test_l2.gds", "hc_test_au2.gds"); + run_hc_test_with_backannotation (_this, "hc_test_l2.gds", "hc_test_au2b.gds"); } TEST(43_HierClusters) { run_hc_test (_this, "hc_test_l3.gds", "hc_test_au3.gds"); + run_hc_test_with_backannotation (_this, "hc_test_l3.gds", "hc_test_au3b.gds"); } TEST(44_HierClusters) { run_hc_test (_this, "hc_test_l4.gds", "hc_test_au4.gds"); + run_hc_test_with_backannotation (_this, "hc_test_l4.gds", "hc_test_au4b.gds"); } TEST(45_HierClusters) { run_hc_test (_this, "hc_test_l5.gds", "hc_test_au5.gds"); + run_hc_test_with_backannotation (_this, "hc_test_l5.gds", "hc_test_au5b.gds"); } TEST(46_HierClusters) { run_hc_test (_this, "hc_test_l6.gds", "hc_test_au6.gds"); + run_hc_test_with_backannotation (_this, "hc_test_l6.gds", "hc_test_au6b.gds"); } TEST(47_HierClusters) { run_hc_test (_this, "hc_test_l7.gds", "hc_test_au7.gds"); + run_hc_test_with_backannotation (_this, "hc_test_l7.gds", "hc_test_au7b.gds"); } TEST(48_HierClusters) { run_hc_test (_this, "hc_test_l8.gds", "hc_test_au8.gds"); + run_hc_test_with_backannotation (_this, "hc_test_l8.gds", "hc_test_au8b.gds"); } TEST(49_HierClusters) { run_hc_test (_this, "hc_test_l9.gds", "hc_test_au9.gds"); + run_hc_test_with_backannotation (_this, "hc_test_l9.gds", "hc_test_au9b.gds"); } TEST(50_HierClusters) { run_hc_test (_this, "hc_test_l10.gds", "hc_test_au10.gds"); + run_hc_test_with_backannotation (_this, "hc_test_l10.gds", "hc_test_au10b.gds"); } TEST(51_HierClusters) { run_hc_test (_this, "hc_test_l11.gds", "hc_test_au11.gds"); + run_hc_test_with_backannotation (_this, "hc_test_l4.gds", "hc_test_au4b.gds"); } diff --git a/testdata/algo/hc_test_au10b.gds b/testdata/algo/hc_test_au10b.gds new file mode 100644 index 0000000000000000000000000000000000000000..56a41f98c764b020ab72624f4cb15586a5c75a8f GIT binary patch literal 3032 zcma);O>9h27>3`@&+T9;qr_ikVPRoWK_WrYh`$BVV9|w$g@vC@7Zw&4Bt;u7O*GC?XFzW4p^`Odkg2#`o@ zN4_di{RUZNP=&>)jsK2JB52sO4w#ipuU^}}V)N4*L#sCQFS&AQM^(cf&0@XJeJ$}UIM zhnp+>iTErh-*GN?vt}~YK>rg*)yeqt$Na{OY&7Qk2O;Nf#F%dbO4WrvKTw_F_(CDT zRfcJeO4UQg^OLTAV@B(34@T>y?r^Rnsvh>n>mMmezgRz+Daiags?NT8{OtED&Ueo8 zM<0-7FO{m3q5mJNG!q1kTetBsrm}=uyEC$~6S|v#***3i91A$M48i=WW{FF$&%I^~ z`3bLW-c{!kD?G?|! zR?BX$@So=npV|Qkr*j=&dgZ7(8Sg`d|19@k4cDNsb^y3oc2u48`fqXXja~tST(7u0 z=%_mB_1|nW=5s$F99s(9>2g$^^!i(xY`#$P+xi_PKN|P?j~=x7Ldieg;VAjhxYysc z#=f_NK@qslOr^ZnqH(YP>RaxCgMe^Omi~H2)k&|vo%`nJ3!pu3_y6fbO4UPp{igMqw1vB-?NkTabpUH*~8KXN7YHMzjvE4AJ~84 z&=cT(i=*nK*MFqJ<_jgib-APDN8?`qu{AbdDETLOo+>3j8u$9o4a&L2`6H{jj=I@L zrRt>Df2_#$k!4Pi`=|vtQBtZN((CW-v)A>qhvL8YSgHC1|Gq!hkDTGMex~&U7Zy0G zPR8>q{GAK!dKb#Rm-nbr&gE#_>z8#SXMfL5&SNKVn{#2QdPuLonB()k0E#(2H*3Gy zrc^zo*Dvcs@{csw+}3fW>XYXmhRrz)n|qXNM(U9FrqmUUd-J<9z)aRGoHqzuWB-+^ slU{%OTVvjr`Tiq64ROACjwn?pz5X))_mb;`;(J(dR9*f2KO~jHFTNxhQ~&?~ literal 0 HcmV?d00001 diff --git a/testdata/algo/hc_test_au1b.gds b/testdata/algo/hc_test_au1b.gds new file mode 100644 index 0000000000000000000000000000000000000000..e1f2615cf0fe676636519693db3807ef6812de1b GIT binary patch literal 1386 zcmbW0y-EW?6opTAH=7lsD5TuNB8?ER6hQ>VLNTC43bC^A=LIY+()tF1DeP=4Ei5g> z$_KEp5GxA{A&Eu}9`7W%%xtlOQ!HON;mh8+bAlK_u#L13l%7#Wf&ykybw48s;`;gu zPzj4m%O~?2cNcF9tJibqXFCm~#Xr0_ZftG=Q3Avhf&6kj833qFg=GIpAD~ckAI%LB zP3QP*kw0aUEg+l$iWQ~ihWUQ?h-{~%VgH!y^(-}Sr}_TJz4%Siu=@av?OJNyZf5+z zo?m8tkxlFk8P&zVm4l9`xzIhoV!Z literal 0 HcmV?d00001 diff --git a/testdata/algo/hc_test_au2b.gds b/testdata/algo/hc_test_au2b.gds new file mode 100644 index 0000000000000000000000000000000000000000..cd520f4de6ceac1d17ea49facc4e8e322a11f9c9 GIT binary patch literal 2218 zcmbW2KWI}?6vj_pUS3{flqek>-r&$dAs|9Q1rgK?iUl1qh&VX-XL0D@(7~ZY7dM9v zf*m>tIyiLb(80l>NC!s;hYrOlSdr4CZEF4;&-ZQ)_uk?aOyKbg-^431D4Dr+ooKRHx_a&9#oM3X?OblGonL-)ze!ms>`Rj5#s!K~ zqU3lae>XW15mCKXWbSY2LsY1{kLn=BC+Y8gUSb|rnR$t*c!sDnsZ<>d`}dwRw=-t2 z|AM*OwN$;Gh5ZL##6Qmr?tLSgcxb75d*1U$_WZKfmQ>=AVLT)LbvfvWsteuoJAUTQ zP3GS}L8)Db`S6ocbui>7DyQ;(3M7)-r(;c}>N(x@i+2Ca`&UqV5c|$+J)-LQ-30xe z54bPczc77``dg|l_ZslaeQ!#=Ylgj5qH4yhR9%?+%kbjo!Qa z_x$MKp0r(QQ)<3IR5`0uJ!imgrg#4|XeLQ_Q7Mx=*Fmp-&iW?znsd#)QuQPGcl=}Z zpW`=uqkW=%qg4G!|2(zzH`9+cMpJN3&bo#A8>&tl-uXSh{CCPHHaM}4{90n7oA)8V dcx86v(_e_SD?65|3*Gzk*8iXWmkA!n^anC9_09kQ literal 0 HcmV?d00001 diff --git a/testdata/algo/hc_test_au3b.gds b/testdata/algo/hc_test_au3b.gds new file mode 100644 index 0000000000000000000000000000000000000000..9767fc7a0b68c3b9ab90e5559462d53bce142511 GIT binary patch literal 2346 zcmbW2KWI}?6vj_pUS3{fEU|QOc!Pt3Lqvpv3L>Z(6bp99AmZTQpT(hrLkEWr9dvW( zAlRXUpo2q)4jCLAiga*v=-^PCf)y!E+NRB)Y(3`3D&3o!JH&Y)n&Tv`Z@6*tYUg(0)>ZCd(=#+x=feXKSuvL>yOdDmVd1N zeUj~;?A0gJe_&w&r$WRc4o~3)$#om`H&mTA yo%|iY+>Ysu0Zwe7|1;u7G4FkT@ygki-abOCUE0m4y3pP~XZ`;G!M36?^$op%!eIVVU5L0HfA*VMV~)$lm|38B0Vs7URTqZ+yDyE|sTd=yPZ?9I zd8)os3H$d~>7O=6xVr{4Kk-z3XS%^3`SWwHn~cO$$9RnXWgax6>SX@>IlnR0QDY9a zgp6I)n4h1OstZGYpeg13J|V#D@ zl-Ti*p+4Wqy<}9K4D281+HlzxO4Xiw%Jb)MZuO1#o*o~pBx0{;K1zg+#ey3;!Q z$NGEj>yNSf#9n&qSelehXZ$m&PUiRD;FoTfdMT~5=3dEpl&V_>{p~}X*58>wa(@*# z!(LFTP6qwbZ!+bD>=T^c@>HD+`g@r#nUun#5ul&BRH{w}{O(It?-shLDY=j-S)1Wk z%j&`g{|g^~*E?Vj+Q~S{XE!ANj;eDW<=@}n=aM?Jf(R$RS3=jgg4N0wX3SYGO=83XLRMP!KB%#g@W?g5nAb?JOuv zq@dG+!oq^W!h#qIN(%~#i?N_Ek%R+IIBtCZ%>C}3aV)%K^IhKTyP5gt&3}jy1XD;0 zLC05=kf4Bz=*@pe62udC$AG?Kbo18BtM@*?-MT)$d};B`!%3u(-xtU6?aK%gAU+!K zcjN8=z(`Ngm_}6}pfHkuR2L#FBGf)bHP0qrYN|aAzIpe3Vi3?Mj6f$@H&qw<*6-3TiI?Z_ox62P)p--V^Y60WwI!yNlzJssGOErbdi=m(!=-Dm z;X2Lvic)n;ufNQ*mwE}q_rSRe8C55}{{P6&bUr`jQFg0uoS)oV15TDQs!rzTZ}UrD zrOOG~RdJl1N2xmL^#>n$mtL_3WHc)`J)`QR*DtqS@*Zt4GtYUCSU*SAEj@nM=^On* z*LCF1Ntdb5v+G-3=%0U(d67;hJRApxnI)y_WPbjq`TD2Kxzt%Ga}OapI@@x`llde iZppLK{)4!2&-#Jxb-q6*lyhUh>Q}06Y5nZ>VTfN7tj8Dt literal 0 HcmV?d00001 diff --git a/testdata/algo/hc_test_au6b.gds b/testdata/algo/hc_test_au6b.gds new file mode 100644 index 0000000000000000000000000000000000000000..903d59d5fdeb78546de96d9f28346527e6d5c1bb GIT binary patch literal 3484 zcmaKuJ8TqJ6o!xYF$k7NHG$M972&ONJ-(sLKGCvqoAOmpm5)`QuNnee}hzw>D3mUHoAF=krri zD~Eki6n%O^N)?f)uYm7H{RI&jA1JEsJ@%hS&v^FdIw_?i@@Bu@RNaqN^`=O1Or$*Q zbe#z)l|v7S=CM_rR!U@u>a)}{Bx@0&a%j%iz!{-n#=hM>H0C(CU#=RSULy) zeJr#~*TL-iGk(?W&s1NxN$lOW>Z^NB*U6Ayq_=|S$4C)GUk*<>T~C-DznIQn^~GuK zJ;`||d)=k$No<1t?FGgQ^9L(GasN}gj<^Q=h<6?PJz(6uBNEqCovwq4zgOOxrIjd} z`tmC*ql!EoWX8tK(EW!=RwiHg|4H;-58@Wr%4aZU@|V2Z92eKfwQ#=eu!;oU&ooUXU)VgEXE&VQ^i)``>g^-9>kd&g>Ypg-mT(Rjo86N)`#_L;9C6AzAtikJay>B7xe=>rYEvk|OONhmfDP2Fj81}Q~ z{rB%}>pf1_(GP;_e=*N`L(PIOOO}aF*HMo_|Hes?!3&5xc=WF7KZ_|{AG{FuKUxwQ z6;<-+wCd)?l&+5=B$=L{%U|vhz2piC_T7<`u7g28=lCaj9?7{6BcGhEg8@I{_L#9V zwyz=&W>61Zx{lZe{ZA+0omC}QA6opJu0NU0`M=55KlAkONy}H9P15@t>&NIim>oao zXV2uGlkB_w11Vhx1Agq)6#Yi#TjxW|N7D7T`FYm1#_Y`Hw_e?|Z;`II#zNzx*6*St zqh`qRRh}0qT?Yg6w{`C#Z_0J-A^K=V3p41Y<~cZdm_tx_;o!nVUcFHS(Z) z@4?u(AEOS8uFHe)__&WIcQo?QefFP}yu;b^uphOV%bX%h2@)V8{zVFrqKFU*tRN+Y3k#)i;Uo@14}8Qkjx=U#0(^G$ofld0U3#|0S=~PfZ*b8L8Gj`0%TDKmOs{&U+`W9a#A0 z^rW;vAteaeb!Xf%Ocfr zk=lsUbuw-LU{-a#tx9g5SM7EKU0-jf?H}EO{hTWK;I_!XbfD|&b0zyqm_Nq4j7ZEF zvs19Yfr<9$IvCGCvRBmV1knzb?k!D-f={i{0_sh$w zbmFjN4OHnc>$N`Chuk#Vwd441aW#jk6ga}th&~Sy5ovS~%`?WqYa*{9GEUdQct$0A zW}f3$buhO7GWOp> zHt2`UH$`?V1-ib)f64xJR3k5v^WAwi&~>oz{|XsJ-+4hsPxDK-ij3}_D>77k@%g*O z6XtFBv(j8kx!Rjq$0D;UB8O)J+0A;-<5-pK4=kekFNlykMq!U3Ib8>n_VmFRk*(Y2 z+v)n2S}FObkJ=p@18ar8ovwqi|5B~Jd67XBA?a`5e4y)K(w^^ZJITM;R6aFZr|V#B zU#gY8w?wwXC%N+{k%Ooer|V$Sp6_r?lB`$SI$ig*`ULH5a>E~*rfgXeUV*Lh#B|>^6>OTpzFJ)()K)kG&&qV zw%7|CN1*H27i0gWK2rG}RelLI2eOY~e|=8Z!K6J;0Z*`ayk|A`SWjafOfQ(QSN#Y1 z?o1mQ@9sg%1?hTcI_2L^k1OLwe(Ujd`xfc?%6Q72>qYg?V@8}drT<6PuhDfdF@DaQ z<23Rl)f!?w7+wFr@pG+gj+#%Ny1MfiOF`Gklz;XQk+Dn0@!az0bbYLxzo?Jf2~KYI zPIBkqYl-NT&kv&iQ|8g&J~3{_Q5QZ{{TB2;8Xwr literal 0 HcmV?d00001 diff --git a/testdata/algo/hc_test_au8b.gds b/testdata/algo/hc_test_au8b.gds new file mode 100644 index 0000000000000000000000000000000000000000..816bb74d3e0e3fe3b16118409c820313636551dd GIT binary patch literal 3950 zcmbW4KWr3N5XQ%Md+YW2axsn(mN`Y1l1P9Y@mC6wqKFWRSh188E-aM7h4ZJNpm0Iq z!UaVlrJ!&TDHQJFA_WBnMG6WOQBb6yNZ}C6hso)1%n=)WfXU?h_T8{=Ek9zh(&~5m z_GaIEGxKKNN-TxKgw(nU-OEyuM7rc%>Gyw2Qi#V!Pm2r`OCNsp-Fu(@`cv!uGuIB! z|9Ey>YNfDU9LFCYl_(L3Un}6fakU^KBYj2HttGofx<>rlbW)-{va`KjR{gi4s+UEI z!y=^tqv>SW{?WARdQFwwno(`HGn&3$3)^qrg8i&2`RI3%p2>`+ug~V}3)%WH*9JT> zq3NK%e$QTY;}g}Vt0a84q59;y(R4CoFVdah`P-xjqA$JUM$=RJ;}^5} zt3LjKz9%{F)Yl!Fp2j9tCxfA={)yDCztsTxfOQ~PfD zzbqX+CQ%t#+RuEAhq@4(O09Gn?@g~tUy%Z5n48g;nMXv*EqL>sWA8PQ*WnqX>7c)& zoIN8^y5J&G{vPAa;$0n@4*K?A`QtN+%pfv3k-tp`gZ6S04mgGNg4Joaql~75zWvw! z_*F!M*&(85`6gUxMBkZBBb2`J z#edT$j9dQ~xwYnEbue-ji;S*_9Gl9>YSww~`zmLDcmdgeQH0z(2zyM)XgcWI=VJX9 z@`4vhUmcpuXgcWI=X`zemdGC1ko#_n9D%Qmrh}>dE_{95e2smS`j2zKwHx~+j>kXy z9RKwrfO>*i!ISA5+>_Dc-po?Wd@qmi>^!RM zNfHhm%eqOiVLF+cf6o3sD)%ZXDf#e#TZ_^3)y1&=8oG$x?3(O+M$^}lkiF|d_f9%C zu^)QJRgI>Df%PNj2UHsyj%(*oFR=!r>0rR#by0Rw-p?0YH#eG&4jZ(8JkJh>`~f#n z3z8EVO-F|d+OOXg**^iFfo~!X&(CBueg8z*p54EUyd!HDIggB{qb~)=uP>?A2XTX| z7m&YG8BMPbhVAbm_v$mMB=-PMLq^l11ep)=!b4OOC@R(2S$e^r2w4_8j2VX46 zA4k)-^^crAz7Wz=Gud;4`zIq$)$VzC{JRUTW|Pbx?qMVQk9!`r=N@Ma$o8Du|3=fd zeFb^*cX{(CW7eQ8_fJOCK|g;ydwwCP-iaKSxsL`Aiw;e{6NT*IyDOb95RkrS%`>K7 wChmD~e15sHW|P%v*v@1$9cSsFJ$=1WaX!C~v7Ua5UfQAQD-~ytb5s<`e+V(f<^TWy literal 0 HcmV?d00001 diff --git a/testdata/algo/hc_test_au9b.gds b/testdata/algo/hc_test_au9b.gds new file mode 100644 index 0000000000000000000000000000000000000000..3e89d8674d82a66843142b212dc4141c40e9deb6 GIT binary patch literal 1664 zcmai!FKiT15XQg#_iibB<$AO!AuABb5<)^kNE!kK0ikITCrA~dfI(IuDk=~qK_C!K zKva-mDiDau3PKQ-2n2!<1Oh>F*HYlZF!SCH`xbcRCA+`7nf>0(&b(O|#PM~MQQZ1~ z0y!d_K-d3`JT|jeW`OY|J9pv!nX9j!eK~t+^W^&Dg&xXmADuB5=jY~-=74F(yt5gN z0ZergzI!Wr$bVh~O3#&!0ci{S#xWe{)W4z-4d3g}dF~ZZ(l@n`@M%GtGjbADE)$okschr`W!->mBeRDR2e zWnh$ZSF%q1{`)rctvfEhu=r^6_)W>H@(1P%delz$f0#PYc6(vx~AHhLA^QeVhbk=uK!X^$*J;( z^-p1!VM?vq8#Totc3!^z_MiDj1DC(ddOmbBFH}1-sJFW>+Pkg4