WIP: hierarchical net clusters.

This commit is contained in:
Matthias Koefferlein 2018-12-02 22:26:03 +01:00
parent f7f9f4f1fc
commit 0e4eab2dce
1 changed files with 608 additions and 29 deletions

View File

@ -470,44 +470,623 @@ template class DB_PUBLIC local_clusters<db::PolygonRef>;
// ------------------------------------------------------------------------------
// hier_clusters implementation
#if 0
/**
* @brief Represents all clusters in a cell and their connections to child cells
*
* Connections to indirect children are made through empty dummy clusters.
* Also, connections between two clusters of different children without
* mediating cluster on cell level are made through empty dummy clusters.
* Hence, there is always a cluster in the parent cell which connects to
* clusters from child cells.
* @brief A connection to a cluster in a child instance
*/
class HierarchicalClusters
class DB_PUBLIC ClusterInstance
{
public:
HierarchicalClusters ();
typedef std::vector<db::InstElement> inst_path_type;
LocalClusters &local ();
ClusterInstance (size_t id, const inst_path_type &inst_path)
: m_id (id), m_inst_path (inst_path)
{
// .. nothing yet ..
}
// build local clusters
// determine local to cell cluster interactions -> top-down connection, maybe across dummy
// identify cell overlaps
// determine cell-to-cell cluster interactions -> make dummy cluster to connect both, connect to each child
// maybe across dummy cluster
// shall be called bottom-up
void build_clusters (const db::Cell &cell, const Connectivity &conn);
/**
* @brief Gets the cluster ID
*/
size_t id () const
{
return m_id;
}
// @@@ trans is the transformation from child to this (instance transformation)
// used by child clusters to verify whether they are connected somewhere in the parent
LocalCluster::id_type is_connected_to (LocalCluster::id_type id, const db::InstElement &trans) const;
/**
* @brief Gets the instance path
*/
const inst_path_type &inst () const
{
return m_inst_path;
}
// connections to subcells (== pins?)
const std::vector<std::pair<LocalCluster::id_type, db::InstElement> > &top_down_connections (LocalCluster::id_type) const;
/**
* @brief Equality
*/
bool operator== (const ClusterInstance &other) const
{
return m_id == other.m_id && m_inst_path == other.m_inst_path;
}
// propagate all connected clusters to their parents
// -> creates new local clusters, removes them from their local set
// used by the merge step to form local-only clusters
// can be called bottom-up
void propagate_connected ();
/**
* @brief Less operator
*/
bool operator< (const ClusterInstance &other) const
{
if (m_id != other.m_id) {
return m_id < other.m_id;
}
return m_inst_path < other.m_inst_path;
}
private:
size_t m_id;
inst_path_type m_inst_path;
};
template <class T> class hier_clusters;
/**
* @brief Local clusters with connections to clusters from child cells
*/
template <class T>
class DB_PUBLIC connected_clusters
: public local_clusters<T>
{
public:
typedef std::list<ClusterInstance> connections_type;
typedef typename local_clusters<T>::box_type box_type;
/**
* @brief Constructor
*/
connected_clusters ()
: local_clusters<T> ()
{
// .. nothing yet ..
}
/**
* @brief Gets the connections for a given cluster ID
*/
const connections_type &connections_for_cluster (typename local_cluster<T>::id_type id);
/**
* @brief Adds a connection between a local cluster and one from a child instance
*/
void add_connection (typename local_cluster<T>::id_type, const ClusterInstance &inst);
/**
* @brief Joins all connections of with_id to id
*/
void join_connected_clusters (typename local_cluster<T>::id_type id, typename local_cluster<T>::id_type with_id);
/**
* @brief Reverse "connections_for_cluster"
*
* Finds the cluster which has a connection given by inst. "strip" elements
* are stipped from the front of the instantiation path.
* This method returns 0 if no cluster can be found.
*/
typename local_cluster<T>::id_type find_cluster_with_connection (const ClusterInstance &inst, size_t strip) const;
private:
std::map<typename local_cluster<T>::id_type, connections_type> m_connections;
box_type m_full_bbox;
};
template <class T>
const typename connected_clusters<T>::connections_type &
connected_clusters<T>::connections_for_cluster (typename local_cluster<T>::id_type id)
{
typename std::map<typename local_cluster<T>::id_type, connections_type>::const_iterator c = m_connections.find (id);
if (c == m_connections.end ()) {
static connections_type empty_connections;
return empty_connections;
} else {
return c->second;
}
}
template <class T>
void
connected_clusters<T>::add_connection (typename local_cluster<T>::id_type id, const ClusterInstance &inst)
{
m_connections [id].push_back (inst);
}
template <class T>
void
connected_clusters<T>::join_connected_clusters (typename local_cluster<T>::id_type id, typename local_cluster<T>::id_type with_id)
{
if (id == with_id) {
return;
}
const connections_type &to_join = connections_for_cluster (with_id);
connections_type &target = m_connections [id];
target.insert (target.end (), to_join.begin (), to_join.end ());
m_connections.erase (with_id);
}
template <class T>
typename local_cluster<T>::id_type
connected_clusters<T>::find_cluster_with_connection (const ClusterInstance &ci, size_t strip) const
{
for (typename std::map<typename local_cluster<T>::id_type, connections_type>::const_iterator i = m_connections.begin (); i != m_connections.end (); ++i) {
for (connections_type::const_iterator j = i->second.begin (); j != i->second.end (); ++j) {
const ClusterInstance::inst_path_type &path = j->inst ();
if (j->id () == ci.id () && path.size () == ci.inst ().size () - strip) {
bool match = true;
for (size_t k = 0; k < path.size () && match; ++k) {
match = (path [k] == ci.inst () [k + strip]);
}
if (match) {
return i->first;
}
}
}
}
return 0;
}
template <typename> class cell_box_converter;
/**
* @brief A hierarchical representation of clusters
*
* Hierarchical clusters
*/
template <class T>
class DB_PUBLIC hier_clusters
{
public:
typedef typename local_cluster<T>::box_type box_type;
/**
* @brief Creates an empty set of clusters
*/
hier_clusters ();
/**
* @brief Builds a hierarchy of clusters from a cell hierarchy and given connectivity
*/
void build (const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn);
/**
* @brief Gets the connected clusters for a given cell
*/
const connected_clusters<T> &clusters_per_cell (db::cell_index_type cell_index) const;
/**
* @brief Clears this collection
*/
void clear ();
private:
void do_build (cell_box_converter<T> &cbc, const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn);
std::map<db::cell_index_type, connected_clusters<T> > m_per_cell_clusters;
};
template <class T>
class DB_PUBLIC cell_box_converter
{
public:
typedef db::simple_bbox_tag complexity;
typedef typename hier_clusters<T>::box_type box_type;
cell_box_converter (const db::Layout &layout, const hier_clusters<T> &tree)
: mp_layout (&layout), mp_tree (&tree)
{
// .. nothing yet ..
}
const box_type &operator() (db::cell_index_type cell_index) const
{
typename std::map<db::cell_index_type, box_type>::const_iterator b = m_cache.find (cell_index);
if (b != m_cache.end ()) {
return b->second;
} else {
const connected_clusters<T> &clusters = mp_tree->clusters_per_cell (cell_index);
box_type box = clusters.bbox ();
const db::Cell &cell = mp_layout->cell (cell_index);
for (db::Cell::const_iterator inst = cell.begin (); ! inst.at_end (); ++inst) {
const db::CellInstArray &inst_array = inst->cell_inst ();
box += inst_array.raw_bbox () * (*this) (inst_array.object ().cell_index ());
}
return m_cache.insert (std::make_pair (cell_index, box)).first->second;
}
}
private:
mutable std::map<db::cell_index_type, box_type> m_cache;
const db::Layout *mp_layout;
const hier_clusters<T> *mp_tree;
};
template <class T>
hier_clusters<T>::hier_clusters ()
{
// .. nothing yet ..
}
template <class T>
void hier_clusters<T>::clear ()
{
m_per_cell_clusters.clear ();
}
template <class T>
void
hier_clusters<T>::build (const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn)
{
clear ();
cell_box_converter<T> cbc (layout, *this);
do_build (cbc, layout, cell, shape_flags, conn);
}
namespace
{
template <class T>
struct hc_receiver
: public db::box_scanner_receiver<db::Instance, unsigned int>,
public db::box_scanner_receiver2<local_cluster<T>, unsigned int, db::Instance, unsigned int>
{
public:
typedef typename hier_clusters<T>::box_type box_type;
typedef typename local_cluster<T>::id_type id_type;
typedef std::map<ClusterInstance, local_cluster<T> *> connector_map;
hc_receiver (const db::Layout &layout, db::connected_clusters<T> &cell_clusters, hier_clusters<T> &tree, const cell_box_converter<T> &cbc, const db::Connectivity &conn)
: mp_layout (&layout), mp_tree (&tree), mp_cbc (&cbc), mp_conn (&conn)
{
mp_cell_clusters = &cell_clusters;
}
void add (const db::Instance *i1, unsigned int /*p1*/, const db::Instance *i2, unsigned int /*p2*/)
{
std::vector<db::InstElement> p;
db::ICplxTrans t;
add_pair (*i1, p, t, *i2, p, t);
}
void add (const local_cluster<T> *c1, unsigned int /*p1*/, const db::Instance *i2, unsigned int /*p2*/)
{
std::vector<db::InstElement> p;
db::ICplxTrans t;
add_pair (*c1, *i2, p, t);
}
bool stop () const
{
return false;
}
private:
const db::Layout *mp_layout;
db::connected_clusters<T> *mp_cell_clusters;
hier_clusters<T> *mp_tree;
const cell_box_converter<T> *mp_cbc;
const db::Connectivity *mp_conn;
connector_map m_connectors;
mutable std::map<ClusterInstance, ClusterInstance> m_reduction_cache;
void add_pair (const db::Instance &i1, const std::vector<db::InstElement> &p1, const db::ICplxTrans &t1, const db::Instance &i2, const std::vector<db::InstElement> &p2, const db::ICplxTrans &t2)
{
box_type bb1 = (*mp_cbc) (i1.cell_index ());
box_type b1 = (i1.cell_inst ().raw_bbox () * bb1).transformed (t1);
box_type bb2 = (*mp_cbc) (i2.cell_index ());
box_type b2 = (i2.cell_inst ().raw_bbox () * bb2).transformed (t2);
if (! b1.touches (b2)) {
return;
}
db::ICplxTrans t2i = t2.inverted ();
db::ICplxTrans t12 = t2i * t1;
box_type common = b1 & b2;
for (db::CellInstArray::iterator ii1 = i1.begin_touching (common, mp_layout); ! ii1.at_end (); ++ii1) {
db::ICplxTrans tt1 = t1 * i1.complex_trans (*ii1);
box_type ib1 = bb1.transformed (tt1);
box_type ib12 = ib1.transformed (t12);
ClusterInstance::inst_path_type pp1;
pp1.reserve (p1.size () + 1);
pp1.insert (pp1.end (), p1.begin (), p1.end ());
pp1.push_back (db::InstElement (i1, ii1));
for (db::CellInstArray::iterator ii2 = i2.begin_touching (ib12, mp_layout); ! ii2.at_end (); ++ii2) {
db::ICplxTrans tt2 = t2 * i2.complex_trans (*ii2);
box_type ib2 = bb2.transformed (tt2);
if (ib1.touches (ib2)) {
ClusterInstance::inst_path_type pp2;
pp2.reserve (p2.size () + 1);
pp2.insert (pp2.end (), p2.begin (), p2.end ());
pp2.push_back (db::InstElement (i2, ii2));
add_single_pair (common, i1.cell_index (), pp1, tt1, i2.cell_index (), pp2, tt2);
// dive into cell of ii2
const db::Cell &cell2 = mp_layout->cell (i2.cell_index ());
for (db::Cell::touching_iterator jj2 = cell2.begin_touching (common.transformed (tt2.inverted ())); ! jj2.at_end (); ++jj2) {
add_pair (i1, p1, t1, *jj2, pp2, tt2);
}
}
}
// dive into cell of ii1
const db::Cell &cell1 = mp_layout->cell (i1.cell_index ());
for (db::Cell::touching_iterator jj1 = cell1.begin_touching (common.transformed (tt1.inverted ())); ! jj1.at_end (); ++jj1) {
add_pair (*jj1, pp1, tt1, i2, p2, t2);
}
}
}
void add_single_pair (const box_type &common,
db::cell_index_type ci1, const std::vector<db::InstElement> &p1, const db::ICplxTrans &t1,
db::cell_index_type ci2, const std::vector<db::InstElement> &p2, const db::ICplxTrans &t2)
{
const db::local_clusters<T> &cl1 = mp_tree->clusters_per_cell (ci1);
const db::local_clusters<T> &cl2 = mp_tree->clusters_per_cell (ci2);
db::ICplxTrans t1i = t1.inverted ();
db::ICplxTrans t2i = t2.inverted ();
db::ICplxTrans t21 = t1i * t2;
for (typename db::local_clusters<T>::touching_iterator i = cl1.begin_touching (common.transformed (t1i)); ! i.at_end (); ++i) {
box_type bc1 = common & i->bbox ().transformed (t1);
for (typename db::local_clusters<T>::touching_iterator j = cl2.begin_touching (bc1.transformed (t2i)); ! j.at_end (); ++j) {
if (i->interacts (*j, t21, *mp_conn)) {
ClusterInstance k1 (i->id (), p1);
reduce (k1);
ClusterInstance k2 (j->id (), p2);
reduce (k2);
typename connector_map::iterator x1 = m_connectors.find (k1);
typename connector_map::iterator x2 = m_connectors.find (k2);
if (x1 == m_connectors.end ()) {
if (x2 == m_connectors.end ()) {
db::local_cluster<T> *connector = mp_cell_clusters->insert ();
m_connectors [k1] = connector;
mp_cell_clusters->add_connection (connector->id (), k1);
mp_cell_clusters->add_connection (connector->id (), k2);
} else {
mp_cell_clusters->add_connection (x2->second->id (), k1);
}
} else if (x2 == m_connectors.end ()) {
mp_cell_clusters->add_connection (x1->second->id (), k2);
} else if (x1->second != x2->second) {
mp_cell_clusters->join_connected_clusters (x1->second->id (), x2->second->id ());
mp_cell_clusters->remove_cluster (x2->second->id ());
x2->second = x1->second;
}
}
}
}
}
void add_pair (const local_cluster<T> &c1, const db::Instance &i2, const std::vector<db::InstElement> &p2, const db::ICplxTrans &t2)
{
box_type b1 = c1.bbox ();
box_type bb2 = (*mp_cbc) (i2.cell_index ());
box_type b2 = (i2.cell_inst ().raw_bbox () * bb2).transformed (t2);
if (! b1.touches (b2)) {
return;
}
box_type common = b1 & b2;
for (db::CellInstArray::iterator ii2 = i2.begin_touching (common.transformed (t2.inverted ()), mp_layout); ! ii2.at_end (); ++ii2) {
db::ICplxTrans tt2 = t2 * i2.complex_trans (*ii2);
box_type ib2 = bb2.transformed (tt2);
if (b1.touches (ib2)) {
ClusterInstance::inst_path_type pp2;
pp2.reserve (p2.size () + 1);
pp2.insert (pp2.end (), p2.begin (), p2.end ());
pp2.push_back (db::InstElement (i2, ii2));
add_single_pair (c1, i2.cell_index (), pp2, tt2);
// dive into cell of ii2
const db::Cell &cell2 = mp_layout->cell (i2.cell_index ());
for (db::Cell::touching_iterator jj2 = cell2.begin_touching (common.transformed (tt2.inverted ())); ! jj2.at_end (); ++jj2) {
add_pair (c1, *jj2, pp2, tt2);
}
}
}
}
void add_single_pair (const local_cluster<T> &c1,
db::cell_index_type ci2, const std::vector<db::InstElement> &p2, const db::ICplxTrans &t2)
{
const db::local_clusters<T> &cl2 = mp_tree->clusters_per_cell (ci2);
for (typename db::local_clusters<T>::touching_iterator j = cl2.begin_touching (c1.bbox ().transformed (t2.inverted ())); ! j.at_end (); ++j) {
if (c1.interacts (*j, t2, *mp_conn)) {
ClusterInstance k2 (j->id (), p2);
reduce (k2);
mp_cell_clusters->add_connection (c1.id (), k2);
}
}
}
/**
* @brief Reduce the connection path to the connector highest in the hierarchy
*
* This feature shall prevent a situation where a connection is made to a sub-cluster of
* another hierarchical cluster. We always attach to the highest possible connector.
*/
void reduce (ClusterInstance &k) const
{
std::map<ClusterInstance, ClusterInstance>::const_iterator kr = m_reduction_cache.find (k);
if (kr != m_reduction_cache.end ()) {
k = kr->second;
return;
}
for (size_t rn = 1; rn + 1 < k.inst ().size (); ++rn) {
const db::connected_clusters<T> &clusters = mp_tree->clusters_per_cell (k.inst () [rn - 1].inst_ptr.cell_index ());
id_type red_id = clusters.find_cluster_with_connection (k, rn);
if (red_id > 0) {
// reduction possible
ClusterInstance::inst_path_type new_path;
new_path.insert (new_path.end (), k.inst ().begin (), k.inst ().begin () + rn);
k = ClusterInstance (red_id, new_path);
return;
}
}
}
};
template <class T>
struct cell_inst_clusters_box_converter
{
typedef typename local_cluster<T>::box_type box_type;
typedef db::simple_bbox_tag complexity;
cell_inst_clusters_box_converter (const cell_box_converter<T> &cbc)
: mp_cbc (&cbc)
{
// .. nothing yet ..
}
box_type operator() (const db::Instance &inst) const
{
return inst.cell_inst ().raw_bbox () * (*mp_cbc) (inst.cell_index ());
}
private:
const cell_box_converter<T> *mp_cbc;
};
#endif
}
template <class T>
void
hier_clusters<T>::do_build (cell_box_converter<T> &cbc, const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn)
{
// already done - don't do again
if (m_per_cell_clusters.find (cell.cell_index ()) != m_per_cell_clusters.end ()) {
return;
}
// Build local clusters
connected_clusters<T> &local = m_per_cell_clusters [cell.cell_index ()];
local.build_clusters (cell, shape_flags, conn);
// handle connections inside child cells in a bottom-up fashion
for (db::Cell::child_cell_iterator cc = cell.begin_child_cells (); ! cc.at_end (); ++cc) {
do_build (cbc, layout, layout.cell (*cc), shape_flags, conn);
}
// NOTE: this is a receiver for both the child-to-child and
// local to child interactions.
hc_receiver<T> rec (layout, local, *this, cbc, conn);
cell_inst_clusters_box_converter<T> cibc (cbc);
// handle instance to instance connections
{
db::box_scanner<db::Instance, unsigned int> bs;
for (db::Cell::const_iterator inst = cell.begin (); ! inst.at_end (); ++inst) {
bs.insert (inst.operator-> (), 0);
}
bs.process (rec, 1 /*touching*/, cibc);
}
// handle local to instance connections
{
db::box_scanner2<db::local_cluster<T>, unsigned int, db::Instance, unsigned int> bs2;
for (typename connected_clusters<T>::const_iterator c = local.begin (); c != local.end (); ++c) {
bs2.insert1 (c.operator-> (), 0);
}
for (db::Cell::const_iterator inst = cell.begin (); ! inst.at_end (); ++inst) {
bs2.insert2 (inst.operator-> (), 0);
}
bs2.process (rec, 1 /*touching*/, local_cluster_box_convert<T> (), cibc);
}
}
template <class T>
const connected_clusters<T> &
hier_clusters<T>::clusters_per_cell (db::cell_index_type cell_index) const
{
typename std::map<db::cell_index_type, connected_clusters<T> >::const_iterator c = m_per_cell_clusters.find (cell_index);
if (c == m_per_cell_clusters.end ()) {
static connected_clusters<T> empty;
return empty;
} else {
return c->second;
}
}
// explicit instantiations
template class DB_PUBLIC hier_clusters<db::PolygonRef>;
}