R network simplify

This commit is contained in:
Matthias Koefferlein 2025-04-19 23:48:58 +02:00
parent 1379d30502
commit fcd42bd0f1
5 changed files with 242 additions and 10 deletions

View File

@ -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<std::pair<RNode *, RNode *>, RElement *> m_elements_by_nodes;
std::map<std::pair<RNode::node_type, unsigned int>, 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<RNode *> ((*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<const RNode *> 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<RNode *> ((*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<RNode *> ((*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<RNode *> 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<RNode *> ((*e)->other (n.operator-> ()));
double r1 = (*e)->resistance ();
++e;
RNode *n2 = const_cast<RNode *> ((*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 ()

View File

@ -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<double>::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);
};

View File

@ -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<db::Coord, pex::RNode *> 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;

View File

@ -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;
};

View File

@ -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"
);
}