Refactoring with the goal to reduce the overhead for variant computation

This commit is contained in:
Matthias Koefferlein 2023-11-18 21:42:24 +01:00
parent b0648e1c45
commit dd81fda27d
5 changed files with 471 additions and 12 deletions

View File

@ -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<db::cell_index_type> 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<db::cell_index_type, std::map<db::ICplxTrans, size_t> > variants_per_parent_cell;
for (db::Cell::parent_inst_iterator pi = layout.cell (*c).begin_parent_insts (); ! pi.at_end (); ++pi) {
std::map<db::ICplxTrans, size_t> &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<db::ICplxTrans, size_t> &new_variants = m_variants [*c];
for (std::map<db::cell_index_type, std::map<db::ICplxTrans, size_t> >::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<db::ICplxTrans, size_t> &
VariantStatistics::variants (db::cell_index_type ci) const
{
std::map<db::cell_index_type, std::map<db::ICplxTrans, size_t> >::const_iterator v = m_variants.find (ci);
static std::map<db::ICplxTrans, size_t> empty_set;
if (v == m_variants.end ()) {
return empty_set;
} else {
return v->second;
}
}
bool
VariantStatistics::has_variants () const
{
for (std::map<db::cell_index_type, std::map<db::ICplxTrans, size_t> >::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<db::ICplxTrans, size_t> &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<db::ICplxTrans, size_t> &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<db::ICplxTrans, size_t> &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<db::ICplxTrans, size_t> &v1, const std::map<db::ICplxTrans, size_t> &v2, std::map<db::ICplxTrans, size_t> &prod) const
{
for (std::map<db::ICplxTrans, size_t>::const_iterator i = v1.begin (); i != v1.end (); ++i) {
for (std::map<db::ICplxTrans, size_t>::const_iterator j = v2.begin (); j != v2.end (); ++j) {
prod [mp_red->reduce (i->first * j->first)] += i->second * j->second;
}
}
}
}

View File

@ -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<db::ICplxTrans, size_t> &variants (db::cell_index_type ci) const;
/**
* @brief Returns true, if variants have been built
*/
bool has_variants () const;
private:
std::map<db::cell_index_type, std::map<db::ICplxTrans, size_t> > m_variants;
const TransformationReducer *mp_red;
void add_variant (std::map<db::ICplxTrans, size_t> &variants, const db::CellInstArray &inst, bool tl_invariant) const;
void add_variant_non_tl_invariant (std::map<db::ICplxTrans, size_t> &variants, const db::CellInstArray &inst) const;
void add_variant_tl_invariant (std::map<db::ICplxTrans, size_t> &variants, const db::CellInstArray &inst) const;
void product (const std::map<db::ICplxTrans, size_t> &v1, const std::map<db::ICplxTrans, size_t> &v2, std::map<db::ICplxTrans, size_t> &prod) const;
};
/**
* @brief A template using a specific transformation reducer
*/
template <class RED>
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

View File

@ -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<db::MagnificationReducer> vars (red);
db::cell_variants_statistics<db::MagnificationReducer> 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<db::ICplxTrans> &vv = vars.variants (*c);
const std::map<db::ICplxTrans, size_t> &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;
}
}

View File

@ -1109,7 +1109,7 @@ DeepRegion::area (const db::Box &box) const
const db::DeepLayer &polygons = merged_deep_layer ();
db::cell_variants_collector<db::MagnificationReducer> vars;
db::cell_variants_statistics<db::MagnificationReducer> 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<db::ICplxTrans> &vv = vars.variants (*c);
const std::map<db::ICplxTrans, size_t> &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<db::MagnificationReducer> vars;
db::cell_variants_statistics<db::MagnificationReducer> 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<db::ICplxTrans> &vv = vars.variants (*c);
const std::map<db::ICplxTrans, size_t> &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;
}
}

View File

@ -39,6 +39,21 @@ std::string var2str (const std::set<db::ICplxTrans> &vars)
return res;
}
std::string var2str (const std::map<db::ICplxTrans, size_t> &vars)
{
std::string res;
for (std::map<db::ICplxTrans, size_t>::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<db::cell_index_type, std::map<db::ICplxTrans, db::cell_index_type> > &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<db::OrientationReducer> 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<db::OrientationReducer> 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<db::OrientationReducer> 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<db::OrientationReducer> 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<db::OrientationReducer> 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<db::OrientationReducer> 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<db::MagnificationReducer> 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<db::GridReducer> 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<db::GridReducer> 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;