WIP: first algorithm - is capable of deriving the 'resistor cube' symmetry.

This commit is contained in:
Matthias Koefferlein 2020-02-26 00:20:18 +01:00
parent 58de38739a
commit 08af8d85c4
3 changed files with 189 additions and 0 deletions

View File

@ -3626,4 +3626,136 @@ NetlistComparer::do_subcircuit_assignment (const db::Circuit *c1, const db::NetG
}
}
// @@@
bool derive_symmetry_groups (const db::NetGraph &graph, const tl::equivalence_clusters<const NetGraphNode *> &identical_nodes, std::set<size_t> &considered_nodes, const std::set<size_t> &symmetry_group, std::list<std::set<size_t> > &symmetry_groups)
{
std::set<size_t> cids;
std::set<size_t> new_symmetry_group;
NetGraphNode::edge_type::first_type edge;
bool has_candidate = true;
for (std::set<size_t>::const_iterator g = symmetry_group.begin (); g != symmetry_group.end (); ++g) {
const NetGraphNode &n = graph.node (*g);
for (NetGraphNode::edge_iterator e = n.begin (); e != n.end () && has_candidate; ++e) {
if (considered_nodes.find (e->second.first) != considered_nodes.end ()) {
continue;
}
const NetGraphNode *other = &graph.node (e->second.first);
if (identical_nodes.has_attribute (other)) {
if (cids.empty ()) {
edge = e->first;
} else if (edge != e->first) {
has_candidate = false;
}
if (has_candidate) {
cids.insert (identical_nodes.cluster_id (other));
if (cids.size () > 1) {
has_candidate = false;
} else {
new_symmetry_group.insert (e->second.first);
}
}
}
}
}
if (has_candidate && ! cids.empty () && new_symmetry_group.size () > 1) {
considered_nodes.insert (new_symmetry_group.begin (), new_symmetry_group.end ());
if (derive_symmetry_groups (graph, identical_nodes, considered_nodes, new_symmetry_group, symmetry_groups)) {
symmetry_groups.push_back (new_symmetry_group);
} else {
std::set<size_t> cn;
std::set_difference (considered_nodes.begin (), considered_nodes.end (), new_symmetry_group.begin (), new_symmetry_group.end (), std::inserter (cn, cn.begin ()));
considered_nodes.swap (cn);
has_candidate = false;
}
}
return has_candidate;
}
void join_symmetric_nodes (db::Circuit *circuit)
{
db::CircuitCategorizer circuit_categorizer;
db::DeviceCategorizer device_categorizer;
db::CircuitPinMapper circuit_pin_mapper;
db::DeviceFilter device_filter (0.0, 0.0);
std::map<const db::Circuit *, CircuitMapper> circuit_and_pin_mapping;
db::NetGraph graph;
graph.build (circuit, device_categorizer, circuit_categorizer, device_filter, &circuit_and_pin_mapping, &circuit_pin_mapper);
// sort the nodes so we can easily identify the identical ones (in terms of topology)
// nodes are identical if the attached devices and circuits are of the same kind and with the same parameters
// and connect to other nodes in identical configurations.
std::vector<const NetGraphNode *> nodes;
nodes.reserve (graph.end () - graph.begin ());
for (db::NetGraph::node_iterator i = graph.begin (); i != graph.end (); ++i) {
if (! i->has_other () && i->net ()) {
nodes.push_back (i.operator-> ());
}
}
std::sort (nodes.begin (), nodes.end (), CompareNodePtr ());
// Identical nodes leading to the same nodes on the other side are candidates for symmetry.
tl::equivalence_clusters<const NetGraphNode *> identical_nodes;
for (std::vector<const NetGraphNode *>::const_iterator np = nodes.begin (); np + 1 != nodes.end (); ++np) {
if (*np[0] == *np[1]) {
identical_nodes.same (np[0], np[1]);
}
}
std::list<std::set<size_t> > symmetry_groups;
std::set<size_t> considered_nodes;
for (std::vector<const NetGraphNode *>::const_iterator np = nodes.begin (); np != nodes.end (); ++np) {
size_t node_id = graph.node_index_for_net (np[0]->net ());
if (considered_nodes.find (node_id) != considered_nodes.end ()) {
continue;
}
considered_nodes.insert (node_id);
std::set<size_t> symmetry_group;
symmetry_group.insert (node_id);
derive_symmetry_groups (graph, identical_nodes, considered_nodes, symmetry_group, symmetry_groups);
}
printf("@@@ symmetry groups:\n");
for (std::list<std::set<size_t> >::const_iterator g = symmetry_groups.begin (); g != symmetry_groups.end (); ++g) {
printf("@@@ group:\n");
for (std::set<size_t>::const_iterator i = g->begin (); i != g->end (); ++i) {
printf("@@@ %s\n", graph.node (*i).net () ? graph.node (*i).net ()->expanded_name ().c_str () : "(null)");
}
}
fflush(stdout);
}
// @@@
}

