diff --git a/src/pex/pex/pexRExtractor.cc b/src/pex/pex/pexRExtractor.cc index 4913c90ab..1df03457b 100644 --- a/src/pex/pex/pexRExtractor.cc +++ b/src/pex/pex/pexRExtractor.cc @@ -22,6 +22,7 @@ #include "pexRExtractor.h" +#include "tlEquivalenceClusters.h" namespace pex { @@ -102,9 +103,6 @@ RNetwork::clear () m_nodes_by_type.clear (); } -std::map, RElement *> m_elements_by_nodes; -std::map, RNode *> m_nodes; - RNode * RNetwork::create_node (RNode::node_type type, unsigned int port_index) { @@ -189,6 +187,113 @@ RNetwork::remove_element (RElement *element) } } +void +RNetwork::join_nodes (RNode *a, RNode *b) +{ + for (auto e = b->elements ().begin (); e != b->elements ().end (); ++e) { + RNode *on = const_cast ((*e)->other (b)); + if (on != a) { + create_element ((*e)->conductivity, on, a); + } + } + + remove_node (b); +} + +void +RNetwork::simplify () +{ + bool any_change = true; + + while (any_change) { + + any_change = false; + + // join shorted clusters - we take care to remove internal nodes only + + tl::equivalence_clusters clusters; + for (auto e = m_elements.begin (); e != m_elements.end (); ++e) { + if (e->conductivity == pex::RElement::short_value () && (e->a ()->type == pex::RNode::Internal || e->b ()->type == pex::RNode::Internal)) { + clusters.same (e->a (), e->b ()); + } + } + + for (size_t ic = 1; ic <= clusters.size (); ++ic) { + + RNode *remaining = 0; + RNode *first_node = 0; + for (auto c = clusters.begin_cluster (ic); c != clusters.end_cluster (ic); ++c) { + RNode *n = const_cast ((*c)->first); + if (! first_node) { + first_node = n; + } + if (n->type != pex::RNode::Internal) { + remaining = n; + break; + } + } + + if (! remaining) { + // Only internal nodes + remaining = first_node; + } + + for (auto c = clusters.begin_cluster (ic); c != clusters.end_cluster (ic); ++c) { + RNode *n = const_cast ((*c)->first); + if (n != remaining && n->type == pex::RNode::Internal) { + any_change = true; + join_nodes (remaining, n); + } + } + + } + + // combine serial resistors if connected through an internal node + + std::vector nodes_to_remove; + + for (auto n = m_nodes.begin (); n != m_nodes.end (); ++n) { + + size_t nres = n->elements ().size (); + + if (n->type == pex::RNode::Internal && nres <= 2) { + + any_change = true; + + if (nres == 2) { + + auto e = n->elements ().begin (); + + RNode *n1 = const_cast ((*e)->other (n.operator-> ())); + double r1 = (*e)->resistance (); + + ++e; + RNode *n2 = const_cast ((*e)->other (n.operator-> ())); + double r2 = (*e)->resistance (); + + double r = r1 + r2; + if (r == 0.0) { + create_element (pex::RElement::short_value (), n1, n2); + } else { + create_element (1.0 / r, n1, n2); + } + + } + + nodes_to_remove.push_back (n.operator-> ()); + + } + + } + + for (auto n = nodes_to_remove.begin (); n != nodes_to_remove.end (); ++n) { + remove_node (*n); + } + + } + +} + // ----------------------------------------------------------------------------- RExtractor::RExtractor () diff --git a/src/pex/pex/pexRExtractor.h b/src/pex/pex/pexRExtractor.h index 890b6ad67..f1c4f4659 100644 --- a/src/pex/pex/pexRExtractor.h +++ b/src/pex/pex/pexRExtractor.h @@ -88,6 +88,16 @@ struct PEX_PUBLIC RElement const RNode *a () const { return mp_a; } const RNode *b () const { return mp_b; } + const RNode *other (const RNode *n) const + { + if (mp_a == n) { + return mp_b; + } else if (mp_b == n) { + return mp_a; + } + tl_assert (false); + } + static double short_value () { return std::numeric_limits::infinity (); @@ -140,6 +150,7 @@ public: void remove_element (RElement *element); void remove_node (RNode *node); void clear (); + void simplify (); std::string to_string () const; @@ -151,6 +162,8 @@ private: RNetwork (const RNetwork &); RNetwork &operator= (const RNetwork &); + + void join_nodes (RNode *a, RNode *b); }; diff --git a/src/pex/pex/pexSquareCountingRExtractor.cc b/src/pex/pex/pexSquareCountingRExtractor.cc index eaa865719..5477abdb0 100644 --- a/src/pex/pex/pexSquareCountingRExtractor.cc +++ b/src/pex/pex/pexSquareCountingRExtractor.cc @@ -133,11 +133,11 @@ SquareCountingRExtractor::do_extract (const db::Polygon &db_poly, const std::vec } } - // sort the port locations + // sort the port locations - note that we take the port box centers for the location! std::multimap port_locations; for (auto p = ports.begin (); p != ports.end (); ++p) { - db::Coord c = (trans * p->first.location).x (); + db::Coord c = (trans * p->first.location).center ().x (); port_locations.insert (std::make_pair (c, p->second)); } @@ -258,7 +258,7 @@ SquareCountingRExtractor::extract (const db::Polygon &polygon, const std::vector // 1. internal ports for (auto i = ip_indexes.begin (); i != ip_indexes.end (); ++i) { - db::Point loc = (inv_trans * internal_port_edges [*i]->edge ()).bbox ().center (); + db::Box loc = (inv_trans * internal_port_edges [*i]->edge ()).bbox (); ports.push_back (std::make_pair (PortDefinition (pex::RNode::Internal, loc, *i), (pex::RNode *) 0)); } @@ -271,7 +271,7 @@ SquareCountingRExtractor::extract (const db::Polygon &polygon, const std::vector // 3. polygon ports // (NOTE: here we only take the center of the bounding box) for (auto i = pp_indexes.begin (); i != pp_indexes.end (); ++i) { - db::Point loc = polygon_ports [*i].box ().center (); + db::Box loc = polygon_ports [*i].box (); ports.push_back (std::make_pair (PortDefinition (pex::RNode::PolygonPort, loc, *i), (pex::RNode *) 0)); } @@ -282,8 +282,7 @@ SquareCountingRExtractor::extract (const db::Polygon &polygon, const std::vector auto n4p = nodes_for_ports.find (p->first); if (n4p == nodes_for_ports.end ()) { pex::RNode *node = rnetwork.create_node (p->first.type, p->first.port_index); - db::DPoint loc = trans * p->first.location; - node->location = db::DBox (loc, loc); + node->location = trans * p->first.location; n4p = nodes_for_ports.insert (std::make_pair (p->first, node)).first; } p->second = n4p->second; diff --git a/src/pex/pex/pexSquareCountingRExtractor.h b/src/pex/pex/pexSquareCountingRExtractor.h index b498bb1b2..abacc2dfa 100644 --- a/src/pex/pex/pexSquareCountingRExtractor.h +++ b/src/pex/pex/pexSquareCountingRExtractor.h @@ -66,6 +66,10 @@ protected: { } PortDefinition (pex::RNode::node_type _type, const db::Point &_location, unsigned int _port_index) + : type (_type), location (_location, _location), port_index (_port_index) + { } + + PortDefinition (pex::RNode::node_type _type, const db::Box &_location, unsigned int _port_index) : type (_type), location (_location), port_index (_port_index) { } @@ -86,7 +90,7 @@ protected: } pex::RNode::node_type type; - db::Point location; + db::Box location; unsigned int port_index; }; diff --git a/src/pex/unit_tests/pexRExtractorTests.cc b/src/pex/unit_tests/pexRExtractorTests.cc index 3915e8337..d386ce621 100644 --- a/src/pex/unit_tests/pexRExtractorTests.cc +++ b/src/pex/unit_tests/pexRExtractorTests.cc @@ -74,3 +74,114 @@ TEST(network_basic) EXPECT_EQ (rn.to_string (), ""); } +TEST(network_simplify1) +{ + pex::RNetwork rn; + EXPECT_EQ (rn.to_string (), ""); + + pex::RNode *n1 = rn.create_node (pex::RNode::VertexPort, 1); + pex::RNode *n2 = rn.create_node (pex::RNode::Internal, 2); + pex::RNode *n3 = rn.create_node (pex::RNode::VertexPort, 3); + + rn.create_element (1, n1, n2); + rn.create_element (pex::RElement::short_value (), n2, n3); + rn.create_element (1, n1, n3); + + EXPECT_EQ (rn.to_string (), + "R V1 $2 1\n" + "R $2 V3 0\n" + "R V1 V3 1" + ); + + rn.simplify (); + + EXPECT_EQ (rn.to_string (), + "R V1 V3 0.5" + ); +} + +TEST(network_simplify2) +{ + pex::RNetwork rn; + EXPECT_EQ (rn.to_string (), ""); + + pex::RNode *n1 = rn.create_node (pex::RNode::VertexPort, 1); + pex::RNode *n2 = rn.create_node (pex::RNode::Internal, 2); + pex::RNode *n3 = rn.create_node (pex::RNode::Internal, 3); + pex::RNode *n4 = rn.create_node (pex::RNode::VertexPort, 4); + pex::RNode *n5 = rn.create_node (pex::RNode::VertexPort, 5); + + rn.create_element (1, n1, n2); + rn.create_element (pex::RElement::short_value (), n2, n3); + rn.create_element (1, n3, n4); + rn.create_element (1, n3, n5); + + EXPECT_EQ (rn.to_string (), + "R V1 $2 1\n" + "R $2 $3 0\n" + "R $3 V4 1\n" + "R $3 V5 1" + ); + + rn.simplify (); + + EXPECT_EQ (rn.to_string (), + "R V1 $2 1\n" + "R V4 $2 1\n" + "R V5 $2 1" + ); +} + +TEST(network_simplify3) +{ + pex::RNetwork rn; + EXPECT_EQ (rn.to_string (), ""); + + pex::RNode *n1 = rn.create_node (pex::RNode::VertexPort, 1); + pex::RNode *n2 = rn.create_node (pex::RNode::Internal, 2); + pex::RNode *n3 = rn.create_node (pex::RNode::Internal, 3); + pex::RNode *n4 = rn.create_node (pex::RNode::VertexPort, 4); + + rn.create_element (1, n1, n2); + rn.create_element (pex::RElement::short_value (), n2, n3); + rn.create_element (1, n3, n4); + + EXPECT_EQ (rn.to_string (), + "R V1 $2 1\n" + "R $2 $3 0\n" + "R $3 V4 1" + ); + + rn.simplify (); + + EXPECT_EQ (rn.to_string (), + "R V1 V4 2" + ); +} + +TEST(network_simplify4) +{ + pex::RNetwork rn; + EXPECT_EQ (rn.to_string (), ""); + + pex::RNode *n1 = rn.create_node (pex::RNode::VertexPort, 1); + pex::RNode *n2 = rn.create_node (pex::RNode::Internal, 2); + pex::RNode *n3 = rn.create_node (pex::RNode::Internal, 3); + pex::RNode *n4 = rn.create_node (pex::RNode::VertexPort, 4); + + rn.create_element (1, n1, n4); + rn.create_element (1, n2, n1); + rn.create_element (1, n4, n3); + + EXPECT_EQ (rn.to_string (), + "R V1 V4 1\n" + "R $2 V1 1\n" + "R V4 $3 1" + ); + + rn.simplify (); + + EXPECT_EQ (rn.to_string (), + "R V1 V4 1" + ); +}