diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index 1210f81b1..390301734 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -346,7 +346,7 @@ DeepRegion::and_or_not_with (const DeepRegion *other, bool and_op) const { DeepLayer dl_out (m_deep_layer.derived ()); - db::BoolAndOrNotLocalOperation op (and_op); + db::BoolAndOrNotLocalOperation op (and_op, m_deep_layer.store ()->max_area_ratio (), m_deep_layer.store ()->max_vertex_count ()); db::LocalProcessor proc (const_cast (m_deep_layer.layout ()), const_cast (m_deep_layer.initial_cell ()), other->deep_layer ().layout (), other->deep_layer ().initial_cell ()); proc.set_threads (m_deep_layer.store ()->threads ()); diff --git a/src/db/db/dbDeepShapeStore.cc b/src/db/db/dbDeepShapeStore.cc index 41f3909b9..2ff81f9e0 100644 --- a/src/db/db/dbDeepShapeStore.cc +++ b/src/db/db/dbDeepShapeStore.cc @@ -177,7 +177,7 @@ struct DeepShapeStore::LayoutHolder static size_t s_instance_count = 0; DeepShapeStore::DeepShapeStore () - : m_threads (1) + : m_threads (1), m_max_area_ratio (3.0), m_max_vertex_count (16) { ++s_instance_count; } @@ -219,6 +219,16 @@ void DeepShapeStore::set_threads (int n) m_threads = n; } +void DeepShapeStore::set_max_area_ratio (double ar) +{ + m_max_area_ratio = ar; +} + +void DeepShapeStore::set_max_vertex_count (size_t n) +{ + m_max_vertex_count = n; +} + void DeepShapeStore::add_ref (unsigned int layout, unsigned int layer) { tl::MutexLocker locker (&m_lock); @@ -245,6 +255,13 @@ void DeepShapeStore::remove_ref (unsigned int layout, unsigned int layer) DeepLayer DeepShapeStore::create_polygon_layer (const db::RecursiveShapeIterator &si, double max_area_ratio, size_t max_vertex_count) { + if (max_area_ratio == 0.0) { + max_area_ratio = m_max_area_ratio; + } + if (max_vertex_count == 0) { + max_vertex_count = m_max_vertex_count; + } + unsigned int layout_index = 0; layout_map_type::iterator l = m_layout_map.find (si); diff --git a/src/db/db/dbDeepShapeStore.h b/src/db/db/dbDeepShapeStore.h index c4ee8cd0c..31b18f472 100644 --- a/src/db/db/dbDeepShapeStore.h +++ b/src/db/db/dbDeepShapeStore.h @@ -195,7 +195,7 @@ public: * into parts satisfying the area ratio (bounding box vs. polygon area) * and maximum vertex count constraints. */ - DeepLayer create_polygon_layer (const db::RecursiveShapeIterator &si, double max_area_ratio = 3.0, size_t max_vertex_count = 16); + DeepLayer create_polygon_layer (const db::RecursiveShapeIterator &si, double max_area_ratio = 0.0, size_t max_vertex_count = 0); /** * @brief Inserts the deep layer's shapes into some target layout @@ -240,6 +240,40 @@ public: return m_threads; } + /** + * @brief Sets the maximum vertex count default value + * + * This parameter is used to simplify complex polygons. It is used by + * create_polygon_layer with the default parameters. It's also used by + * boolean operations when they deliver their output. + */ + void set_max_vertex_count (size_t n); + + /** + * @brief Gets the maximum vertex count + */ + size_t max_vertex_count () const + { + return m_max_vertex_count; + } + + /** + * @brief Sets the max. area ratio for bounding box vs. polygon area + * + * This parameter is used to simplify complex polygons. It is used by + * create_polygon_layer with the default parameters. It's also used by + * boolean operations when they deliver their output. + */ + void set_max_area_ratio (double ar); + + /** + * @brief Gets the max. area ratio + */ + double max_area_ratio () const + { + return m_max_area_ratio; + } + private: friend class DeepLayer; @@ -259,6 +293,8 @@ private: std::vector m_layouts; layout_map_type m_layout_map; int m_threads; + double m_max_area_ratio; + size_t m_max_vertex_count; tl::Mutex m_lock; struct DeliveryMappingCacheKey diff --git a/src/db/db/dbHierProcessor.cc b/src/db/db/dbHierProcessor.cc index d390a4ab4..6f105a063 100644 --- a/src/db/db/dbHierProcessor.cc +++ b/src/db/db/dbHierProcessor.cc @@ -101,14 +101,14 @@ public: template Ref operator() (const Ref &ref, const Trans &tr) const { - shape_type sh = ref.obj ().transformed (Trans (ref_trans_type (tr).inverted ()) * tr); + shape_type sh = ref.obj ().transformed (tr * Trans (ref.trans ())); ref_trans_type red_trans; sh.reduce (red_trans); - typename std::unordered_map >::const_iterator m = m_cache_by_shape.find (sh); + typename std::unordered_map::const_iterator m = m_cache_by_shape.find (sh); if (m != m_cache_by_shape.end ()) { - return Ref (m->second.first, ref_trans_type (tr * Trans (ref.trans ())) * m->second.second); + return Ref (m->second, red_trans); } else { @@ -118,8 +118,8 @@ public: ptr = mp_layout->shape_repository ().repository (typename shape_type::tag ()).insert (sh); } - m_cache_by_shape[sh] = std::make_pair (ptr, red_trans); - return Ref (ptr, ref_trans_type (tr * Trans (ref.trans ())) * red_trans); + m_cache_by_shape[sh] = ptr; + return Ref (ptr, red_trans); } } @@ -127,7 +127,7 @@ public: private: db::Layout *mp_layout; mutable std::unordered_map m_cache; - mutable std::unordered_map > m_cache_by_shape; + mutable std::unordered_map m_cache_by_shape; }; template @@ -494,9 +494,9 @@ private: unsigned int m_intruder_layer; db::Coord m_dist; ShapeInteractions *mp_result; - std::unordered_map, unsigned int> m_inst_shape_ids; + std::unordered_map m_inst_shape_ids; - void add_shapes_from_intruder_inst (unsigned int id1, const db::Cell &intruder_cell, const db::ICplxTrans &tn, unsigned int inst_id, const db::Box ®ion) + void add_shapes_from_intruder_inst (unsigned int id1, const db::Cell &intruder_cell, const db::ICplxTrans &tn, unsigned int /*inst_id*/, const db::Box ®ion) { db::shape_reference_translator rt (mp_subject_layout); @@ -507,18 +507,17 @@ private: si.shape_flags (polygon_ref_flags ()); while (! si.at_end ()) { - const db::PolygonRef *ref2 = si.shape ().basic_ptr (db::PolygonRef::tag ()); + // NOTE: we intentionally rewrite to the *subject* layout - this way polygon refs in the context come from the + // subject, not from the intruder. + db::PolygonRef ref2 = rt (*si.shape ().basic_ptr (db::PolygonRef::tag ()), tn * si.trans ()); // reuse the same id for shapes from the same instance -> this avoid duplicates with different IDs on // the intruder side. - std::unordered_map, unsigned int>::const_iterator k = m_inst_shape_ids.find (std::make_pair (inst_id, ref2)); + std::unordered_map::const_iterator k = m_inst_shape_ids.find (ref2); if (k == m_inst_shape_ids.end ()) { - k = m_inst_shape_ids.insert (std::make_pair (std::make_pair (inst_id, ref2), mp_result->next_id ())).first; - - // NOTE: we intentionally rewrite to the *subject* layout - this way polygon refs in the context come from the - // subject, not from the intruder. - mp_result->add_shape (k->second, rt (*ref2, tn * si.trans ())); + k = m_inst_shape_ids.insert (std::make_pair (ref2, mp_result->next_id ())).first; + mp_result->add_shape (k->second, ref2); } @@ -887,6 +886,7 @@ void LocalProcessor::compute_contexts (LocalProcessorContexts &contexts, } } +// @@@ can we shortcut this if interactions is empty? { db::box_scanner2 scanner; InteractionRegistrationInst2Inst rec (mp_subject_layout, contexts.subject_layer (), mp_intruder_layout, contexts.intruder_layer (), dist, &interactions); @@ -935,6 +935,7 @@ void LocalProcessor::compute_contexts (LocalProcessorContexts &contexts, scanner.process (rec, dist, inst_bcs, inst_bci); } +// @@@ can we shortcut this if interactions is empty? { db::box_scanner2 scanner; InteractionRegistrationInst2Shape rec (mp_subject_layout, contexts.subject_layer (), dist, &interactions); @@ -1136,6 +1137,7 @@ LocalProcessor::compute_local_cell (const LocalProcessorContexts &contexts, db:: scanner.insert (ref, id++); } +// @@@ TODO: can we confine this search to the subject's (sized) bounding box? for (std::unordered_set::const_iterator i = intruders.second.begin (); i != intruders.second.end (); ++i) { scanner.insert (i.operator-> (), interactions.next_id ()); } @@ -1153,11 +1155,13 @@ LocalProcessor::compute_local_cell (const LocalProcessorContexts &contexts, db:: scanner.insert1 (ref, id++); } +// @@@ TODO: can we confine this search to the subject's (sized) bounding box? for (std::unordered_set::const_iterator i = intruders.second.begin (); i != intruders.second.end (); ++i) { scanner.insert2 (i.operator-> (), interactions.next_id ()); } if (intruder_shapes) { +// @@@ TODO: can we confine this search to the subject's (sized) bounding box? for (db::Shapes::shape_iterator i = intruder_shapes->begin (polygon_ref_flags ()); !i.at_end (); ++i) { scanner.insert2 (i->basic_ptr (db::PolygonRef::tag ()), interactions.next_id ()); } @@ -1188,6 +1192,7 @@ LocalProcessor::compute_local_cell (const LocalProcessorContexts &contexts, db:: // interactions low in the hierarchy. } else if (intruder_cell) { +// @@@ TODO: can we confine this search to the subject's (sized) bounding box? for (db::Cell::const_iterator i = intruder_cell->begin (); !i.at_end (); ++i) { if (! inst_bci (i->cell_inst ()).empty ()) { scanner.insert2 (&i->cell_inst (), ++inst_id); @@ -1195,6 +1200,7 @@ LocalProcessor::compute_local_cell (const LocalProcessorContexts &contexts, db:: } } +// @@@ TODO: can we confine this search to the subject's (sized) bounding box? for (std::unordered_set::const_iterator i = intruders.first.begin (); i != intruders.first.end (); ++i) { if (! inst_bci (*i).empty ()) { scanner.insert2 (i.operator-> (), ++inst_id); diff --git a/src/db/db/dbHierarchyBuilder.cc b/src/db/db/dbHierarchyBuilder.cc index c07523fb4..2f8b999e0 100644 --- a/src/db/db/dbHierarchyBuilder.cc +++ b/src/db/db/dbHierarchyBuilder.cc @@ -474,20 +474,10 @@ ReducingHierarchyBuilderShapeReceiver::push (const db::Polygon &shape, const db: reduce (shape, region, complex_region, target); } -static double area_ratio (const db::Polygon &poly) -{ - return double (poly.box ().area ()) / double (poly.area ()); -} - void ReducingHierarchyBuilderShapeReceiver::reduce (const db::Polygon &poly, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) { - size_t npoints = 0; - for (unsigned int c = 0; c < poly.holes () + 1; ++c) { - npoints += poly.contour (c).size (); - } - - if (npoints > m_max_vertex_count || area_ratio (poly) > m_area_ratio) { + if (poly.vertices () > m_max_vertex_count || poly.area_ratio () > m_area_ratio) { std::vector split_polygons; db::split_polygon (poly, split_polygons); diff --git a/src/db/db/dbLocalOperation.cc b/src/db/db/dbLocalOperation.cc index a9e5300f8..95efbb377 100644 --- a/src/db/db/dbLocalOperation.cc +++ b/src/db/db/dbLocalOperation.cc @@ -27,6 +27,7 @@ #include "dbBoxConvert.h" #include "dbEdgeProcessor.h" #include "dbPolygonGenerators.h" +#include "dbPolygonTools.h" #include "tlLog.h" #include "tlTimer.h" #include "tlInternational.h" @@ -65,12 +66,46 @@ private: std::unordered_set *mp_polyrefs; }; +class PolygonSplitter + : public PolygonSink +{ +public: + PolygonSplitter (PolygonSink &sink, double max_area_ratio, size_t max_vertex_count) + : mp_sink (&sink), m_max_area_ratio (max_area_ratio), m_max_vertex_count (max_vertex_count) + { + // .. nothing yet .. + } + + virtual void put (const db::Polygon &poly) + { + if ((m_max_vertex_count > 0 && poly.vertices () > m_max_vertex_count) || (m_max_area_ratio > 0.0 && poly.area_ratio () > m_max_area_ratio)) { + + std::vector split_polygons; + db::split_polygon (poly, split_polygons); + for (std::vector ::const_iterator sp = split_polygons.begin (); sp != split_polygons.end (); ++sp) { + put (*sp); + } + + } else { + mp_sink->put (poly); + } + } + + virtual void start () { mp_sink->start (); } + virtual void flush () { mp_sink->flush (); } + +private: + PolygonSink *mp_sink; + double m_max_area_ratio; + size_t m_max_vertex_count; +}; + } // --------------------------------------------------------------------------------------------- -BoolAndOrNotLocalOperation::BoolAndOrNotLocalOperation (bool is_and) - : m_is_and (is_and) +BoolAndOrNotLocalOperation::BoolAndOrNotLocalOperation (bool is_and, double max_area_ratio, size_t max_vertex_count) + : m_is_and (is_and), m_max_area_ratio (max_area_ratio), m_max_vertex_count (max_vertex_count) { // .. nothing yet .. } @@ -133,7 +168,8 @@ BoolAndOrNotLocalOperation::compute_local (db::Layout *layout, const ShapeIntera db::BooleanOp op (m_is_and ? db::BooleanOp::And : db::BooleanOp::ANotB); db::PolygonRefGenerator pr (layout, result); - db::PolygonGenerator pg (pr, true, true); + db::PolygonSplitter splitter (pr, m_max_area_ratio, m_max_vertex_count); + db::PolygonGenerator pg (splitter, true, true); ep.process (pg, op); } diff --git a/src/db/db/dbLocalOperation.h b/src/db/db/dbLocalOperation.h index 8fe9ae0be..c80086fdc 100644 --- a/src/db/db/dbLocalOperation.h +++ b/src/db/db/dbLocalOperation.h @@ -114,7 +114,7 @@ class DB_PUBLIC BoolAndOrNotLocalOperation : public LocalOperation { public: - BoolAndOrNotLocalOperation (bool is_and); + BoolAndOrNotLocalOperation (bool is_and, double max_area_ratio = 0.0, size_t max_vertex_count = 0); virtual void compute_local (db::Layout *layout, const ShapeInteractions &interactions, std::unordered_set &result) const; virtual on_empty_intruder_mode on_empty_intruder_hint () const; @@ -122,6 +122,8 @@ public: private: bool m_is_and; + double m_max_area_ratio; + size_t m_max_vertex_count; }; /** diff --git a/src/db/db/dbPolygon.h b/src/db/db/dbPolygon.h index 09a09832e..94941f6e7 100644 --- a/src/db/db/dbPolygon.h +++ b/src/db/db/dbPolygon.h @@ -1662,7 +1662,7 @@ public: } /** - * @brief Return the number of points in the polygon + * @brief Returns the number of points in the polygon */ size_t vertices () const { @@ -1673,6 +1673,18 @@ public: return n; } + /** + * @brief Returns the area ratio between the polygon's bounding box and actual area + * + * This number is a measure how well the polygon is approximated by the bounding box. + * Values are bigger than 1 for well-formed polygons. Bigger values mean worse + * approximation. + */ + double area_ratio () const + { + return double (box ().area ()) / double (area ()); + } + /** * @brief The hull "begin" point iterator * @@ -2956,6 +2968,18 @@ public: return m_hull.size (); } + /** + * @brief Returns the area ratio between the polygon's bounding box and actual area + * + * This number is a measure how well the polygon is approximated by the bounding box. + * Values are bigger than 1 for well-formed polygons. Bigger values mean worse + * approximation. + */ + double area_ratio () const + { + return double (box ().area ()) / double (area ()); + } + void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self = false, void *parent = 0) const { db::mem_stat (stat, purpose, cat, m_hull, no_self, parent); diff --git a/src/db/unit_tests/dbDeepRegionTests.cc b/src/db/unit_tests/dbDeepRegionTests.cc index 41b148e58..863566678 100644 --- a/src/db/unit_tests/dbDeepRegionTests.cc +++ b/src/db/unit_tests/dbDeepRegionTests.cc @@ -288,3 +288,54 @@ TEST(5_BoolXOR) db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au5.gds"); } +TEST(6_Reduction) +{ + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/deep_region_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; + dss.set_max_vertex_count (4); + dss.set_threads (0); + + unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0)); + unsigned int l3 = ly.get_layer (db::LayerProperties (3, 0)); + unsigned int l42 = ly.get_layer (db::LayerProperties (42, 0)); + unsigned int lbox = ly.insert_layer (); + + db::Region r2 (db::RecursiveShapeIterator (ly, top_cell, l2), dss); + db::Region r3 (db::RecursiveShapeIterator (ly, top_cell, l3), dss); + db::Region r42 (db::RecursiveShapeIterator (ly, top_cell, l42), dss); + + top_cell.shapes (lbox).insert (db::Box (2000, -1000, 6000, 4000)); + db::Region box (db::RecursiveShapeIterator (ly, top_cell, lbox), dss); + + db::Region r2xor3 = r2 ^ r3; + db::Region r2xorbox = r2 ^ box; + db::Region r2xor42 = r2 ^ r42; + db::Region rboxxor3 = box ^ r3; + db::Region r42xor3 = r42 ^ r3; + db::Region r42xor42 = r42 ^ r42; + + 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)), r2xor3); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r2xorbox); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), r2xor42); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), rboxxor3); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (14, 0)), r42xor3); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (15, 0)), r42xor42); + + CHECKPOINT(); + db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au6.gds"); +} + diff --git a/src/db/unit_tests/dbHierProcessorTests.cc b/src/db/unit_tests/dbHierProcessorTests.cc index 3453aacd9..53870f177 100644 --- a/src/db/unit_tests/dbHierProcessorTests.cc +++ b/src/db/unit_tests/dbHierProcessorTests.cc @@ -1061,3 +1061,12 @@ TEST(BasicSelfOverlapWithSize10) run_test_bool_with_size (_this, "hlp10.oas", TMSelfOverlap, 150, 111); } +TEST(TopWithBelow1) +{ + run_test_bool (_this, "hlp12.oas", TMNot, 100); +} + +TEST(TopWithBelow2) +{ + run_test_bool (_this, "hlp12.oas", TMNotSwapped, 101); +} diff --git a/src/gsi/unit_tests/gsiExpression.cc b/src/gsi/unit_tests/gsiExpression.cc index 960c30c1a..500ee0da4 100644 --- a/src/gsi/unit_tests/gsiExpression.cc +++ b/src/gsi/unit_tests/gsiExpression.cc @@ -235,7 +235,7 @@ TEST(2) v = e.parse ("var b=B.new; b.bx(-1)").execute (); EXPECT_EQ (v.to_string (), std::string ("xz")); /* - @@@ No detailed type analysis for ambiguity resolution so far: + TODO: No detailed type analysis for ambiguity resolution so far: v = e.parse ("var b=B.new; b.bx('hello', 1)").execute (); EXPECT_EQ (v.to_string (), std::string ("20.5")); */ @@ -297,10 +297,8 @@ TEST(2) v = e.parse ("b.amember_ref.a5(177)").execute (); EXPECT_EQ (v.to_string (), std::string ("nil")); - // @@@ v = e.parse ("b.amember_or_nil(true)").execute (); EXPECT_EQ (v.to_string (), std::string ("A: 177")); - // @@@ bool error = false; try { diff --git a/testdata/algo/deep_region_au6.gds b/testdata/algo/deep_region_au6.gds new file mode 100644 index 000000000..6609f6f40 Binary files /dev/null and b/testdata/algo/deep_region_au6.gds differ diff --git a/testdata/algo/hlp12.oas b/testdata/algo/hlp12.oas new file mode 100644 index 000000000..259bf940c Binary files /dev/null and b/testdata/algo/hlp12.oas differ