View File

@ -328,6 +328,9 @@ protected:
bool m_dont_consider_net_names;
};
// @@@
void DB_PUBLIC join_symmetric_nodes (db::Circuit *circuit);
}
namespace tl

View File

@ -3703,3 +3703,57 @@ TEST(24_NodesRemovedButConnectedInOther)
);
EXPECT_EQ (good, true);
}
TEST(25_SplitGates)
{
const char *nls1 =
"circuit NAND2 (A=A,B=B,OUT=OUT,VSS=VSS,VDD=VDD);\n"
" device PMOS $1 (S=OUT,G=A,D=VDD) (L=0.25,W=1);\n"
" device PMOS $2 (S=VDD,G=B,D=OUT) (L=0.25,W=1);\n"
// NOTE: $1 and $2 are separate nets, but can be joined due to symmetry
" device NMOS $3 (S=$1,G=A,D=OUT) (L=0.25,W=1);\n"
" device NMOS $4 (S=$2,G=A,D=OUT) (L=0.25,W=1);\n"
" device NMOS $5 (S=$1,G=B,D=VSS) (L=0.25,W=1);\n"
" device NMOS $6 (S=$2,G=B,D=VSS) (L=0.25,W=1);\n"
"end;\n";
nls1 =
"circuit NAND2 (A=A,B=B);\n"
" device RES $1 (A=A,B=$1) (R=1000);\n"
" device RES $2 (A=A,B=$2) (R=1000);\n"
" device RES $3 (A=A,B=$3) (R=1000);\n"
" device RES $4 (A=$1,B=$4) (R=1000);\n"
" device RES $5 (A=$2,B=$4) (R=1000);\n"
" device RES $6 (A=$2,B=$5) (R=1000);\n"
" device RES $7 (A=$3,B=$5) (R=1000);\n"
" device RES $8 (A=$3,B=$6) (R=1000);\n"
" device RES $9 (A=$1,B=$6) (R=1000);\n"
" device RES $9 (A=$4,B=B) (R=1000);\n"
" device RES $10 (A=$5,B=B) (R=1000);\n"
" device RES $11 (A=$6,B=B) (R=1000);\n"
"end;\n";
const char *nls2 =
"circuit NAND2 (A=A,B=B,OUT=OUT,VSS=VSS,VDD=VDD);\n"
" device PMOS $1 (S=OUT,G=A,D=VDD) (L=0.25,W=1);\n"
" device PMOS $2 (S=VDD,G=B,D=OUT) (L=0.25,W=1);\n"
" device NMOS $3 (S=$1,G=A,D=OUT) (L=0.25,W=2);\n"
" device NMOS $4 (S=$1,G=B,D=VSS) (L=0.25,W=2);\n"
"end;\n";
db::Netlist nl1, nl2;
prep_nl (nl1, nls1);
prep_nl (nl2, nls2);
db::join_symmetric_nodes (nl1.circuit_by_name ("NAND2")); // @@@
#if 0
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
bool good = comp.compare (&nl1, &nl2);
std::string txt = logger.text ();
printf("@@@\n%s", txt.c_str()); fflush(stdout); // @@@
#endif
}