From dd81fda27d46de620d6019b28ae3eda1681c3eb0 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 18 Nov 2023 21:42:24 +0100 Subject: [PATCH] Refactoring with the goal to reduce the overhead for variant computation --- src/db/db/dbCellVariants.cc | 117 ++++++++++ src/db/db/dbCellVariants.h | 79 +++++++ src/db/db/dbDeepEdges.cc | 8 +- src/db/db/dbDeepRegion.cc | 16 +- src/db/unit_tests/dbCellVariantsTests.cc | 263 +++++++++++++++++++++++ 5 files changed, 471 insertions(+), 12 deletions(-) diff --git a/src/db/db/dbCellVariants.cc b/src/db/db/dbCellVariants.cc index b842b2585..ce555dd1a 100644 --- a/src/db/db/dbCellVariants.cc +++ b/src/db/db/dbCellVariants.cc @@ -706,5 +706,122 @@ VariantsCollectorBase::create_var_instances_tl_invariant (db::Cell &in_cell, std } } +// ------------------------------------------------------------------------------------------ + +VariantStatistics::VariantStatistics () + : mp_red () +{ + // .. nothing yet .. +} + +VariantStatistics::VariantStatistics (const TransformationReducer *red) + : mp_red (red) +{ + // .. nothing yet .. +} + +void +VariantStatistics::collect (const db::Layout &layout, const db::Cell &top_cell) +{ + tl_assert (mp_red != 0); + + // The top cell gets a "variant" with unit transformation + m_variants [top_cell.cell_index ()].insert (std::make_pair (db::ICplxTrans (), 1)); + + std::set called; + top_cell.collect_called_cells (called); + + for (db::Layout::top_down_const_iterator c = layout.begin_top_down (); c != layout.end_top_down (); ++c) { + + if (called.find (*c) == called.end ()) { + continue; + } + + // collect the parent variants per parent cell + + std::map > variants_per_parent_cell; + for (db::Cell::parent_inst_iterator pi = layout.cell (*c).begin_parent_insts (); ! pi.at_end (); ++pi) { + std::map &variants = variants_per_parent_cell [pi->inst ().object ().cell_index ()]; + add_variant (variants, pi->child_inst ().cell_inst (), mp_red->is_translation_invariant ()); + } + + // compute the resulting variants + + std::map &new_variants = m_variants [*c]; + + for (std::map >::const_iterator pv = variants_per_parent_cell.begin (); pv != variants_per_parent_cell.end (); ++pv) { + product (variants (pv->first), pv->second, new_variants); + } + + } +} + +const std::map & +VariantStatistics::variants (db::cell_index_type ci) const +{ + std::map >::const_iterator v = m_variants.find (ci); + static std::map empty_set; + if (v == m_variants.end ()) { + return empty_set; + } else { + return v->second; + } +} + +bool +VariantStatistics::has_variants () const +{ + for (std::map >::const_iterator i = m_variants.begin (); i != m_variants.end (); ++i) { + if (i->second.size () > 1) { + return true; + } + } + return false; +} + +void +VariantStatistics::add_variant (std::map &variants, const db::CellInstArray &inst, bool tl_invariant) const +{ + if (tl_invariant) { + add_variant_tl_invariant (variants, inst); + } else { + add_variant_non_tl_invariant (variants, inst); + } +} + +void +VariantStatistics::add_variant_non_tl_invariant (std::map &variants, const db::CellInstArray &inst) const +{ + if (inst.is_complex ()) { + for (db::CellInstArray::iterator i = inst.begin (); ! i.at_end (); ++i) { + variants [mp_red->reduce_trans (inst.complex_trans (*i))] += 1; + } + } else { + for (db::CellInstArray::iterator i = inst.begin (); ! i.at_end (); ++i) { + variants [db::ICplxTrans (mp_red->reduce_trans (*i))] += 1; + } + } +} + +void +VariantStatistics::add_variant_tl_invariant (std::map &variants, const db::CellInstArray &inst) const +{ + if (inst.is_complex ()) { + variants [mp_red->reduce_trans (inst.complex_trans ())] += inst.size (); + } else { + variants [db::ICplxTrans (mp_red->reduce_trans (inst.front ()))] += inst.size (); + } +} + +void +VariantStatistics::product (const std::map &v1, const std::map &v2, std::map &prod) const +{ + for (std::map::const_iterator i = v1.begin (); i != v1.end (); ++i) { + for (std::map::const_iterator j = v2.begin (); j != v2.end (); ++j) { + prod [mp_red->reduce (i->first * j->first)] += i->second * j->second; + } + } +} + } diff --git a/src/db/db/dbCellVariants.h b/src/db/db/dbCellVariants.h index 8375c1c11..f7a938501 100644 --- a/src/db/db/dbCellVariants.h +++ b/src/db/db/dbCellVariants.h @@ -282,6 +282,85 @@ private: RED m_red; }; +/** + * @brief A class computing variants for cells with statistics + * + * This version provides detailed information about the multiplicity of a certain variant. + * It does not offer a way to seperate variants. + */ +class DB_PUBLIC VariantStatistics +{ +public: + /** + * @brief Creates a variant collector without a transformation reducer + */ + VariantStatistics (); + + /** + * @brief Creates a variant collector with the given reducer + */ + VariantStatistics (const TransformationReducer *red); + + /** + * @brief Collects cell variants for the given layout starting from the top cell + */ + void collect (const db::Layout &layout, const db::Cell &top_cell); + /** + * @brief Gets the variants for a given cell + * + * The keys of the map are the variants, the values is the instance count of the variant + * (as seen from the top cell). + */ + const std::map &variants (db::cell_index_type ci) const; + + /** + * @brief Returns true, if variants have been built + */ + bool has_variants () const; + +private: + std::map > m_variants; + const TransformationReducer *mp_red; + + void add_variant (std::map &variants, const db::CellInstArray &inst, bool tl_invariant) const; + void add_variant_non_tl_invariant (std::map &variants, const db::CellInstArray &inst) const; + void add_variant_tl_invariant (std::map &variants, const db::CellInstArray &inst) const; + void product (const std::map &v1, const std::map &v2, std::map &prod) const; +}; + +/** + * @brief A template using a specific transformation reducer + */ +template +class DB_PUBLIC_TEMPLATE cell_variants_statistics + : public VariantStatistics +{ +public: + /** + * @brief Creates a variant statistics without a transformation reducer + */ + cell_variants_statistics () + : VariantStatistics (&m_red) + { + // .. nothing yet .. + } + + /** + * @brief Creates a variant statistics with the given reducer + * + * The statistics object will take ownership over the reducer + */ + cell_variants_statistics (const RED &red) + : VariantStatistics (&m_red), m_red (red) + { + // .. nothing yet .. + } + +private: + RED m_red; +}; + + } // namespace db #endif diff --git a/src/db/db/dbDeepEdges.cc b/src/db/db/dbDeepEdges.cc index 719534e7d..e5c935c68 100644 --- a/src/db/db/dbDeepEdges.cc +++ b/src/db/db/dbDeepEdges.cc @@ -737,7 +737,7 @@ DeepEdges::length_type DeepEdges::length (const db::Box &box) const const db::DeepLayer &edges = merged_deep_layer (); db::MagnificationReducer red; - db::cell_variants_collector vars (red); + db::cell_variants_statistics vars (red); vars.collect (edges.layout (), edges.initial_cell ()); DeepEdges::length_type l = 0; @@ -748,10 +748,10 @@ DeepEdges::length_type DeepEdges::length (const db::Box &box) const for (db::ShapeIterator s = layout.cell (*c).shapes (edges.layer ()).begin (db::ShapeIterator::Edges); ! s.at_end (); ++s) { lc += s->edge ().length (); } - const std::set &vv = vars.variants (*c); + const std::map &vv = vars.variants (*c); for (auto v = vv.begin (); v != vv.end (); ++v) { - double mag = v->mag (); - // @@@ l += v->second * lc * mag; + double mag = v->first.mag (); + l += v->second * lc * mag; } } diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index ff96a0b42..09f7485b3 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -1109,7 +1109,7 @@ DeepRegion::area (const db::Box &box) const const db::DeepLayer &polygons = merged_deep_layer (); - db::cell_variants_collector vars; + db::cell_variants_statistics vars; vars.collect (polygons.layout (), polygons.initial_cell ()); DeepRegion::area_type a = 0; @@ -1120,10 +1120,10 @@ DeepRegion::area (const db::Box &box) const for (db::ShapeIterator s = layout.cell (*c).shapes (polygons.layer ()).begin (db::ShapeIterator::All); ! s.at_end (); ++s) { ac += s->area (); } - const std::set &vv = vars.variants (*c); + const std::map &vv = vars.variants (*c); for (auto v = vv.begin (); v != vv.end (); ++v) { - double mag = v->mag (); - // @@@ a += v->second * ac * mag * mag; + double mag = v->first.mag (); + a += v->second * ac * mag * mag; } } @@ -1146,7 +1146,7 @@ DeepRegion::perimeter (const db::Box &box) const const db::DeepLayer &polygons = merged_deep_layer (); - db::cell_variants_collector vars; + db::cell_variants_statistics vars; vars.collect (polygons.layout (), polygons.initial_cell ()); DeepRegion::perimeter_type p = 0; @@ -1157,10 +1157,10 @@ DeepRegion::perimeter (const db::Box &box) const for (db::ShapeIterator s = layout.cell (*c).shapes (polygons.layer ()).begin (db::ShapeIterator::All); ! s.at_end (); ++s) { pc += s->perimeter (); } - const std::set &vv = vars.variants (*c); + const std::map &vv = vars.variants (*c); for (auto v = vv.begin (); v != vv.end (); ++v) { - double mag = v->mag (); - // @@@ p += v->second * pc * mag; + double mag = v->first.mag (); + p += v->second * pc * mag; } } diff --git a/src/db/unit_tests/dbCellVariantsTests.cc b/src/db/unit_tests/dbCellVariantsTests.cc index acddd9b80..8775743e2 100644 --- a/src/db/unit_tests/dbCellVariantsTests.cc +++ b/src/db/unit_tests/dbCellVariantsTests.cc @@ -39,6 +39,21 @@ std::string var2str (const std::set &vars) return res; } +std::string var2str (const std::map &vars) +{ + std::string res; + for (std::map::const_iterator i = vars.begin (); i != vars.end (); ++i) { + if (! res.empty ()) { + res += ";"; + } + res += i->first.to_string (); + res += "["; + res += tl::to_string (i->second); + res += "]"; + } + return res; +} + std::string vm2str (const db::Layout &ly, const std::map > &vm) { std::string res; @@ -390,6 +405,254 @@ TEST(100_OrientationVariantsWithLayout) db::compare_layouts (_this, ly, tl::testdata () + "/algo/cell_variants_au1.gds"); } +TEST(10_TrivialStatistics) +{ + db::Layout ly; + db::Cell &a = ly.cell (ly.add_cell ("A")); + db::Cell &b = ly.cell (ly.add_cell ("B")); + db::Cell &c = ly.cell (ly.add_cell ("C")); + db::Cell &d = ly.cell (ly.add_cell ("D")); + + a.insert (db::CellInstArray (db::CellInst (b.cell_index ()), db::Trans (0, false, db::Vector (1, 10)))); + + db::OrientationReducer red; + db::cell_variants_statistics vb (red); + vb.collect (ly, a); + EXPECT_EQ (var2str (vb.variants (a.cell_index ())), "r0 *1 0,0[1]"); + EXPECT_EQ (var2str (vb.variants (b.cell_index ())), "r0 *1 0,0[1]"); + EXPECT_EQ (var2str (vb.variants (c.cell_index ())), ""); + EXPECT_EQ (var2str (vb.variants (d.cell_index ())), ""); +} + +TEST(11_TwoVariantsStatistics) +{ + db::Layout ly; + db::Cell &a = ly.cell (ly.add_cell ("A")); + db::Cell &b = ly.cell (ly.add_cell ("B")); + db::Cell &c = ly.cell (ly.add_cell ("C")); + db::Cell &d = ly.cell (ly.add_cell ("D")); + + a.insert (db::CellInstArray (db::CellInst (b.cell_index ()), db::Trans (0, false, db::Vector (1, 10)))); + a.insert (db::CellInstArray (db::CellInst (b.cell_index ()), db::Trans (0, true, db::Vector (1, 100)))); + + db::OrientationReducer red; + db::cell_variants_statistics vb (red); + vb.collect (ly, a); + EXPECT_EQ (var2str (vb.variants (a.cell_index ())), "r0 *1 0,0[1]"); + EXPECT_EQ (var2str (vb.variants (b.cell_index ())), "m0 *1 0,0[1];r0 *1 0,0[1]"); + EXPECT_EQ (var2str (vb.variants (c.cell_index ())), ""); + EXPECT_EQ (var2str (vb.variants (d.cell_index ())), ""); + + EXPECT_EQ (inst2str (ly, a), "B:r0 *1 1,10;B:m0 *1 1,100"); +} + +TEST(12_TwoLevelsStatistics) +{ + db::Layout ly; + db::Cell &a = ly.cell (ly.add_cell ("A")); + db::Cell &b = ly.cell (ly.add_cell ("B")); + db::Cell &c = ly.cell (ly.add_cell ("C")); + db::Cell &d = ly.cell (ly.add_cell ("D")); + + a.insert (db::CellInstArray (db::CellInst (b.cell_index ()), db::Trans (0, false, db::Vector (1, 10)))); + a.insert (db::CellInstArray (db::CellInst (b.cell_index ()), db::Trans (1, false, db::Vector (1, 100)))); + b.insert (db::CellInstArray (db::CellInst (c.cell_index ()), db::Trans (0, false, db::Vector (2, 10)))); + b.insert (db::CellInstArray (db::CellInst (c.cell_index ()), db::Trans (0, true, db::Vector (2, 100)))); + + db::OrientationReducer red; + db::cell_variants_statistics vb (red); + vb.collect (ly, a); + EXPECT_EQ (var2str (vb.variants (a.cell_index ())), "r0 *1 0,0[1]"); + EXPECT_EQ (var2str (vb.variants (b.cell_index ())), "r0 *1 0,0[1];r90 *1 0,0[1]"); + EXPECT_EQ (var2str (vb.variants (c.cell_index ())), "m0 *1 0,0[1];r0 *1 0,0[1];m45 *1 0,0[1];r90 *1 0,0[1]"); + EXPECT_EQ (var2str (vb.variants (d.cell_index ())), ""); + + EXPECT_EQ (inst2str (ly, a), "B:r0 *1 1,10;B:r90 *1 1,100"); + EXPECT_EQ (inst2str (ly, b), "C:r0 *1 2,10;C:m0 *1 2,100"); +} + +TEST(13_ThreeLevelsStatistics) +{ + db::Layout ly; + db::Cell &a = ly.cell (ly.add_cell ("A")); + db::Cell &b = ly.cell (ly.add_cell ("B")); + db::Cell &c = ly.cell (ly.add_cell ("C")); + db::Cell &d = ly.cell (ly.add_cell ("D")); + + a.insert (db::CellInstArray (db::CellInst (b.cell_index ()), db::Trans (0, false, db::Vector (1, 10)))); + a.insert (db::CellInstArray (db::CellInst (b.cell_index ()), db::Trans (1, false, db::Vector (1, 100)))); + b.insert (db::CellInstArray (db::CellInst (c.cell_index ()), db::Trans (0, false, db::Vector (2, 10)))); + b.insert (db::CellInstArray (db::CellInst (c.cell_index ()), db::Trans (0, true, db::Vector (2, 100)))); + c.insert (db::CellInstArray (db::CellInst (d.cell_index ()), db::Trans (1, true, db::Vector (0, 0)))); + + db::OrientationReducer red; + db::cell_variants_statistics vb (red); + vb.collect (ly, a); + EXPECT_EQ (var2str (vb.variants (a.cell_index ())), "r0 *1 0,0[1]"); + EXPECT_EQ (var2str (vb.variants (b.cell_index ())), "r0 *1 0,0[1];r90 *1 0,0[1]"); + EXPECT_EQ (var2str (vb.variants (c.cell_index ())), "m0 *1 0,0[1];r0 *1 0,0[1];m45 *1 0,0[1];r90 *1 0,0[1]"); + EXPECT_EQ (var2str (vb.variants (d.cell_index ())), "r270 *1 0,0[1];m90 *1 0,0[1];r0 *1 0,0[1];m45 *1 0,0[1]"); + + EXPECT_EQ (inst2str (ly, a), "B:r0 *1 1,10;B:r90 *1 1,100"); + EXPECT_EQ (inst2str (ly, b), "C:r0 *1 2,10;C:m0 *1 2,100"); + EXPECT_EQ (inst2str (ly, c), "D:m45 *1 0,0"); +} + +TEST(14_ComplexTransStatistics) +{ + db::Layout ly; + db::Cell &a = ly.cell (ly.add_cell ("A")); + db::Cell &b = ly.cell (ly.add_cell ("B")); + db::Cell &c = ly.cell (ly.add_cell ("C")); + db::Cell &d = ly.cell (ly.add_cell ("D")); + + a.insert (db::CellInstArray (db::CellInst (b.cell_index ()), db::ICplxTrans (db::Trans (0, false, db::Vector (1, 10))))); + a.insert (db::CellInstArray (db::CellInst (b.cell_index ()), db::ICplxTrans (db::Trans (1, false, db::Vector (1, 100))))); + b.insert (db::CellInstArray (db::CellInst (c.cell_index ()), db::ICplxTrans (db::Trans (0, false, db::Vector (2, 10))))); + b.insert (db::CellInstArray (db::CellInst (c.cell_index ()), db::ICplxTrans (db::Trans (0, true, db::Vector (2, 100))))); + + db::OrientationReducer red; + db::cell_variants_statistics vb (red); + vb.collect (ly, a); + EXPECT_EQ (var2str (vb.variants (a.cell_index ())), "r0 *1 0,0[1]"); + EXPECT_EQ (var2str (vb.variants (b.cell_index ())), "r0 *1 0,0[1];r90 *1 0,0[1]"); + EXPECT_EQ (var2str (vb.variants (c.cell_index ())), "m0 *1 0,0[1];r0 *1 0,0[1];m45 *1 0,0[1];r90 *1 0,0[1]"); + EXPECT_EQ (var2str (vb.variants (d.cell_index ())), ""); +} + +TEST(15_ArraysStatistics) +{ + + db::Layout ly; + db::Cell &a = ly.cell (ly.add_cell ("A")); + db::Cell &b = ly.cell (ly.add_cell ("B")); + db::Cell &c = ly.cell (ly.add_cell ("C")); + db::Cell &d = ly.cell (ly.add_cell ("D")); + + a.insert (db::CellInstArray (db::CellInst (b.cell_index ()), db::Trans (0, false, db::Vector (1, 10)), db::Vector (0, 100), db::Vector (100, 0), 10, 10)); + a.insert (db::CellInstArray (db::CellInst (b.cell_index ()), db::Trans (1, false, db::Vector (1, 100)))); + b.insert (db::CellInstArray (db::CellInst (c.cell_index ()), db::Trans (0, false, db::Vector (2, 10)), db::Vector (0, 101), db::Vector (101, 0), 10, 10)); + b.insert (db::CellInstArray (db::CellInst (c.cell_index ()), db::Trans (0, true, db::Vector (2, 100)))); + + db::OrientationReducer red; + db::cell_variants_statistics vb (red); + vb.collect (ly, a); + EXPECT_EQ (var2str (vb.variants (a.cell_index ())), "r0 *1 0,0[1]"); + EXPECT_EQ (var2str (vb.variants (b.cell_index ())), "r0 *1 0,0[100];r90 *1 0,0[1]"); + EXPECT_EQ (var2str (vb.variants (c.cell_index ())), "m0 *1 0,0[100];r0 *1 0,0[10000];m45 *1 0,0[1];r90 *1 0,0[100]"); + EXPECT_EQ (var2str (vb.variants (d.cell_index ())), ""); +} + +TEST(16_ScalingVariantsStatistics) +{ + db::Layout ly; + db::Cell &a = ly.cell (ly.add_cell ("A")); + db::Cell &b = ly.cell (ly.add_cell ("B")); + db::Cell &c = ly.cell (ly.add_cell ("C")); + db::Cell &d = ly.cell (ly.add_cell ("D")); + + a.insert (db::CellInstArray (db::CellInst (b.cell_index ()), db::ICplxTrans (1.5, 0, false, db::Vector (1, 10)), db::Vector (0, 100), db::Vector (100, 0), 10, 10)); + a.insert (db::CellInstArray (db::CellInst (b.cell_index ()), db::ICplxTrans (1.0, 90.0, false, db::Vector (1, 100)))); + b.insert (db::CellInstArray (db::CellInst (c.cell_index ()), db::ICplxTrans (2.0, 0, false, db::Vector (2, 10)), db::Vector (0, 101), db::Vector (101, 0), 10, 10)); + b.insert (db::CellInstArray (db::CellInst (c.cell_index ()), db::ICplxTrans (1.0, 0, true, db::Vector (2, 100)))); + + db::MagnificationReducer red; + db::cell_variants_statistics vb (red); + vb.collect (ly, a); + EXPECT_EQ (var2str (vb.variants (a.cell_index ())), "r0 *1 0,0[1]"); + EXPECT_EQ (var2str (vb.variants (b.cell_index ())), "r0 *1 0,0[1];r0 *1.5 0,0[100]"); + EXPECT_EQ (var2str (vb.variants (c.cell_index ())), "r0 *1 0,0[1];r0 *1.5 0,0[100];r0 *2 0,0[100];r0 *3 0,0[10000]"); + EXPECT_EQ (var2str (vb.variants (d.cell_index ())), ""); +} + +TEST(17_GridVariantsStatistics) +{ + db::Layout ly; + db::Cell &a = ly.cell (ly.add_cell ("A")); + db::Cell &b = ly.cell (ly.add_cell ("B")); + db::Cell &c = ly.cell (ly.add_cell ("C")); + db::Cell &d = ly.cell (ly.add_cell ("D")); + + a.insert (db::CellInstArray (db::CellInst (b.cell_index ()), db::ICplxTrans (1.0, 0, false, db::Vector (1, 10)), db::Vector (0, 101), db::Vector (102, 0), 2, 2)); + b.insert (db::CellInstArray (db::CellInst (c.cell_index ()), db::ICplxTrans (1.0, 0, false, db::Vector (2, 3)))); + + db::GridReducer red (10); + db::cell_variants_statistics vb (red); + vb.collect (ly, a); + EXPECT_EQ (var2str (vb.variants (a.cell_index ())), "r0 *1 0,0[1]"); + EXPECT_EQ (var2str (vb.variants (b.cell_index ())), "r0 *1 1,0[1];r0 *1 3,0[1];r0 *1 1,1[1];r0 *1 3,1[1]"); + + // placements are: + // b in a: r0 *1 x=1,1+102 y=10,10+101 + // c in b: r0 *1 x=2,y=3 + // expanded placements: + // c in a: r0 *2 x=1,1+102 y=10,10+101 x r0 *1 x=2,y=3 + // = (3,13),(105,13),(3,114),(105,114) + // expanded placements mod 10: + // c in a: r0 *2 x=1,1+102 y=10,10+101 x r0 *1 x=2,y=3 + // = (3,3),(5,3),(3,4),(5,4) + EXPECT_EQ (var2str (vb.variants (c.cell_index ())), "r0 *1 -5,3[1];r0 *1 3,3[1];r0 *1 -5,4[1];r0 *1 3,4[1]"); + EXPECT_EQ (var2str (vb.variants (d.cell_index ())), ""); + + EXPECT_EQ (inst2str (ly, a), "B:r0 *1 1,10;B:r0 *1 1,111;B:r0 *1 103,10;B:r0 *1 103,111"); + EXPECT_EQ (inst2str (ly, b), "C:r0 *1 2,3"); + EXPECT_EQ (inst2str (ly, c), ""); +} + +TEST(18_ComplexGridVariantsStatistics) +{ + db::Layout ly; + db::Cell &a = ly.cell (ly.add_cell ("A")); + db::Cell &b = ly.cell (ly.add_cell ("B")); + db::Cell &c = ly.cell (ly.add_cell ("C")); + db::Cell &d = ly.cell (ly.add_cell ("D")); + + a.insert (db::CellInstArray (db::CellInst (b.cell_index ()), db::ICplxTrans (2.0, 0, false, db::Vector (1, 10)), db::Vector (0, 101), db::Vector (102, 0), 2, 2)); + a.insert (db::CellInstArray (db::CellInst (b.cell_index ()), db::ICplxTrans (1.0, 90.0, false, db::Vector (1, 100)))); + b.insert (db::CellInstArray (db::CellInst (c.cell_index ()), db::ICplxTrans (2.0, 0, false, db::Vector (2, 10)), db::Vector (0, 103), db::Vector (105, 0), 2, 2)); + b.insert (db::CellInstArray (db::CellInst (c.cell_index ()), db::ICplxTrans (1.0, 0, true, db::Vector (2, 100)))); + + db::GridReducer red (10); + db::cell_variants_statistics vb (red); + vb.collect (ly, a); + EXPECT_EQ (var2str (vb.variants (a.cell_index ())), "r0 *1 0,0[1]"); + EXPECT_EQ (var2str (vb.variants (b.cell_index ())), "r0 *2 1,0[1];r90 *1 1,0[1];r0 *2 3,0[1];r0 *2 1,1[1];r0 *2 3,1[1]"); + + // placements are: + // b in a: r0 *2 x=1,1+102 y=10,10+101 + // r90 *1 x=1,y=100 + // c in b: r0 *2 x=2,2+105 y=10,10+103 + // m0 *1 x=2,y=100 + // expanded placements: + // c in a: r0 *2 x=1,1+102 y=10,10+101 x r0 *2 x=2,2+105 y=10,10+103 + // = (5,30),(215,30),(5,236),(215,236) + // (107,30),(317,30),(107,236),(317,236) + // (5,131),(215,131),(5,337),(215,337) + // (107,131),(317,131),(107,337),(317,337) + // r0 *2 x=1,1+102 y=10,10+101 x m0 *1 x=2,y=100 + // (5,210),(5,311),(107,210),(107,311) + // r90 *1 x=1,y=100 x r0 *2 x=2,2+105 y=10,10+103 + // (-9,102),(-9,207),(-112,102),(-112,207) + // r90 *1 x=1,y=100 x m0 *1 x=2,y=100 + // (-99,102) + // expanded ((placements + 5) mod 10) - placements + // c in a: r0 *2 x=1,1+102 y=10,10+101 x r0 *2 x=2,2+105 y=10,10+103 + // = (5,0),(5,0),(-5,-4),(-5,-4) + // (7,0),(7,0),(-3,-4),(-3,-4) + // (-5,1),(-5,1),(-5,-3),(-5,-3) + // (-3,1),(-3,1),(-3,-3),(-3,-3) + // r0 *2 x=1,1+102 y=10,10+101 x m0 *1 x=2,y=100 + // (-5,0),(-5,1),(-3,0),(-3,1) + // r90 *1 x=1,y=100 x r0 *2 x=2,2+105 y=10,10+103 + // (1,2),(1,-3),(-2,2),(-2,-3) + // r90 *1 x=1,y=100 x m0 *1 x=2,y=100 + // (1,2) + EXPECT_EQ (var2str (vb.variants (c.cell_index ())), "r0 *4 -5,-4[2];r0 *4 -3,-4[2];r0 *4 -5,-3[2];r0 *4 -3,-3[2];r90 *2 -2,-3[1];" + "r90 *2 1,-3[1];m0 *2 -5,0[1];r0 *4 -5,0[2];m0 *2 -3,0[1];r0 *4 -3,0[2];" + "m0 *2 -5,1[1];r0 *4 -5,1[2];m0 *2 -3,1[1];r0 *4 -3,1[2];r90 *2 -2,2[1];m45 *1 1,2[1];r90 *2 1,2[1]"); + EXPECT_EQ (var2str (vb.variants (d.cell_index ())), ""); +} + TEST(101_Propagation) { db::Layout ly;