mirror of https://github.com/KLayout/klayout.git
Refined XOR optimization solution such that it is compatible with deep mode and 'wants_all_cells', added more tests
This commit is contained in:
parent
cb5a1f7d3e
commit
7080ed9a0c
|
|
@ -82,6 +82,7 @@ RecursiveShapeIterator &RecursiveShapeIterator::operator= (const RecursiveShapeI
|
|||
m_cells = d.m_cells;
|
||||
m_local_complex_region_stack = d.m_local_complex_region_stack;
|
||||
m_local_region_stack = d.m_local_region_stack;
|
||||
m_skip_shapes_stack = d.m_skip_shapes_stack;
|
||||
m_needs_reinit = d.m_needs_reinit;
|
||||
m_inst_quad_id = d.m_inst_quad_id;
|
||||
m_inst_quad_id_stack = d.m_inst_quad_id_stack;
|
||||
|
|
@ -462,6 +463,8 @@ RecursiveShapeIterator::validate (RecursiveShapeReceiver *receiver) const
|
|||
|
||||
m_local_region_stack.clear ();
|
||||
m_local_region_stack.push_back (m_global_trans.inverted () * m_region);
|
||||
m_skip_shapes_stack.clear ();
|
||||
m_skip_shapes_stack.push_back (false);
|
||||
|
||||
m_local_complex_region_stack.clear ();
|
||||
if (mp_complex_region.get ()) {
|
||||
|
|
@ -736,9 +739,23 @@ RecursiveShapeIterator::next_shape (RecursiveShapeReceiver *receiver) const
|
|||
|
||||
}
|
||||
|
||||
if (is_empty || !down (receiver)) {
|
||||
if (is_empty) {
|
||||
|
||||
// skip entire cell
|
||||
++m_inst;
|
||||
new_inst (receiver);
|
||||
|
||||
} else if (!down (receiver)) {
|
||||
|
||||
// skip this instance array member
|
||||
++m_inst_array;
|
||||
new_inst_member (receiver);
|
||||
|
||||
if (m_inst_array.at_end ()) {
|
||||
++m_inst;
|
||||
new_inst (receiver);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
|
@ -769,6 +786,39 @@ RecursiveShapeIterator::next_shape (RecursiveShapeReceiver *receiver) const
|
|||
bool
|
||||
RecursiveShapeIterator::down (RecursiveShapeReceiver *receiver) const
|
||||
{
|
||||
bool skip_shapes = false;
|
||||
|
||||
if (m_for_merged_input && ! m_skip_shapes_stack.back () && (! m_has_layers || m_layers.size () == 1)) {
|
||||
|
||||
// Try some optimization: if the instance we're looking at is entirely covered
|
||||
// by a rectangle (other objects are too expensive to check), then we skip it
|
||||
//
|
||||
// We check 10 shapes max.
|
||||
|
||||
box_type inst_bx;
|
||||
if (m_inst->size () == 1) {
|
||||
inst_bx = m_inst->bbox (m_box_convert);
|
||||
} else {
|
||||
inst_bx = m_inst->complex_trans (*m_inst_array) * m_box_convert (m_inst->cell_inst ().object ());
|
||||
}
|
||||
|
||||
unsigned int l = m_has_layers ? m_layers.front () : m_layer;
|
||||
auto si = cell ()->shapes (l).begin_overlapping (inst_bx, m_shape_flags, mp_shape_prop_sel, m_shape_inv_prop_sel);
|
||||
size_t nmax = 10;
|
||||
while (! si.at_end () && nmax-- > 0) {
|
||||
if (inst_bx.inside (si->rectangle ())) {
|
||||
skip_shapes = true;
|
||||
break;
|
||||
}
|
||||
++si;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (skip_shapes && (! receiver || ! receiver->wants_all_cells ())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
tl_assert (mp_layout);
|
||||
|
||||
m_trans_stack.push_back (m_trans);
|
||||
|
|
@ -796,6 +846,7 @@ RecursiveShapeIterator::down (RecursiveShapeReceiver *receiver) const
|
|||
}
|
||||
|
||||
m_local_region_stack.push_back (new_region);
|
||||
m_skip_shapes_stack.push_back (m_skip_shapes_stack.back () || skip_shapes);
|
||||
|
||||
if (! m_local_complex_region_stack.empty ()) {
|
||||
|
||||
|
|
@ -878,6 +929,7 @@ RecursiveShapeIterator::pop () const
|
|||
mp_cell = m_cells.back ();
|
||||
m_cells.pop_back ();
|
||||
m_local_region_stack.pop_back ();
|
||||
m_skip_shapes_stack.pop_back ();
|
||||
if (! m_local_complex_region_stack.empty ()) {
|
||||
m_local_complex_region_stack.pop_back ();
|
||||
}
|
||||
|
|
@ -902,7 +954,7 @@ RecursiveShapeIterator::start_shapes () const
|
|||
void
|
||||
RecursiveShapeIterator::new_layer () const
|
||||
{
|
||||
if (int (m_trans_stack.size ()) < m_min_depth || int (m_trans_stack.size ()) > m_max_depth) {
|
||||
if (m_skip_shapes_stack.back () || int (m_trans_stack.size ()) < m_min_depth || int (m_trans_stack.size ()) > m_max_depth) {
|
||||
m_shape = shape_iterator ();
|
||||
} else if (! m_overlapping) {
|
||||
m_shape = cell ()->shapes (m_layer).begin_touching (m_local_region_stack.back (), m_shape_flags, mp_shape_prop_sel, m_shape_inv_prop_sel);
|
||||
|
|
@ -942,7 +994,7 @@ RecursiveShapeIterator::new_cell (RecursiveShapeReceiver *receiver) const
|
|||
m_inst_quad_id = 0;
|
||||
|
||||
// skip instance quad if possible
|
||||
if (! m_local_complex_region_stack.empty ()) {
|
||||
if (! m_local_complex_region_stack.empty () && (! receiver || ! receiver->wants_all_cells ())) {
|
||||
skip_inst_iter_for_complex_region ();
|
||||
}
|
||||
|
||||
|
|
@ -958,40 +1010,13 @@ RecursiveShapeIterator::new_inst (RecursiveShapeReceiver *receiver) const
|
|||
while (! m_inst.at_end ()) {
|
||||
|
||||
// skip instance quad if possible
|
||||
if (! m_local_complex_region_stack.empty ()) {
|
||||
if (! m_local_complex_region_stack.empty () && (! receiver || ! receiver->wants_all_cells ())) {
|
||||
skip_inst_iter_for_complex_region ();
|
||||
if (m_inst.at_end ()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_for_merged_input && (! m_has_layers || m_layers.size () == 1)) {
|
||||
|
||||
// Try some optimization: if the instance we're looking at is entirely covered
|
||||
// by a rectangle (other objects are too expensive to check), then wil skip it
|
||||
//
|
||||
// We check 10 shapes max.
|
||||
|
||||
unsigned int l = m_has_layers ? m_layers.front () : m_layer;
|
||||
box_type inst_bx = m_inst->bbox (m_box_convert);
|
||||
auto si = cell ()->shapes (l).begin_overlapping (inst_bx, m_shape_flags, mp_shape_prop_sel, m_shape_inv_prop_sel);
|
||||
bool skip = false;
|
||||
size_t nmax = 10;
|
||||
while (! skip && ! si.at_end () && nmax-- > 0) {
|
||||
if (inst_bx.inside (si->rectangle ())) {
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
++si;
|
||||
}
|
||||
|
||||
if (skip) {
|
||||
++m_inst;
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool all_of_instance = false;
|
||||
bool with_region = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -867,6 +867,7 @@ private:
|
|||
mutable std::vector<const cell_type *> m_cells;
|
||||
mutable std::vector<box_tree_type> m_local_complex_region_stack;
|
||||
mutable std::vector<box_type> m_local_region_stack;
|
||||
mutable std::vector<bool> m_skip_shapes_stack;
|
||||
mutable bool m_needs_reinit;
|
||||
mutable size_t m_inst_quad_id;
|
||||
mutable std::vector<size_t> m_inst_quad_id_stack;
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include "tlUnitTest.h"
|
||||
#include "tlStream.h"
|
||||
#include "tlFileUtils.h"
|
||||
#include "dbHierProcessor.h"
|
||||
#include "dbTestSupport.h"
|
||||
#include "dbReader.h"
|
||||
|
|
@ -32,6 +33,9 @@
|
|||
#include "dbLocalOperationUtils.h"
|
||||
#include "dbRegionLocalOperations.h"
|
||||
#include "dbPolygon.h"
|
||||
#include "dbRecursiveInstanceIterator.h"
|
||||
#include "dbDeepShapeStore.h"
|
||||
#include "dbRegion.h"
|
||||
|
||||
static std::string testdata (const std::string &fn)
|
||||
{
|
||||
|
|
@ -1284,3 +1288,87 @@ TEST(Arrays)
|
|||
run_test_bool2 (_this, "hlp18.oas", TMNot, 100);
|
||||
}
|
||||
|
||||
TEST(XORTool)
|
||||
{
|
||||
test_is_long_runner ();
|
||||
|
||||
std::string fna (tl::combine_path (tl::testdata_private (), "xor/a.gds.gz"));
|
||||
std::string fnb (tl::combine_path (tl::testdata_private (), "xor/b.gds.gz"));
|
||||
std::string fn_au (tl::combine_path (tl::testdata_private (), "xor/xor_au.oas.gz"));
|
||||
|
||||
db::Layout lya, lyb;
|
||||
|
||||
unsigned int l1, l2;
|
||||
|
||||
db::LayerMap lmap;
|
||||
|
||||
lmap.map (db::LDPair (1, 0), l1 = lya.insert_layer ());
|
||||
lyb.insert_layer ();
|
||||
|
||||
lmap.map (db::LDPair (2, 0), l2 = lya.insert_layer ());
|
||||
lyb.insert_layer ();
|
||||
|
||||
{
|
||||
tl::InputStream stream (fna);
|
||||
db::Reader reader (stream);
|
||||
db::LoadLayoutOptions options;
|
||||
options.get_options<db::CommonReaderOptions> ().layer_map = lmap;
|
||||
options.get_options<db::CommonReaderOptions> ().create_other_layers = false;
|
||||
reader.read (lya, options);
|
||||
}
|
||||
|
||||
{
|
||||
tl::InputStream stream (fnb);
|
||||
db::Reader reader (stream);
|
||||
db::LoadLayoutOptions options;
|
||||
options.get_options<db::CommonReaderOptions> ().layer_map = lmap;
|
||||
options.get_options<db::CommonReaderOptions> ().create_other_layers = false;
|
||||
reader.read (lyb, options);
|
||||
}
|
||||
|
||||
db::Layout ly_out;
|
||||
db::cell_index_type top_out = ly_out.add_cell ("TOP");
|
||||
unsigned int l1_out = ly_out.insert_layer (db::LayerProperties (1, 0));
|
||||
unsigned int l2_out = ly_out.insert_layer (db::LayerProperties (2, 0));
|
||||
|
||||
db::DeepShapeStore dss;
|
||||
dss.set_wants_all_cells (true); // saves time for less cell mapping operations
|
||||
|
||||
{
|
||||
db::RecursiveShapeIterator ri_a, ri_b;
|
||||
|
||||
ri_a = db::RecursiveShapeIterator (lya, lya.cell (*lya.begin_top_down ()), l1);
|
||||
ri_a.set_for_merged_input (true);
|
||||
|
||||
ri_b = db::RecursiveShapeIterator (lyb, lyb.cell (*lyb.begin_top_down ()), l1);
|
||||
ri_b.set_for_merged_input (true);
|
||||
|
||||
db::Region in_a (ri_a, dss, db::ICplxTrans (1.0));
|
||||
db::Region in_b (ri_b, dss, db::ICplxTrans (1.0));
|
||||
|
||||
db::Region xor_res = in_a ^ in_b;
|
||||
EXPECT_EQ (xor_res.count (), size_t (12));
|
||||
|
||||
xor_res.insert_into (&ly_out, top_out, l1_out);
|
||||
}
|
||||
|
||||
{
|
||||
db::RecursiveShapeIterator ri_a, ri_b;
|
||||
|
||||
ri_a = db::RecursiveShapeIterator (lya, lya.cell (*lya.begin_top_down ()), l2);
|
||||
ri_a.set_for_merged_input (true);
|
||||
|
||||
ri_b = db::RecursiveShapeIterator (lyb, lyb.cell (*lyb.begin_top_down ()), l2);
|
||||
ri_b.set_for_merged_input (true);
|
||||
|
||||
db::Region in_a (ri_a, dss, db::ICplxTrans (1.0));
|
||||
db::Region in_b (ri_b, dss, db::ICplxTrans (1.0));
|
||||
|
||||
db::Region xor_res = in_a ^ in_b;
|
||||
EXPECT_EQ (xor_res.count (), size_t (15984));
|
||||
|
||||
xor_res.insert_into (&ly_out, top_out, l2_out);
|
||||
}
|
||||
|
||||
db::compare_layouts (_this, ly_out, fn_au, db::WriteOAS);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1683,7 +1683,7 @@ TEST(13_ForMergedPerformance)
|
|||
++n;
|
||||
}
|
||||
tl::info << "Counted " << n << " shapes on 66/20";
|
||||
EXPECT_EQ (n, size_t (1212844));
|
||||
EXPECT_EQ (n, size_t (1203078));
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -1735,7 +1735,7 @@ TEST(13_ForMergedPerformance)
|
|||
++n;
|
||||
}
|
||||
tl::info << "Counted " << n << " shapes on 66/20";
|
||||
EXPECT_EQ (n, size_t (218552));
|
||||
EXPECT_EQ (n, size_t (218069));
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -1757,7 +1757,7 @@ TEST(13_ForMergedPerformance)
|
|||
db::Region r2 (si1);
|
||||
|
||||
EXPECT_EQ (r1.count (), size_t (218823));
|
||||
EXPECT_EQ (r2.count (), size_t (218552));
|
||||
EXPECT_EQ (r2.count (), size_t (218069));
|
||||
EXPECT_EQ ((r1 ^ r2).count (), size_t (0));
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue