From 3cf8b29699a1e883fbec8ca102e3a635517e28fc Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 24 Mar 2024 21:57:39 +0100 Subject: [PATCH] RecursiveShapeIterator debugging --- src/db/db/dbRecursiveShapeIterator.cc | 97 ++++++++++++------- .../dbRecursiveShapeIteratorTests.cc | 72 ++++++++++++++ 2 files changed, 132 insertions(+), 37 deletions(-) diff --git a/src/db/db/dbRecursiveShapeIterator.cc b/src/db/db/dbRecursiveShapeIterator.cc index 0534ebd3f..33f6c0448 100644 --- a/src/db/db/dbRecursiveShapeIterator.cc +++ b/src/db/db/dbRecursiveShapeIterator.cc @@ -790,44 +790,11 @@ RecursiveShapeIterator::down (RecursiveShapeReceiver *receiver) const box_type new_region = box_type::world (); // compute the region inside the new cell - if (new_region != m_region) { - new_region = m_trans.inverted () * m_region; + if (new_region != m_local_region_stack.back ()) { + new_region = m_inst->complex_trans (*m_inst_array).inverted () * m_local_region_stack.back (); new_region &= cell_bbox (cell_index ()); } - // try some optimization - only consider optimizing by dropping the shape-covered area under certain circumstances: - // - single layer - // - less than 32 shapes to consider - // - total shape bbox in current region covers at least a third of it - // - total area of shapes in current region is at least a third of it - // TODO: the current implementation does not touch the complex search region - - if (m_for_merged_input && (! m_has_layers || m_layers.size () == 1) && ! new_region.empty ()) { - - unsigned int l = m_has_layers ? m_layers.front () : m_layer; - const shapes_type &shapes = m_cells.back ()->shapes (l); - box_type region_in_parent = m_inst->complex_trans (*m_inst_array) * new_region; - - // NOTE: new_region is already in the coordinate system of the child cell - - if (shapes.size () < 32 && - 3 * (shapes.bbox () & region_in_parent).area () > region_in_parent.area ()) { - - region_type shapes_region (shapes); - if (3 * shapes_region.area (region_in_parent) > region_in_parent.area ()) { - - shapes_region.transform (m_inst->complex_trans (*m_inst_array).inverted ()); - - // reduce the search region for less instances to look up - region_type new_complex_region = region_type (new_region) - shapes_region; - new_region = new_complex_region.bbox (); - - } - - } - - } - m_local_region_stack.push_back (new_region); if (! m_local_complex_region_stack.empty ()) { @@ -966,7 +933,59 @@ RecursiveShapeIterator::new_cell (RecursiveShapeReceiver *receiver) const new_layer (); - m_inst = cell ()->begin_touching (m_local_region_stack.back ()); + // try some optimization - only consider optimizing by dropping the shape-covered area under certain circumstances: + // - single layer + // - less than 32 shapes to consider + // - total shape bbox in current region covers at least a third of it + // - total area of shapes in current region is at least a third of it + // + // NOTE that this implementation can modify the search box on the box stack + // because we did "new_layer()" already and this function is not going to + // be called, because we do so only for single layers. + + const box_type ®ion = m_local_region_stack.back (); + + if (m_for_merged_input && (! m_has_layers || m_layers.size () == 1) && ! region.empty ()) { + + unsigned int l = m_has_layers ? m_layers.front () : m_layer; + const shapes_type &shapes = cell ()->shapes (l); + + if (! shapes.empty () && shapes.size () < 32 && + 3 * (shapes.bbox () & region).area () > region.area ()) { + + region_type shapes_region (shapes); + if (3 * shapes_region.area (region) > region.area ()) { + + // Need to enlarge the empty area somewhat so we really exclude instances + // entirely enclosed by the shape - also the ones at the border. + box_type::vector_type bias; + if (! m_overlapping) { + bias = box_type::vector_type (1, 1); + } + + // reduce the search region for less instances to look up + // NOTE: because we use "touching" for the instances below, we + region_type new_complex_region; + if (region == box_type::world ()) { + new_complex_region = region_type (cell ()->bbox ()) - shapes_region; + } else { + new_complex_region = region_type (cell ()->bbox () & region.enlarged (bias)) - shapes_region; + } + + // TODO: the current implementation does not touch the complex search region + m_local_region_stack.back () = new_complex_region.bbox ().enlarged (-bias); + + } + + } + + } + + if (m_overlapping) { + m_inst = cell ()->begin_touching (m_local_region_stack.back ().enlarged (box_type::vector_type (-1, -1))); + } else { + m_inst = cell ()->begin_touching (m_local_region_stack.back ()); + } m_inst_quad_id = 0; @@ -1015,7 +1034,11 @@ RecursiveShapeIterator::new_inst (RecursiveShapeReceiver *receiver) const // a singular iterator m_inst_array = db::CellInstArray::iterator (m_inst->cell_inst ().front (), false); } else if (with_region) { - m_inst_array = m_inst->cell_inst ().begin_touching (m_local_region_stack.back (), m_box_convert); + if (m_overlapping) { + m_inst_array = m_inst->cell_inst ().begin_touching (m_local_region_stack.back ().enlarged (box_type::vector_type (-1, -1)), m_box_convert); + } else { + m_inst_array = m_inst->cell_inst ().begin_touching (m_local_region_stack.back (), m_box_convert); + } } else { m_inst_array = m_inst->cell_inst ().begin (); } diff --git a/src/db/unit_tests/dbRecursiveShapeIteratorTests.cc b/src/db/unit_tests/dbRecursiveShapeIteratorTests.cc index c89af7605..c4fec7476 100644 --- a/src/db/unit_tests/dbRecursiveShapeIteratorTests.cc +++ b/src/db/unit_tests/dbRecursiveShapeIteratorTests.cc @@ -1554,3 +1554,75 @@ TEST(11_LayoutIsWeakPointer) x = collect(i1, *g); EXPECT_EQ (x, ""); } + +TEST(12_ForMerged) +{ + std::unique_ptr g (new db::Layout ()); + g->insert_layer (0); + g->insert_layer (1); + db::Cell &c0 (g->cell (g->add_cell ())); + db::Cell &c1 (g->cell (g->add_cell ())); + db::Cell &c2 (g->cell (g->add_cell ())); + db::Cell &c3 (g->cell (g->add_cell ())); + + db::Box b (0, 100, 1000, 1200); + c0.shapes (0).insert (db::Box (0, 0, 3000, 2000)); + c1.shapes (0).insert (b); + c2.shapes (0).insert (b); + c3.shapes (0).insert (b); + + db::Trans tt; + c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), tt)); + c0.insert (db::CellInstArray (db::CellInst (c2.cell_index ()), db::Trans (db::Vector (100, -100)))); + c0.insert (db::CellInstArray (db::CellInst (c3.cell_index ()), db::Trans (1))); + c2.insert (db::CellInstArray (db::CellInst (c3.cell_index ()), db::Trans (db::Vector (1100, 0)))); + + std::string x; + + db::RecursiveShapeIterator i1 (*g, c0, 0); + x = collect(i1, *g); + EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](1200,0;2200,1100)/[$4](-1200,0;-100,1000)"); + + i1.set_for_merged_input (true); + x = collect(i1, *g); + EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$4](-1200,0;-100,1000)"); + + std::vector lv; + lv.push_back (0); + i1 = db::RecursiveShapeIterator (*g, c0, lv); + x = collect(i1, *g); + EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](1200,0;2200,1100)/[$4](-1200,0;-100,1000)"); + + i1.set_for_merged_input (true); + x = collect(i1, *g); + EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$4](-1200,0;-100,1000)"); + + lv.push_back (1); // empty, but kills "for merged" optimization + i1 = db::RecursiveShapeIterator (*g, c0, lv); + x = collect(i1, *g); + EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](1200,0;2200,1100)/[$4](-1200,0;-100,1000)"); + + i1.set_for_merged_input (true); + x = collect(i1, *g); + // no longer optimized + EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](1200,0;2200,1100)/[$4](-1200,0;-100,1000)"); + + i1 = db::RecursiveShapeIterator (*g, c0, 0, db::Box (-100, 0, 100, 50)); + x = collect(i1, *g); + EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$3](100,0;1100,1100)/[$4](-1200,0;-100,1000)"); + + i1.set_for_merged_input (true); + x = collect(i1, *g); + EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$4](-1200,0;-100,1000)"); + + i1 = db::RecursiveShapeIterator (*g, c0, 0, db::Box (-101, 0, 100, 50)); + i1.set_overlapping (true); + x = collect(i1, *g); + EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$4](-1200,0;-100,1000)"); + + i1.set_for_merged_input (true); + x = collect(i1, *g); + EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$4](-1200,0;-100,1000)"); + + // ... +}