diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index a4100ef19..c869ac5af 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -1070,56 +1070,163 @@ DeepRegion::snapped (db::Coord gx, db::Coord gy) return res.release (); } +namespace +{ + +class PolygonToEdgeLocalOperation + : public local_operation +{ +public: + PolygonToEdgeLocalOperation () + : local_operation () + { + // .. nothing yet .. + } + + virtual db::Coord dist () const { return 1; } + virtual bool requests_single_subjects () const { return true; } + virtual std::string description () const { return std::string ("polygon to edges"); } + + virtual void do_compute_local (db::Layout * /*layout*/, const shape_interactions &interactions, std::vector > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const + { + db::EdgeProcessor ep; + + for (shape_interactions::subject_iterator s = interactions.begin_subjects (); s != interactions.end_subjects (); ++s) { + ep.insert (s->second); + } + + if (interactions.num_intruders () == 0) { + + db::EdgeToEdgeSetGenerator eg (results.front ()); + db::MergeOp op (0); + ep.process (eg, op); + + } else { + + // With intruders: to compute our local contribution we take the edges without and with intruders + // and deliver what is in both sets + + db::MergeOp op (0); + + std::vector edges1; + db::EdgeContainer ec1 (edges1); + ep.process (ec1, op); + + ep.clear (); + + for (shape_interactions::subject_iterator s = interactions.begin_subjects (); s != interactions.end_subjects (); ++s) { + ep.insert (s->second); + } + for (shape_interactions::intruder_iterator i = interactions.begin_intruders (); i != interactions.end_intruders (); ++i) { + ep.insert (i->second.second); + } + + std::vector edges2; + db::EdgeContainer ec2 (edges2); + ep.process (ec2, op); + + // Runs the boolean AND between the result with and without intruders + + db::box_scanner scanner; + scanner.reserve (edges1.size () + edges2.size ()); + + for (std::vector::const_iterator i = edges1.begin (); i != edges1.end (); ++i) { + scanner.insert (i.operator-> (), 0); + } + for (std::vector::const_iterator i = edges2.begin (); i != edges2.end (); ++i) { + scanner.insert (i.operator-> (), 1); + } + + EdgeBooleanClusterCollector > cluster_collector (&results.front (), EdgeAnd); + scanner.process (cluster_collector, 1, db::box_convert ()); + + } + + } +}; + +} + EdgesDelegate * DeepRegion::edges (const EdgeFilterBase *filter) const { - const db::DeepLayer &polygons = merged_deep_layer (); + if (! filter && merged_semantics ()) { - std::unique_ptr vars; + // Hierarchical edge detector - no pre-merge required - if (filter && filter->vars ()) { + const db::DeepLayer &polygons = deep_layer (); - vars.reset (new db::VariantsCollectorBase (filter->vars ())); + db::PolygonToEdgeLocalOperation op; - vars->collect (polygons.layout (), polygons.initial_cell ()); + db::local_processor proc (const_cast (&polygons.layout ()), + const_cast (&polygons.initial_cell ()), + polygons.breakout_cells ()); - // NOTE: m_merged_polygons is mutable, so why is the const_cast needed? - const_cast (polygons).separate_variants (*vars); + proc.set_description (progress_desc ()); + proc.set_report_progress (report_progress ()); + proc.set_base_verbosity (base_verbosity ()); + proc.set_threads (polygons.store ()->threads ()); - } + // a boolean core makes somewhat better hierarchy + proc.set_boolean_core (true); - db::Layout &layout = const_cast (polygons.layout ()); + std::unique_ptr res (new db::DeepEdges (polygons.derived ())); - std::unique_ptr res (new db::DeepEdges (polygons.derived ())); - for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { + proc.run (&op, polygons.layer (), foreign_idlayer (), res->deep_layer ().layer ()); + + return res.release (); + + } else { + + const db::DeepLayer &polygons = merged_deep_layer (); + + std::unique_ptr vars; + + if (filter && filter->vars ()) { + + vars.reset (new db::VariantsCollectorBase (filter->vars ())); + + vars->collect (polygons.layout (), polygons.initial_cell ()); + + // NOTE: m_merged_polygons is mutable, so why is the const_cast needed? + const_cast (polygons).separate_variants (*vars); - db::ICplxTrans tr; - if (vars.get ()) { - const std::map &v = vars->variants (c->cell_index ()); - tl_assert (v.size () == size_t (1)); - tr = v.begin ()->first; } - const db::Shapes &s = c->shapes (polygons.layer ()); - db::Shapes &st = c->shapes (res->deep_layer ().layer ()); + db::Layout &layout = const_cast (polygons.layout ()); - for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) { + std::unique_ptr res (new db::DeepEdges (polygons.derived ())); + for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { - db::Polygon poly; - si->polygon (poly); + db::ICplxTrans tr; + if (vars.get ()) { + const std::map &v = vars->variants (c->cell_index ()); + tl_assert (v.size () == size_t (1)); + tr = v.begin ()->first; + } - for (db::Polygon::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end (); ++e) { - if (! filter || filter->selected ((*e).transformed (tr))) { - st.insert (*e); + const db::Shapes &s = c->shapes (polygons.layer ()); + db::Shapes &st = c->shapes (res->deep_layer ().layer ()); + + for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) { + + db::Polygon poly; + si->polygon (poly); + + for (db::Polygon::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end (); ++e) { + if (! filter || filter->selected ((*e).transformed (tr))) { + st.insert (*e); + } } + } } - } + res->set_is_merged (merged_semantics () || is_merged ()); + return res.release (); - res->set_is_merged (merged_semantics () || is_merged ()); - return res.release (); + } } RegionDelegate * diff --git a/src/db/db/dbHierProcessor.cc b/src/db/db/dbHierProcessor.cc index df90ff1ba..8d39b1a00 100644 --- a/src/db/db/dbHierProcessor.cc +++ b/src/db/db/dbHierProcessor.cc @@ -409,6 +409,16 @@ local_processor_cell_contexts::create (const context_key_type &intru return &m_contexts[intruders]; } +template +static void +subtract_set (std::unordered_set &res, const std::unordered_set &other) +{ + // for everything else, we don't use a boolean core but just set intersection + for (typename std::unordered_set::const_iterator o = other.begin (); o != other.end (); ++o) { + res.erase (*o); + } +} + template static void subtract (std::unordered_set &res, const std::unordered_set &other, db::Layout *layout, const db::local_processor *proc) @@ -417,6 +427,11 @@ subtract (std::unordered_set &res, const std::unordered_setboolean_core ()) { + subtract_set (res, other); + return; + } + size_t max_vertex_count = proc->max_vertex_count (); double area_ratio = proc->area_ratio (); @@ -449,14 +464,60 @@ subtract (std::unordered_set &res, const std::unordered_set +static void +subtract (std::unordered_set &res, const std::unordered_set &other, db::Layout *layout, const db::local_processor *proc) +{ + if (other.empty ()) { + return; + } + + if (! proc->boolean_core ()) { + subtract_set (res, other); + return; + } + + db::box_scanner scanner; + scanner.reserve (res.size () + other.size ()); + + for (std::unordered_set::const_iterator i = res.begin (); i != res.end (); ++i) { + scanner.insert (i.operator-> (), 0); + } + for (std::unordered_set::const_iterator i = other.begin (); i != other.end (); ++i) { + scanner.insert (i.operator-> (), 1); + } + + std::unordered_set result; + EdgeBooleanClusterCollector > cluster_collector (&result, EdgeNot); + scanner.process (cluster_collector, 1, db::box_convert ()); + + res.swap (result); +} + template static void subtract (std::unordered_set &res, const std::unordered_set &other, db::Layout * /*layout*/, const db::local_processor * /*proc*/) { - // for edges, we don't use a boolean core but just set intersection - for (typename std::unordered_set::const_iterator o = other.begin (); o != other.end (); ++o) { - res.erase (*o); - } + subtract_set (res, other); +} + +// determines the default boolean core flag per result type + +namespace +{ + +template +struct default_boolean_core +{ + bool operator() () const { return false; } +}; + +template <> +struct default_boolean_core +{ + bool operator() () const { return true; } +}; + } namespace { @@ -1221,7 +1282,7 @@ local_processor::local_processor (db::Layout *layout, db::Cell *top, : mp_subject_layout (layout), mp_intruder_layout (layout), mp_subject_top (top), mp_intruder_top (top), mp_subject_breakout_cells (breakout_cells), mp_intruder_breakout_cells (breakout_cells), - m_report_progress (true), m_nthreads (0), m_max_vertex_count (0), m_area_ratio (0.0), m_base_verbosity (30), m_progress (0), mp_progress (0) + m_report_progress (true), m_nthreads (0), m_max_vertex_count (0), m_area_ratio (0.0), m_boolean_core (default_boolean_core () ()), m_base_verbosity (30), m_progress (0), mp_progress (0) { // .. nothing yet .. } @@ -1231,7 +1292,7 @@ local_processor::local_processor (db::Layout *subject_layout, db::Ce : mp_subject_layout (subject_layout), mp_intruder_layout (intruder_layout), mp_subject_top (subject_top), mp_intruder_top (intruder_top), mp_subject_breakout_cells (subject_breakout_cells), mp_intruder_breakout_cells (intruder_breakout_cells), - m_report_progress (true), m_nthreads (0), m_max_vertex_count (0), m_area_ratio (0.0), m_base_verbosity (30), m_progress (0), mp_progress (0) + m_report_progress (true), m_nthreads (0), m_max_vertex_count (0), m_area_ratio (0.0), m_boolean_core (default_boolean_core () ()), m_base_verbosity (30), m_progress (0), mp_progress (0) { // .. nothing yet .. } @@ -1535,6 +1596,11 @@ void local_processor::compute_contexts (local_processor_contexts ()); } + // this cache should reduce the effort of checking array vs. array + typedef std::pair > effective_instance_cache_key_type; + typedef std::map > effective_instance_cache_type; + effective_instance_cache_type effective_instance_cache; + for (typename std::unordered_map::const_iterator i = interactions.begin (); i != interactions.end (); ++i) { db::Cell &subject_child_cell = mp_subject_layout->cell (i->first->object ().cell_index ()); @@ -1568,17 +1634,28 @@ void local_processor::compute_contexts (local_processor_contexts inst_bcii (*mp_intruder_layout, ail); for (std::unordered_set::const_iterator j = i->second.first.begin (); j != i->second.first.end (); ++j) { + for (db::CellInstArray::iterator k = (*j)->begin_touching (safe_box_enlarged (nbox, -1, -1), inst_bcii); ! k.at_end (); ++k) { + db::ICplxTrans tk = (*j)->complex_trans (*k); // NOTE: no self-interactions if (i->first != *j || tn != tk) { + // optimize the intruder instance so it will be as low as possible - std::pair ei = effective_instance (contexts.subject_layer (), i->first->object ().cell_index (), ail, (*j)->object ().cell_index (), tni * tk, dist); - if (ei.first) { - intruders_below.first.insert (ei.second); + effective_instance_cache_key_type key (ail, std::make_pair ((*j)->object ().cell_index (), tni * tk)); + effective_instance_cache_type::iterator cached = effective_instance_cache.find (key); + if (cached == effective_instance_cache.end ()) { + std::pair ei = effective_instance (contexts.subject_layer (), i->first->object ().cell_index (), ail, (*j)->object ().cell_index (), tni * tk, dist); + cached = effective_instance_cache.insert (std::make_pair (key, ei)).first; } + if (cached->second.first) { + intruders_below.first.insert (cached->second.second); + } + } + } + } } diff --git a/src/db/db/dbHierProcessor.h b/src/db/db/dbHierProcessor.h index c65da727f..712ebf53e 100644 --- a/src/db/db/dbHierProcessor.h +++ b/src/db/db/dbHierProcessor.h @@ -479,6 +479,16 @@ public: return m_area_ratio; } + void set_boolean_core (double boolean_core) + { + m_boolean_core = boolean_core; + } + + double boolean_core () const + { + return m_boolean_core; + } + private: template friend class local_processor_cell_contexts; template friend class local_processor_context_computation_task; @@ -494,6 +504,7 @@ private: unsigned int m_nthreads; size_t m_max_vertex_count; double m_area_ratio; + bool m_boolean_core; int m_base_verbosity; mutable std::unique_ptr > > mp_cc_job; mutable size_t m_progress; diff --git a/src/db/unit_tests/dbDeepRegionTests.cc b/src/db/unit_tests/dbDeepRegionTests.cc index f02a2f1db..bccfefbaa 100644 --- a/src/db/unit_tests/dbDeepRegionTests.cc +++ b/src/db/unit_tests/dbDeepRegionTests.cc @@ -800,7 +800,7 @@ TEST(13_Edges) db::Region r3 (db::RecursiveShapeIterator (ly, top_cell, l3), dss); db::Edges r3edges = r3.edges (); - EXPECT_EQ (r3edges.is_merged (), true); + EXPECT_EQ (r3edges.is_merged (), false); db::EdgeLengthFilter f (0, 500, true); db::Edges r3edges_filtered = r3.edges (f); @@ -816,6 +816,46 @@ TEST(13_Edges) db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au13.gds"); } +TEST(13b_Edges) +{ + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/deep_region_edges.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)); + unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0)); + + db::Region r1 (db::RecursiveShapeIterator (ly, top_cell, l1), dss); + db::Edges r1edges = r1.edges (); + EXPECT_EQ (r1edges.is_merged (), false); + + db::Region r2 (db::RecursiveShapeIterator (ly, top_cell, l2), dss); + db::Edges r2edges = r2.edges (); + EXPECT_EQ (r2edges.is_merged (), false); + + + 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 (1, 0)), r1); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (2, 0)), r2); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r1edges); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), r2edges); + + CHECKPOINT(); + db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au13b.gds"); +} + TEST(14_Interacting) { db::Layout ly; @@ -936,7 +976,7 @@ TEST(14_Interacting) target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (32, 0)), r6r.selected_interacting (r1er)); target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (33, 0)), r6r.selected_not_interacting (r1er)); - EXPECT_EQ (r6.selected_interacting (r1e).is_merged (), true); + EXPECT_EQ (r6.selected_interacting (r1e).is_merged (), false); EXPECT_EQ (r6.selected_interacting (r1er).is_merged (), false); EXPECT_EQ (r6r.selected_interacting (r1e).is_merged (), false); EXPECT_EQ (r6r.selected_interacting (r1er).is_merged (), false); diff --git a/testdata/algo/deep_edges_au10.gds b/testdata/algo/deep_edges_au10.gds index 13ded556b..c809ae30c 100644 Binary files a/testdata/algo/deep_edges_au10.gds and b/testdata/algo/deep_edges_au10.gds differ diff --git a/testdata/algo/deep_edges_au3.gds b/testdata/algo/deep_edges_au3.gds index 62914f828..4bb15fdec 100644 Binary files a/testdata/algo/deep_edges_au3.gds and b/testdata/algo/deep_edges_au3.gds differ diff --git a/testdata/algo/deep_edges_au4.gds b/testdata/algo/deep_edges_au4.gds index f91ff8526..c9a752daa 100644 Binary files a/testdata/algo/deep_edges_au4.gds and b/testdata/algo/deep_edges_au4.gds differ diff --git a/testdata/algo/deep_region_au13.gds b/testdata/algo/deep_region_au13.gds index ade409f90..14c9e6e4e 100644 Binary files a/testdata/algo/deep_region_au13.gds and b/testdata/algo/deep_region_au13.gds differ diff --git a/testdata/algo/deep_region_au13b.gds b/testdata/algo/deep_region_au13b.gds new file mode 100644 index 000000000..98ccf1b00 Binary files /dev/null and b/testdata/algo/deep_region_au13b.gds differ diff --git a/testdata/algo/deep_region_au14b.gds b/testdata/algo/deep_region_au14b.gds index d02050199..fd5afab25 100644 Binary files a/testdata/algo/deep_region_au14b.gds and b/testdata/algo/deep_region_au14b.gds differ diff --git a/testdata/algo/deep_region_au25b.gds b/testdata/algo/deep_region_au25b.gds index 8d0ac52ad..5d0c39497 100644 Binary files a/testdata/algo/deep_region_au25b.gds and b/testdata/algo/deep_region_au25b.gds differ diff --git a/testdata/algo/deep_region_edges.gds b/testdata/algo/deep_region_edges.gds new file mode 100644 index 000000000..c0a9af034 Binary files /dev/null and b/testdata/algo/deep_region_edges.gds differ diff --git a/testdata/drc/drcSimpleTests_au16.gds b/testdata/drc/drcSimpleTests_au16.gds index c8350ab1b..7970f2426 100644 Binary files a/testdata/drc/drcSimpleTests_au16.gds and b/testdata/drc/drcSimpleTests_au16.gds differ