From c6bd8563311b0c3cebc5daa618d5df4fdf17acd7 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 24 Oct 2021 00:05:50 +0200 Subject: [PATCH] WIP --- src/db/db/dbHierProcessor.cc | 386 +++++++++++++++++++++++++++++++---- 1 file changed, 348 insertions(+), 38 deletions(-) diff --git a/src/db/db/dbHierProcessor.cc b/src/db/db/dbHierProcessor.cc index 33d9fbc7b..01d47e1ec 100644 --- a/src/db/db/dbHierProcessor.cc +++ b/src/db/db/dbHierProcessor.cc @@ -1015,9 +1015,141 @@ private: } }; +#if 1 +template +struct interaction_registration_inst2inst + : db::box_scanner_receiver2 +{ +public: + typedef typename local_processor_cell_contexts::context_key_type interactions_value_type; + typedef std::unordered_map, interactions_value_type> interactions_type; + + interaction_registration_inst2inst (const db::Layout *subject_layout, unsigned int subject_layer, const db::Layout *intruder_layout, unsigned int intruder_layer, bool foreign, db::Coord dist, interactions_type *result) + : mp_subject_layout (subject_layout), mp_intruder_layout (intruder_layout), m_subject_layer (subject_layer), m_intruder_layer (intruder_layer), m_dist (dist), mp_result (result), m_foreign (foreign) + { + // nothing yet .. + } + + void add (const db::CellInstArray *inst1, unsigned int id1, const db::CellInstArray *inst2, unsigned int id2) + { + // NOTE: self-interactions are possible for arrays: different elements of the + // array may interact which is a cell-external interaction. + if (mp_subject_layout != mp_intruder_layout || id1 != id2 || inst1->size () > 1) { + + bool ignore = false; + if (mp_subject_layout == mp_intruder_layout && m_subject_layer == m_intruder_layer && ! m_foreign) { + if (m_interactions.find (std::make_pair (id2, id1)) != m_interactions.end ()) { + // for self interactions ignore the reverse interactions + ignore = true; + } else { + m_interactions.insert (std::make_pair (id1, id2)); + } + } + + if (! ignore) { + collect_instance_interactions (inst1, inst2); + } + + } + } + +private: + const db::Layout *mp_subject_layout, *mp_intruder_layout; + unsigned int m_subject_layer, m_intruder_layer; + db::Coord m_dist; + interactions_type *mp_result; + std::unordered_set > m_interactions; + bool m_foreign; + + void + collect_instance_interactions (const db::CellInstArray *inst1, const db::CellInstArray *inst2) + { +printf("@@@ check instance interactions %s (#%d, %s) <-> %s (#%d, %s)\n", + mp_subject_layout->cell_name (inst1->object ().cell_index ()), int (inst1->size ()), (inst1->bbox(db::box_convert (*mp_subject_layout)).to_string()).c_str(), + mp_intruder_layout->cell_name (inst2->object ().cell_index ()), int (inst2->size ()), (inst2->bbox(db::box_convert (*mp_intruder_layout)).to_string()).c_str()); // @@@ + // TODO: this algorithm is not in particular effective for identical arrays + + const db::Cell &cell1 = mp_subject_layout->cell (inst1->object ().cell_index ()); + const db::Cell &cell2 = mp_intruder_layout->cell (inst2->object ().cell_index ()); + db::box_convert inst2_bc (*mp_intruder_layout, m_intruder_layer); + + std::unordered_map interactions_cache; + + for (db::CellInstArray::iterator n = inst1->begin (); ! n.at_end (); ++n) { + + db::ICplxTrans tn1 = inst1->complex_trans (*n); + db::ICplxTrans tni1 = tn1.inverted (); + db::Box ibox1 = tn1 * cell1.bbox (m_subject_layer).enlarged (db::Vector (m_dist, m_dist)); + + std::set *insts = 0; + + if (! ibox1.empty ()) { + + // TODO: in some cases, it may be possible to optimize this for arrays + + for (db::CellInstArray::iterator k = inst2->begin_touching (safe_box_enlarged (ibox1, -1, -1), inst2_bc); ! k.at_end (); ++k) { + + if (inst1 == inst2 && *n == *k) { + // skip self-interactions - this is handled inside the cell + continue; + } + + db::ICplxTrans tn2 = inst2->complex_trans (*k); + + // NOTE: we need to enlarge both subject *and* intruder boxes - either object comes close to intruder or the other way around + db::Box ibox2 = tn2 * cell2.bbox (m_intruder_layer).enlarged (db::Vector (m_dist, m_dist)); + + db::ICplxTrans tn21 = tni1 * tn2; + + db::Box cbox = ibox1 & ibox2; + if (! cbox.empty ()) { + + bool interacts = false; + + std::unordered_map::const_iterator ic = interactions_cache.find (tn21); + if (ic != interactions_cache.end ()) { + + interacts = ic->second; + + } else { + + db::ICplxTrans tni2 = tn2.inverted (); + + // not very strong, but already useful: the cells interact if there is a layer1 in cell1 + // in the common box and a layer2 in the cell2 in the common box + // NOTE: don't use overlap mode for the RecursiveShapeIterator as this would not capture dot-like + // objects like texts. Instead safe-shrink the search box and use touching mode ("false" for the last + // argument) + interacts = (! db::RecursiveShapeIterator (*mp_subject_layout, cell1, m_subject_layer, safe_box_enlarged (tni1 * cbox, -1, -1), false).at_end () && + ! db::RecursiveShapeIterator (*mp_intruder_layout, cell2, m_intruder_layer, safe_box_enlarged (tni2 * cbox, -1, -1), false).at_end ()); + interactions_cache.insert (std::make_pair (tn21, interacts)); + + } + + if (interacts) { + if (! insts) { + insts = & (*mp_result) [std::make_pair (cell1.cell_index (), tn1)].first; + } + insts->insert (db::CellInstArray (db::CellInst (cell2.cell_index ()), tn21)); + } + + } + + } + + } + + } + } +}; +#else + static bool instances_interact (const db::Layout *layout1, const db::CellInstArray *inst1, unsigned int layer1, const db::Layout *layout2, const db::CellInstArray *inst2, unsigned int layer2, db::Coord dist) { +printf("@@@ check instance interactions %s (#%d, %s) <-> %s (#%d, %s)\n", + layout1->cell_name (inst1->object ().cell_index ()), int (inst1->size ()), (inst1->bbox(db::box_convert (*layout1)).to_string()).c_str(), + layout2->cell_name (inst2->object ().cell_index ()), int (inst2->size ()), (inst2->bbox(db::box_convert (*layout2)).to_string()).c_str()); // @@@ // TODO: this algorithm is not in particular effective for identical arrays const db::Cell &cell1 = layout1->cell (inst1->object ().cell_index ()); @@ -1124,7 +1256,69 @@ private: std::unordered_set > m_interactions; bool m_foreign; }; +#endif +#if 1 +template +struct interaction_registration_inst2shape + : db::box_scanner_receiver2 +{ +public: + typedef typename local_processor_cell_contexts::context_key_type interactions_value_type; + typedef std::unordered_map, interactions_value_type> interactions_type; + + interaction_registration_inst2shape (db::Layout *subject_layout, unsigned int subject_layer, db::Coord dist, interactions_type *result) + : mp_subject_layout (subject_layout), m_subject_layer (subject_layer), m_dist (dist), mp_result (result) + { + // nothing yet .. + } + + void add (const db::CellInstArray *inst, unsigned int, const TI *ref, unsigned int layer) + { + collect_instance_shape_interactions (inst, layer, *ref, m_dist); + } + +private: + db::Layout *mp_subject_layout; + unsigned int m_subject_layer; + db::Coord m_dist; + interactions_type *mp_result; + + void + collect_instance_shape_interactions (const db::CellInstArray *inst, unsigned int layer, const TI &ref, db::Coord dist) + { + const db::Cell &cell = mp_subject_layout->cell (inst->object ().cell_index ()); + db::box_convert inst_bc (*mp_subject_layout, m_subject_layer); + db::Box rbox = db::box_convert () (ref); + + for (db::CellInstArray::iterator n = inst->begin_touching (safe_box_enlarged (rbox, dist - 1, dist - 1), inst_bc); ! n.at_end (); ++n) { + + db::ICplxTrans tn = inst->complex_trans (*n); + db::Box cbox = (tn * cell.bbox (m_subject_layer)).enlarged (db::Vector (dist, dist)) & rbox.enlarged (db::Vector (dist, dist)); + + if (! cbox.empty ()) { + + db::ICplxTrans tni = tn.inverted (); + db::shape_reference_translator_with_trans rt (mp_subject_layout, tni); + + std::set *shapes = 0; + + // not very strong, but already useful: the cells interact if there is a layer in cell + // in the common box + // NOTE: don't use overlapping mode here, because this will not select point-like objects as texts or + // dot edges. Instead safe-shrink the search box and use touching mode. + for (db::RecursiveShapeIterator s (*mp_subject_layout, cell, m_subject_layer, safe_box_enlarged (tni * cbox, -1, -1), false); !s.at_end (); ++s) { + if (! shapes) { + shapes = & (*mp_result) [std::make_pair (cell.cell_index (), tn)].second [layer]; + } + shapes->insert (rt (ref)); + } + } + + } + } +}; +#else template static bool instance_shape_interacts (const db::Layout *layout, const db::CellInstArray *inst, unsigned int layer, const T &ref, db::Coord dist) @@ -1181,7 +1375,7 @@ private: db::Coord m_dist; std::unordered_map, std::map > > > *mp_result; }; - +#endif } // --------------------------------------------------------------------------------------------- @@ -1504,9 +1698,119 @@ void local_processor::compute_contexts (local_processor_contextsbegin ().at_end ()) { - typedef std::pair, std::map > > interaction_value_type; +#if 1 + // Key: single instance given by cell index and transformation + // Value the contexts for the child cell for this instance + typedef typename local_processor_cell_contexts::context_key_type interactions_value_type; + typedef std::unordered_map, interactions_value_type> interactions_type; + interactions_type interactions; - std::unordered_map interactions; + // insert dummy interactions to handle at least the child cell vs. itself + // - this is important so we will always handle the instances unless they are + // entirely empty in the subject layer + for (db::Cell::const_iterator i = subject_cell->begin (); !i.at_end (); ++i) { + if (! inst_bcs (i->cell_inst ()).empty ()) { + db::cell_index_type ci = i->cell_inst ().object ().cell_index (); + for (db::CellInstArray::iterator n = i->begin (); ! n.at_end (); ++n) { + db::ICplxTrans tn = i->complex_trans (*n); + interactions.insert (std::make_pair (std::make_pair (ci, tn), interactions_value_type ())); + } + } + } + + // TODO: can we shortcut this if interactions is empty? + for (std::vector::const_iterator il = contexts.intruder_layers ().begin (); il != contexts.intruder_layers ().end (); ++il) { + + db::box_convert inst_bci (*mp_intruder_layout, contexts.actual_intruder_layer (*il)); + + db::box_scanner2 scanner; + interaction_registration_inst2inst rec (mp_subject_layout, contexts.subject_layer (), mp_intruder_layout, contexts.actual_intruder_layer (*il), contexts.is_foreign (*il), dist, &interactions); + + unsigned int id = 0; + + if (subject_cell == intruder_cell) { + + // Use the same id's for same instances - this way we can easily detect same instances + // and don't make them self-interacting + + for (db::Cell::const_iterator i = subject_cell->begin (); !i.at_end (); ++i) { + unsigned int iid = ++id; + if (! inst_bcs (i->cell_inst ()).empty () && ! subject_cell_is_breakout (i->cell_index ())) { + scanner.insert1 (&i->cell_inst (), iid); + } + if (! inst_bci (i->cell_inst ()).empty () && ! intruder_cell_is_breakout (i->cell_index ())) { + scanner.insert2 (&i->cell_inst (), iid); + } + } + + } else { + + for (db::Cell::const_iterator i = subject_cell->begin (); !i.at_end (); ++i) { + if (! inst_bcs (i->cell_inst ()).empty () && ! subject_cell_is_breakout (i->cell_index ())) { + scanner.insert1 (&i->cell_inst (), ++id); + } + } + + if (intruder_cell) { + for (db::Cell::const_iterator i = intruder_cell->begin (); !i.at_end (); ++i) { + if (! inst_bci (i->cell_inst ()).empty () && ! intruder_cell_is_breakout (i->cell_index ())) { + scanner.insert2 (&i->cell_inst (), ++id); + } + } + } + + } + + std::list instance_heap; + + for (std::set::const_iterator i = intruders.first.begin (); i != intruders.first.end (); ++i) { + if (! inst_bci (*i).empty ()) { + scanner.insert2 (i.operator-> (), ++id); + } + } + + scanner.process (rec, dist, inst_bcs, inst_bci); + + } + +// TODO: can we shortcut this if interactions is empty? + { + db::box_scanner2 scanner; + interaction_registration_inst2shape rec (mp_subject_layout, contexts.subject_layer (), dist, &interactions); + + for (db::Cell::const_iterator i = subject_cell->begin (); !i.at_end (); ++i) { + if (! inst_bcs (i->cell_inst ()).empty () && ! subject_cell_is_breakout (i->cell_index ())) { + scanner.insert1 (&i->cell_inst (), 0); + } + } + + for (typename std::map >::const_iterator il = intruders.second.begin (); il != intruders.second.end (); ++il) { + for (typename std::set::const_iterator i = il->second.begin (); i != il->second.end (); ++i) { + scanner.insert2 (i.operator-> (), il->first); + } + } + + for (std::map::const_iterator im = intruder_shapes.begin (); im != intruder_shapes.end (); ++im) { + for (db::Shapes::shape_iterator i = im->second->begin (shape_flags ()); !i.at_end (); ++i) { + scanner.insert2 (i->basic_ptr (typename TI::tag ()), im->first); + } + } + + scanner.process (rec, dist, inst_bcs, db::box_convert ()); + } + + // produce the tasks for computing the next-level interactions + for (typename interactions_type::iterator i = interactions.begin (); i != interactions.end (); ++i) { + + db::Cell *subject_child_cell = &mp_subject_layout->cell (i->first.first); + db::Cell *intruder_child_cell = (subject_cell == intruder_cell ? subject_child_cell : 0); + + issue_compute_contexts (contexts, cell_context, subject_cell, subject_child_cell, i->first.second, intruder_child_cell, i->second, dist); + + } + +#else + typedef std::pair, std::map > > interaction_value_type; // insert dummy interactions to handle at least the child cell vs. itself // - this is important so we will always handle the instances unless they are @@ -1560,6 +1864,8 @@ void local_processor::compute_contexts (local_processor_contexts instance_heap; + for (std::set::const_iterator i = intruders.first.begin (); i != intruders.first.end (); ++i) { if (! inst_bci (*i).empty ()) { scanner.insert2 (i.operator-> (), ++id); @@ -1601,57 +1907,61 @@ void local_processor::compute_contexts (local_processor_contexts > effective_instance_cache_type; effective_instance_cache_type effective_instance_cache; +size_t n = 0, nmax = interactions.size(); // @@@ for (typename std::unordered_map::const_iterator i = interactions.begin (); i != interactions.end (); ++i) { +printf("@@@ %d/%d -> #%d,#%d\n", int(n++), int(nmax), int (i->second.first.size()), int(i->second.second.size())); fflush(stdout); - db::Cell &subject_child_cell = mp_subject_layout->cell (i->first->object ().cell_index ()); + db::Cell *subject_child_cell = &mp_subject_layout->cell (i->first->object ().cell_index ()); + db::Box sc_bbox = subject_child_cell->bbox (contexts.subject_layer ()).enlarged (db::Vector (dist, dist)); + if (sc_bbox.empty ()) { + continue; + } + + db::Cell *intruder_child_cell = (subject_cell == intruder_cell ? subject_child_cell : 0); for (db::CellInstArray::iterator n = i->first->begin (); ! n.at_end (); ++n) { db::ICplxTrans tn = i->first->complex_trans (*n); db::ICplxTrans tni = tn.inverted (); - db::Box nbox = tn * subject_child_cell.bbox (contexts.subject_layer ()).enlarged (db::Vector (dist, dist)); + db::Box nbox = tn * sc_bbox; - if (! nbox.empty ()) { + typename local_processor_cell_contexts::context_key_type intruders_below; - typename local_processor_cell_contexts::context_key_type intruders_below; + db::shape_reference_translator_with_trans rt (mp_subject_layout, tni); - db::shape_reference_translator_with_trans rt (mp_subject_layout, tni); - - for (typename std::map >::const_iterator pl = i->second.second.begin (); pl != i->second.second.end (); ++pl) { - std::set &out = intruders_below.second [pl->first]; - for (typename std::unordered_set::const_iterator p = pl->second.begin (); p != pl->second.end (); ++p) { - if (nbox.overlaps (db::box_convert () (*p))) { - out.insert (rt (*p)); - } + for (typename std::map >::const_iterator pl = i->second.second.begin (); pl != i->second.second.end (); ++pl) { + std::set &out = intruders_below.second [pl->first]; + for (typename std::unordered_set::const_iterator p = pl->second.begin (); p != pl->second.end (); ++p) { + if (nbox.overlaps (db::box_convert () (*p))) { + out.insert (rt (*p)); } } + } - // TODO: in some cases, it may be possible to optimize this for arrays + // TODO: in some cases, it may be possible to optimize this for arrays - for (std::vector::const_iterator il = contexts.intruder_layers ().begin (); il != contexts.intruder_layers ().end (); ++il) { + for (std::vector::const_iterator il = contexts.intruder_layers ().begin (); il != contexts.intruder_layers ().end (); ++il) { - unsigned int ail = contexts.actual_intruder_layer (*il); - db::box_convert inst_bcii (*mp_intruder_layout, ail); + unsigned int ail = contexts.actual_intruder_layer (*il); + db::box_convert inst_bcii (*mp_intruder_layout, ail); - for (std::unordered_set::const_iterator j = i->second.first.begin (); j != i->second.first.end (); ++j) { + 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) { + 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 - 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); - } + 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 + 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); } } @@ -1660,14 +1970,14 @@ void local_processor::compute_contexts (local_processor_contexts