From 0e4eab2dced73b316704995f673ee1c71196d831 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 2 Dec 2018 22:26:03 +0100 Subject: [PATCH] WIP: hierarchical net clusters. --- src/db/db/dbHierNetworkProcessor.cc | 637 ++++++++++++++++++++++++++-- 1 file changed, 608 insertions(+), 29 deletions(-) diff --git a/src/db/db/dbHierNetworkProcessor.cc b/src/db/db/dbHierNetworkProcessor.cc index 686520f4a..d26f32bb3 100644 --- a/src/db/db/dbHierNetworkProcessor.cc +++ b/src/db/db/dbHierNetworkProcessor.cc @@ -470,44 +470,623 @@ template class DB_PUBLIC local_clusters; // ------------------------------------------------------------------------------ // 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 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 > &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 hier_clusters; + +/** + * @brief Local clusters with connections to clusters from child cells + */ +template +class DB_PUBLIC connected_clusters + : public local_clusters +{ +public: + typedef std::list connections_type; + typedef typename local_clusters::box_type box_type; + + /** + * @brief Constructor + */ + connected_clusters () + : local_clusters () + { + // .. nothing yet .. + } + + /** + * @brief Gets the connections for a given cluster ID + */ + const connections_type &connections_for_cluster (typename local_cluster::id_type id); + + /** + * @brief Adds a connection between a local cluster and one from a child instance + */ + void add_connection (typename local_cluster::id_type, const ClusterInstance &inst); + + /** + * @brief Joins all connections of with_id to id + */ + void join_connected_clusters (typename local_cluster::id_type id, typename local_cluster::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::id_type find_cluster_with_connection (const ClusterInstance &inst, size_t strip) const; + +private: + std::map::id_type, connections_type> m_connections; + box_type m_full_bbox; +}; + +template +const typename connected_clusters::connections_type & +connected_clusters::connections_for_cluster (typename local_cluster::id_type id) +{ + typename std::map::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 +void +connected_clusters::add_connection (typename local_cluster::id_type id, const ClusterInstance &inst) +{ + m_connections [id].push_back (inst); +} + +template +void +connected_clusters::join_connected_clusters (typename local_cluster::id_type id, typename local_cluster::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 +typename local_cluster::id_type +connected_clusters::find_cluster_with_connection (const ClusterInstance &ci, size_t strip) const +{ + for (typename std::map::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 class cell_box_converter; + +/** + * @brief A hierarchical representation of clusters + * + * Hierarchical clusters + */ +template +class DB_PUBLIC hier_clusters +{ +public: + typedef typename local_cluster::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 &clusters_per_cell (db::cell_index_type cell_index) const; + + /** + * @brief Clears this collection + */ + void clear (); + +private: + void do_build (cell_box_converter &cbc, const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn); + + std::map > m_per_cell_clusters; +}; + +template +class DB_PUBLIC cell_box_converter +{ +public: + typedef db::simple_bbox_tag complexity; + typedef typename hier_clusters::box_type box_type; + + cell_box_converter (const db::Layout &layout, const hier_clusters &tree) + : mp_layout (&layout), mp_tree (&tree) + { + // .. nothing yet .. + } + + const box_type &operator() (db::cell_index_type cell_index) const + { + typename std::map::const_iterator b = m_cache.find (cell_index); + if (b != m_cache.end ()) { + + return b->second; + + } else { + + const connected_clusters &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 m_cache; + const db::Layout *mp_layout; + const hier_clusters *mp_tree; +}; + +template +hier_clusters::hier_clusters () +{ + // .. nothing yet .. +} + +template +void hier_clusters::clear () +{ + m_per_cell_clusters.clear (); +} + +template +void +hier_clusters::build (const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn) +{ + clear (); + cell_box_converter cbc (layout, *this); + do_build (cbc, layout, cell, shape_flags, conn); +} + +namespace +{ + +template +struct hc_receiver + : public db::box_scanner_receiver, + public db::box_scanner_receiver2, unsigned int, db::Instance, unsigned int> +{ +public: + typedef typename hier_clusters::box_type box_type; + typedef typename local_cluster::id_type id_type; + typedef std::map *> connector_map; + + hc_receiver (const db::Layout &layout, db::connected_clusters &cell_clusters, hier_clusters &tree, const cell_box_converter &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 p; + db::ICplxTrans t; + add_pair (*i1, p, t, *i2, p, t); + } + + void add (const local_cluster *c1, unsigned int /*p1*/, const db::Instance *i2, unsigned int /*p2*/) + { + std::vector p; + db::ICplxTrans t; + add_pair (*c1, *i2, p, t); + } + + bool stop () const + { + return false; + } + +private: + const db::Layout *mp_layout; + db::connected_clusters *mp_cell_clusters; + hier_clusters *mp_tree; + const cell_box_converter *mp_cbc; + const db::Connectivity *mp_conn; + connector_map m_connectors; + mutable std::map m_reduction_cache; + + void add_pair (const db::Instance &i1, const std::vector &p1, const db::ICplxTrans &t1, const db::Instance &i2, const std::vector &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 &p1, const db::ICplxTrans &t1, + db::cell_index_type ci2, const std::vector &p2, const db::ICplxTrans &t2) + { + const db::local_clusters &cl1 = mp_tree->clusters_per_cell (ci1); + const db::local_clusters &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::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::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 *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 &c1, const db::Instance &i2, const std::vector &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 &c1, + db::cell_index_type ci2, const std::vector &p2, const db::ICplxTrans &t2) + { + const db::local_clusters &cl2 = mp_tree->clusters_per_cell (ci2); + + for (typename db::local_clusters::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::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 &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 +struct cell_inst_clusters_box_converter +{ + typedef typename local_cluster::box_type box_type; + typedef db::simple_bbox_tag complexity; + + cell_inst_clusters_box_converter (const cell_box_converter &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 *mp_cbc; }; -#endif + +} + +template +void +hier_clusters::do_build (cell_box_converter &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 &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 rec (layout, local, *this, cbc, conn); + cell_inst_clusters_box_converter cibc (cbc); + + // handle instance to instance connections + + { + db::box_scanner 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, unsigned int, db::Instance, unsigned int> bs2; + + for (typename connected_clusters::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 (), cibc); + } +} + +template +const connected_clusters & +hier_clusters::clusters_per_cell (db::cell_index_type cell_index) const +{ + typename std::map >::const_iterator c = m_per_cell_clusters.find (cell_index); + if (c == m_per_cell_clusters.end ()) { + static connected_clusters empty; + return empty; + } else { + return c->second; + } +} + +// explicit instantiations +template class DB_PUBLIC hier_clusters; }