mirror of https://github.com/KLayout/klayout.git
R network simplify
This commit is contained in:
parent
1379d30502
commit
fcd42bd0f1
|
|
@ -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 ()
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue