From 78617930dd0f24cddc6ba031081c05e87c82b665 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 13 Feb 2019 22:41:12 +0100 Subject: [PATCH] Hierarchical implementation of self-overlap merge. --- src/db/db/dbDeepRegion.cc | 130 +++++++++++++++++-------- src/db/db/dbRegion.cc | 9 +- src/db/db/dbRegion.h | 2 +- src/db/unit_tests/dbDeepRegionTests.cc | 40 ++++++++ testdata/algo/deep_region_au16.gds | Bin 0 -> 1320 bytes testdata/algo/deep_region_au7.gds | Bin 7834 -> 2074 bytes 6 files changed, 139 insertions(+), 42 deletions(-) create mode 100644 testdata/algo/deep_region_au16.gds diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index 9955d9486..459a0088d 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -294,16 +294,31 @@ public: m_ep.set_base_verbosity (vb); } - db::Shapes &merged (size_t cid, db::cell_index_type ci, bool initial = true) + db::Shapes &merged (size_t cid, db::cell_index_type ci, unsigned int min_wc = 0) + { + return compute_merged (cid, ci, true, min_wc); + } + + void erase (size_t cid, db::cell_index_type ci) + { + m_merged_cluster.erase (std::make_pair (cid, ci)); + } + +private: + std::map, db::Shapes> m_merged_cluster; + unsigned int m_layer; + db::Layout *mp_layout; + const db::hier_clusters *mp_hc; + bool m_min_coherence; + db::EdgeProcessor m_ep; + + db::Shapes &compute_merged (size_t cid, db::cell_index_type ci, bool initial, unsigned int min_wc) { std::map, db::Shapes>::iterator s = m_merged_cluster.find (std::make_pair (cid, ci)); // some sanity checks: initial clusters are single-use, are never generated twice and cannot be retrieved again if (initial) { tl_assert (s == m_merged_cluster.end ()); - m_done.insert (std::make_pair (cid, ci)); - } else { - tl_assert (m_done.find (std::make_pair (cid, ci)) == m_done.end ()); } if (s != m_merged_cluster.end ()) { @@ -315,51 +330,60 @@ public: const db::connected_clusters &cc = mp_hc->clusters_per_cell (ci); const db::local_cluster &c = cc.cluster_by_id (cid); - std::list > merged_child_clusters; + if (min_wc > 0) { - const db::connected_clusters::connections_type &conn = cc.connections_for_cluster (cid); - for (db::connected_clusters::connections_type::const_iterator i = conn.begin (); i != conn.end (); ++i) { - const db::Shapes &cc_shapes = merged (i->id (), i->inst ().inst_ptr.cell_index (), false); - merged_child_clusters.push_back (std::make_pair (&cc_shapes, i->inst ().complex_trans ())); - } + // We cannot merge bottom-up in min_wc mode, so we just use the recursive cluster iterator - m_ep.clear (); + m_ep.clear (); - size_t pi = 0; + size_t pi = 0; - for (std::list >::const_iterator i = merged_child_clusters.begin (); i != merged_child_clusters.end (); ++i) { - for (db::Shapes::shape_iterator s = i->first->begin (db::ShapeIterator::All); ! s.at_end (); ++s) { - if (s->is_polygon ()) { - db::Polygon poly; - s->polygon (poly); - m_ep.insert (poly.transformed (i->second), pi++); + for (db::recursive_cluster_shape_iterator s = db::recursive_cluster_shape_iterator (*mp_hc, m_layer, ci, cid); !s.at_end (); ++s) { + db::Polygon poly = s->obj (); + poly.transform (s.trans () * db::ICplxTrans (s->trans ())); + m_ep.insert (poly, pi++); + } + + } else { + + std::list > merged_child_clusters; + + const db::connected_clusters::connections_type &conn = cc.connections_for_cluster (cid); + for (db::connected_clusters::connections_type::const_iterator i = conn.begin (); i != conn.end (); ++i) { + const db::Shapes &cc_shapes = compute_merged (i->id (), i->inst ().inst_ptr.cell_index (), false, min_wc); + merged_child_clusters.push_back (std::make_pair (&cc_shapes, i->inst ().complex_trans ())); + } + + m_ep.clear (); + + size_t pi = 0; + + for (std::list >::const_iterator i = merged_child_clusters.begin (); i != merged_child_clusters.end (); ++i) { + for (db::Shapes::shape_iterator s = i->first->begin (db::ShapeIterator::All); ! s.at_end (); ++s) { + if (s->is_polygon ()) { + db::Polygon poly; + s->polygon (poly); + m_ep.insert (poly.transformed (i->second), pi++); + } } } - } - for (db::local_cluster::shape_iterator s = c.begin (m_layer); !s.at_end (); ++s) { - db::Polygon poly = s->obj (); - poly.transform (s->trans ()); - m_ep.insert (poly, pi++); + for (db::local_cluster::shape_iterator s = c.begin (m_layer); !s.at_end (); ++s) { + db::Polygon poly = s->obj (); + poly.transform (s->trans ()); + m_ep.insert (poly, pi++); + } + } // and run the merge step - db::MergeOp op (0); + db::MergeOp op (min_wc); db::PolygonRefToShapesGenerator pr (mp_layout, &s->second); db::PolygonGenerator pg (pr, false /*don't resolve holes*/, m_min_coherence); m_ep.process (pg, op); return s->second; } - -private: - std::map, db::Shapes> m_merged_cluster; - std::set > m_done; - unsigned int m_layer; - db::Layout *mp_layout; - const db::hier_clusters *mp_hc; - bool m_min_coherence; - db::EdgeProcessor m_ep; }; } @@ -402,7 +426,7 @@ DeepRegion::ensure_merged_polygons_valid () const if (cc.is_root (*cl)) { db::Shapes &s = cm.merged (*cl, c->cell_index ()); c->shapes (m_merged_polygons.layer ()).insert (s); - s.clear (); // not needed anymore + cm.erase (*cl, c->cell_index ()); // not needed anymore } } } @@ -873,8 +897,7 @@ DeepRegion::merged_in_place () RegionDelegate * DeepRegion::merged_in_place (bool min_coherence, unsigned int min_wc) { - // TODO: can probably be optimized - return db::AsIfFlatRegion::merged_in_place (min_coherence, min_wc); + return merged (min_coherence, min_wc); } RegionDelegate * @@ -898,8 +921,39 @@ DeepRegion::merged () const RegionDelegate * DeepRegion::merged (bool min_coherence, unsigned int min_wc) const { - // TODO: can probably be optimized - return db::AsIfFlatRegion::merged (min_coherence, min_wc); + tl::SelfTimer timer (tl::verbosity () > base_verbosity (), "Ensure merged polygons"); + + db::Layout &layout = const_cast (m_deep_layer.layout ()); + + db::hier_clusters hc; + db::Connectivity conn; + conn.connect (m_deep_layer); + // TODO: this uses the wrong verbosity inside ... + hc.build (layout, m_deep_layer.initial_cell (), db::ShapeIterator::Polygons, conn); + + // collect the clusters and merge them into big polygons + // NOTE: using the ClusterMerger we merge bottom-up forming bigger and bigger polygons. This is + // hopefully more efficient that collecting everything and will lead to reuse of parts. + + DeepLayer dl_out (m_deep_layer.derived ()); + + ClusterMerger cm (m_deep_layer.layer (), layout, hc, min_coherence, report_progress (), progress_desc ()); + cm.set_base_verbosity (base_verbosity ()); + + for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { + const db::connected_clusters &cc = hc.clusters_per_cell (c->cell_index ()); + for (db::connected_clusters::all_iterator cl = cc.begin_all (); ! cl.at_end (); ++cl) { + if (cc.is_root (*cl)) { + db::Shapes &s = cm.merged (*cl, c->cell_index (), min_wc); + c->shapes (dl_out.layer ()).insert (s); + cm.erase (*cl, c->cell_index ()); // not needed anymore + } + } + } + + db::DeepRegion *res = new db::DeepRegion (dl_out); + res->set_is_merged (true); + return res; } RegionDelegate * diff --git a/src/db/db/dbRegion.cc b/src/db/db/dbRegion.cc index fb976cd9d..01b5392d9 100644 --- a/src/db/db/dbRegion.cc +++ b/src/db/db/dbRegion.cc @@ -60,7 +60,7 @@ Region::~Region () Region &Region::operator= (const Region &other) { if (this != &other) { - set_delegate (other.mp_delegate->clone ()); + set_delegate (other.mp_delegate->clone (), false); } return *this; } @@ -94,9 +94,13 @@ Region::iter () const } void -Region::set_delegate (RegionDelegate *delegate) +Region::set_delegate (RegionDelegate *delegate, bool keep_attributes) { if (delegate != mp_delegate) { + if (keep_attributes && delegate && mp_delegate) { + // copy the basic attributes like #threads etc. + delegate->RegionDelegate::operator= (*mp_delegate); + } delete mp_delegate; mp_delegate = delegate; } @@ -159,7 +163,6 @@ Region::flat_region () if (! region) { region = new FlatRegion (); if (mp_delegate) { - region->RegionDelegate::operator= (*mp_delegate); region->insert_seq (begin ()); } if (mp_delegate) { diff --git a/src/db/db/dbRegion.h b/src/db/db/dbRegion.h index 77da2d894..4ac0cda62 100644 --- a/src/db/db/dbRegion.h +++ b/src/db/db/dbRegion.h @@ -1786,7 +1786,7 @@ private: RegionDelegate *mp_delegate; - void set_delegate (RegionDelegate *delegate); + void set_delegate (RegionDelegate *delegate, bool keep_attributes = true); FlatRegion *flat_region (); }; diff --git a/src/db/unit_tests/dbDeepRegionTests.cc b/src/db/unit_tests/dbDeepRegionTests.cc index 2126434eb..bd72575fb 100644 --- a/src/db/unit_tests/dbDeepRegionTests.cc +++ b/src/db/unit_tests/dbDeepRegionTests.cc @@ -868,6 +868,46 @@ TEST(15_Filtered) } } +TEST(16_MergeWithMinWC) +{ + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/deep_region_area_peri_l1.gds"; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly); + } + + db::cell_index_type top_cell_index = *ly.begin_top_down (); + db::Cell &top_cell = ly.cell (top_cell_index); + + db::DeepShapeStore dss; + + unsigned int l1 = ly.get_layer (db::LayerProperties (1, 0)); + + db::Region r1 (db::RecursiveShapeIterator (ly, top_cell, l1), dss); + db::Region r1_merged_wc0 = r1.merged (true, 0); + db::Region r1_merged_wc1 = r1.merged (true, 1); + db::Region r1_merged_wc2 = r1.merged (true, 2); + EXPECT_EQ (r1_merged_wc0.is_merged (), true); + EXPECT_EQ (r1_merged_wc1.is_merged (), true); + EXPECT_EQ (r1_merged_wc2.is_merged (), true); + + + { + db::Layout target; + unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index)); + + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), r1_merged_wc0); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r1_merged_wc1); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), r1_merged_wc2); + + CHECKPOINT(); + db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au16.gds"); + } +} + TEST(100_Integration) { db::Layout ly; diff --git a/testdata/algo/deep_region_au16.gds b/testdata/algo/deep_region_au16.gds new file mode 100644 index 0000000000000000000000000000000000000000..eea9b61617c55d8ba03f434a9e656b40c1baf604 GIT binary patch literal 1320 zcma)*KTH%+5XQfKcl%i2F#ItldY5pW7DPLRK+GN5s6i>FC^l+ zQcLG|guE)O$gGdr|C_NX8BeL3dB1#bu~S(TTBq6qCL6I%^kk9AMhI&MF*2-fC6Y}z z*~Jt!daSm>$#w(D(!P@KVK7&8`eT*krBsnhI-gD?@4T8e>ug)D-YK{z2;uy*Zk^1o zziuU_(5_1F>iX8bpLRYLMoS@l%R>10fCO$&1NZj}$~5r%K&K)M;jqnk!KkA?`sz7< zQ#P5WqT_^)+DKkqDroD%e*RR?*|#Kdz6VM2Rrf+^>%wmRU+0xOLEriAYJcp@`pDz` z^bhI(?Rq$&Px6J#f_)f&$gH?-l>Rs;_NkP0?bk>h<3`Kd(|;xZ-+ozre$P6ak7IqK zoH$)KzB!I@+0V~9pgsHt8pXiGHw)K8aL86<3{UC LsPmWqwp_*^X$5eR literal 0 HcmV?d00001 diff --git a/testdata/algo/deep_region_au7.gds b/testdata/algo/deep_region_au7.gds index 2c7a8f312fb14d4fc7d28db94b35640b03d97e41..4d0741a36355ffef889a2ffbb1643cbf9ffdedee 100644 GIT binary patch delta 200 zcmbPbJ4--`fsKKQDS|9*4;U6 ZN$APpH*fO?=4{5vw*@WPfa+LS7y!s^Bv}9e literal 7834 zcmc(iKTKO!6vi*Mc?QR%4xvibSQJGGN+c>MMU6^BR4OBaf(#)}M3Ad8WX!<8$iR@L zQicxM%D@n*3qyts9T*r;Cx#4+86q`f28J%JXx#Jp+@t5?a&Pdds#roFI_LiGIevck z&*u`C$t=5aS0?|v%eZcL!Ij)ct^d28OfoRsn@c^4holO%K1`{OQGaIVlVRI!w8G~TT_d~)aL@8oRZ=!9(YY1gK6 zG=p+^w;2ZfP@| ztG`ThC#{e_>$EM@8VzWEx6$}(KUIm-3T<6sXZ#!9d;^+02(2*eAYB{0L$LA+<9wJm ztk9PFv?C1B_ruOW+T3AihY*!GX`p}l?$k4OsDySWaQQc)693l@q3ZW;@wnbC=Fa3q zB_8Md*0_Ht>Yu%wD*E^NVE?59u2VW-u75&Q;_>?D-}1QgZ<+hJCMxkbe_@aNhob*a z)>B3QJ|FD=Vwvk)EHhW8-vaZL>7Byw;`2d%@CJ_?yusXO&qO8O)F6MU#Qj52_tJi< z=-=mq{1tz~U7^zf{P3YD*Z27#fAtBEyZVH=Yk!DJJl_AvD)$dX{m-dqQS|Tg!TO`S zTxWEbxi2n@N<3bF{1uNIf5qHHMO5N({;TKQKNNjmf0!!z_xWJ|lSQsGS!C{;by11O z>rajFxTz85Zax*2c$}Z6_R%L4{ZGG0RpO+<{wsB^Q>imIt!BSFEjuBV^N96`5%tBe<=E2eU>Wv z_xV8obnd>UvyX1((A*ZEzoHV)PK4jT{1|vT_egQm$N48J@fd$@lX)mOoIj%AeLm1X z?e8y{hl0cYFACo0gZ%Ii^H6ZZhpB@1`5-^G#yk`}_CHbZJ|E;K_n3!*!~P=*-sgk- zOo@3YIIMqB@ID{p7gm{vg2Va~1@H4g{=swRq2TcTi-Pz00ME`yoRBypQHi%Xq_+DL z902`MZE(0hiAp@iq@dp2*c!PgYyurUH z-r!#pZ}2aQH~1ID8~lsn4gN*(2LGaXgMU%H_a{xCg8SPk{EOlZ{zdTy|Dt$|1b8?ZCe% z-r!#pZ}2aQH~1ID8~lsnC-?aN55>Lz6#hl=2LGb?h1HJzi{cIbrG+>7mlmGxuJp`s tPwl|JDBj>-6mRe^iZ}Qd#T)#K;tl>q@dp2*c!PgYd?)@TPfIN4{sGUgN)-SA