Qucs-core  0.0.19
nodelist.cpp
Go to the documentation of this file.
00001 /*
00002  * nodelist.cpp - node list class implementation
00003  *
00004  * Copyright (C) 2003, 2004, 2006, 2008 Stefan Jahn <stefan@lkcc.org>
00005  *
00006  * This is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2, or (at your option)
00009  * any later version.
00010  *
00011  * This software is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this package; see the file COPYING.  If not, write to
00018  * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
00019  * Boston, MA 02110-1301, USA.
00020  *
00021  * $Id$
00022  *
00023  */
00024 
00025 #if HAVE_CONFIG_H
00026 # include <config.h>
00027 #endif
00028 
00029 #include <algorithm>
00030 #include <cassert>
00031 
00032 #include "logging.h"
00033 #include "object.h"
00034 #include "node.h"
00035 #include "complex.h"
00036 #include "circuit.h"
00037 #include "net.h"
00038 #include "nodelist.h"
00039 
00040 namespace qucs {
00041 
00042 
00043 
00044 /* The function creates a nodelist for the given netlist.  The
00045    nodelist is based on the circuit list and consists of unique nodes
00046    inside the circuit list only.  Each node in the list has references
00047    to their actual circuit nodes and thereby to the circuits it is
00048    connected to. */
00049 nodelist::nodelist (net * subnet) {
00050   sorting = 0;
00051 
00052   circuit * c;
00053   // go through circuit list and find unique nodes
00054   for (c = subnet->getRoot (); c != NULL; c = (circuit *) c->getNext ()) {
00055     for (int i = 0; i < c->getSize (); i++) {
00056       node * n = c->getNode (i);
00057       if (contains (n->getName ()) == 0) {
00058         root.push_front(new nodelist_t(n->getName (), n->getInternal ()));;
00059       }
00060     }
00061   }
00062   // add circuit nodes to each unique node in the list
00063   for (auto &n : this->root) {
00064     for (c = subnet->getRoot (); c != NULL; c = (circuit *) c->getNext ()) {
00065       for (int i = 0; i < c->getSize (); i++) {
00066         assert (c->getNode(i)->getName () != NULL);
00067         if (n->name == c->getNode(i)->getName ()) {
00068           addCircuitNode(n, c->getNode (i));
00069         }
00070       }
00071     }
00072   }
00073 }
00074 
00075 // Destructor deletes an instance of the nodelist class.
00076 nodelist::~nodelist () {
00077   for (auto &n: root) {
00078     delete n;
00079   }
00080 }
00081 
00082 
00083 // This function counts the node names in the list.
00084 int nodelist::length (void) const {
00085   return root.size();
00086 }
00087 
00088 // This function finds the specified node name in the list.
00089 bool nodelist::contains (const std::string &str) const {
00090   return std::find_if(root.begin(),root.end(),[str](nodelist_t *n) { return n->name == str; }) != root.end();
00091 }
00092 
00093 // Returns the node number of the given node name.
00094 int nodelist::getNodeNr (const std::string &str) const {
00095   
00096   if(sorting) {
00097     auto it = std::find_if(narray.begin(),narray.end(),[str](nodelist_t *n) { return n->name == str; });
00098     if(it == narray.end())
00099       return -1;
00100     return (*it)->n;
00101   }
00102   auto it = std::find_if(root.begin(),root.end(),[str](nodelist_t *n) { return n->name == str; });
00103   if(it == root.end())
00104     return -1;
00105   return (*it)->n;
00106 }
00107 
00108 /* This function returns the node name positioned at the specified
00109    location in the node name list. */
00110 std::string nodelist::get (int nr) const {
00111   return narray[nr + 1]->name;
00112 }
00113 
00114 /* This function returns non-zero if the node positioned at the
00115    specified location in the node name list is marked internal and
00116    zero otherwise. */
00117 bool nodelist::isInternal (int nr) const {
00118   return narray[nr + 1]->internal;
00119 }
00120 
00121 /* The function returns the nodelist structure with the given name in
00122    the node name list.  It returns NULL if there is no such node. */
00123 struct nodelist_t * nodelist::getNode (const std::string &str) const {
00124   auto it = std::find_if(root.begin(),root.end(),[str](nodelist_t *n) { return n->name == str; });
00125   if(it != root.end())
00126     return *it;
00127   return nullptr;
00128 }
00129 
00130 /* Returns a comma separated list of the circuits connected to the
00131    node specified by the given number. */
00132 std::string nodelist::getNodeString (int nr) const {
00133   std::string txt;
00134   // find the specified node
00135   struct nodelist_t * n = getNode (nr);
00136   // append circuit names connected to the node
00137   std::size_t i=0;
00138   for (auto &currentn: *n) {
00139     const std::string str = currentn->getCircuit()->getName ();
00140     txt+=str;
00141     if (i != n->size() - 1)
00142       txt+=",";
00143     ++i;
00144   }
00145   return txt;
00146 }
00147 
00148 
00149 // This function enumerates the nodes in the node name list.
00150 void nodelist::assignNodes (void) {
00151   int i = 1;
00152 
00153   // create fast array access possibility
00154   narray.clear();
00155   narray.reserve(this->length());
00156 
00157   for (auto n: root) {
00158     // ground node gets a zero counter
00159     if (n->name=="gnd") {
00160       n->n = 0;
00161       narray[0] = n;
00162     }
00163     // others get a unique number greater than zero
00164     else {
00165       narray[i] = n;
00166       n->n = i++;
00167     }
00168   }
00169 }
00170 
00171 /* The function appends a node pointer to the given nodelist
00172    structure. */
00173 void nodelist::addCircuitNode (struct nodelist_t * nl, node * n) {
00174   (*nl).push_back(n);
00175   if (n->getInternal ()) nl->internal = n->getInternal ();
00176 }
00177 
00178 
00179 /* This function is used as sorting criteria for the S-parameter
00180    analysis.  It returns the number of nodes a join of the two
00181    circuits connected to the given node would yield. */
00182 static int sortfunc (struct nodelist_t * n) {
00183   int p;
00184   circuit * c1 = (*n)[0]->getCircuit ();
00185   circuit * c2 = (*n).size() > 1 ? (*n)[1]->getCircuit () : nullptr;
00186   if (c1->getPort () || (c2 && c2->getPort ())) return -1;
00187   if (c1 == c2) { // interconnect
00188     p = c1->getSize () - 2;
00189   } else {        // connect
00190     p = c1->getSize () + (c2 ? c2->getSize () - 2 : 0);
00191   }
00192   return p;
00193 }
00194 
00195 /* The function evaluates the sorting criteria of the given two nodes.
00196    It returns non-zero if 'n1' should be inserted before 'n2'. */
00197 static int insfunc (struct nodelist_t * n1, struct nodelist_t * n2) {
00198   int p1 = sortfunc (n1);
00199   int p2 = sortfunc (n2);
00200   return p1 >= 0 && (p1 <= p2 || p2 < 0);
00201 }
00202 
00203 /* The function inserts the given node structure into the node list.
00204    If the nodelist is sorted then the node gets inserted at a certain
00205    position. */
00206 void nodelist::insert (struct nodelist_t * n) {
00207   // first node at all
00208   if (root.empty()) {
00209     root.push_front(n);
00210     return;
00211   }
00212 
00213   // sorted node list
00214   if (sorting) {
00215     int added = 0;
00216     for (auto it = root.begin();it != root.end();it++) {
00217       if (insfunc (n, *it)) {
00218         root.insert(it,n);
00219         added++;
00220         break;
00221       }
00222     }
00223     if (!added)
00224       root.push_back (n);
00225     return;
00226   }
00227 
00228   // unsorted node list
00229   root.push_front(n);
00230 }
00231 
00232 /* This function removes the nodes associated with the given circuits
00233    from the node list.  If the node list is sorted then the order gets
00234    rearranged properly. */
00235 void nodelist::remove (circuit * c) {
00236   // go through each node of the circuit
00237   for (int i = 0; i < c->getSize (); i++) {
00238     node * n = c->getNode (i);
00239     struct nodelist_t * nl;
00240     if ((nl = this->getNode (n->getName ())) != NULL) {
00241       // remove node from node structure
00242       nl->erase(std::remove(nl->begin(), nl->end(), n), nl->end());
00243       if (nl->empty()) {
00244         // completely remove the node structure
00245         root.erase(std::remove(root.begin(), root.end(), nl), root.end());
00246         delete nl;
00247       }
00248       else if (sorting && sortfunc (nl) > 0) {
00249         // rearrange sorting
00250         root.erase(std::remove(root.begin(), root.end(), nl), root.end());
00251         insert (nl);
00252       }
00253     }
00254   }
00255 }
00256 
00257 /* The following function can be used to insert a new circuit to the
00258    node list.  It goes through each node of the circuit and rearranges
00259    the node list appropriately. */
00260 void nodelist::insert (circuit * c) {
00261   // go through each node of the circuit
00262   for (int i = 0; i < c->getSize (); i++) {
00263     struct nodelist_t * nl;
00264     node * n = c->getNode (i);
00265     // is this node already in the nodelist?
00266     if (contains (n->getName ()) == 0) {
00267       // no, create new node and put it into the list
00268       nl = new nodelist_t(n->getName (), n->getInternal ());
00269       addCircuitNode (nl, n);
00270       if (sorting) {
00271         if (c->getPort ())
00272           root.push_back (nl);
00273         else
00274           insert (nl);
00275       }
00276       else root.push_front (nl);
00277     }
00278     else {
00279       // yes, put additional node into nodelist structure
00280       if ((nl = getNode (n->getName ())) != NULL) {
00281         addCircuitNode (nl, n);
00282         if (sorting && sortfunc (nl) > 0) {
00283           // rearrange sorting
00284           root.erase(std::remove(root.begin(), root.end(), nl), root.end());
00285           insert (nl);
00286         }
00287       }
00288     }
00289   }
00290 }
00291 
00292 /* The function completely rebuilds the nodelist.  Once sort()'ed it
00293    keeps being sorted when removing or inserting new circuits. */
00294 void nodelist::sort (void) {
00295   nodelist * nodes = new nodelist ();
00296   struct nodelist_t * cand;
00297   int i, ports, MaxPorts, len = length ();
00298 
00299   // go through the list until there is no node left
00300   for (i = 0; i < len; i++) {
00301     // find last order node
00302     cand = NULL;
00303     auto nl =  root.begin();
00304     for (MaxPorts = -1, nl = root.begin(); nl != root.end(); nl++) {
00305       ports = sortfunc (*nl);
00306       if (ports > MaxPorts || MaxPorts < 0 || ports == -1) {
00307         cand = *nl;
00308         MaxPorts = ports;
00309       }
00310       if (ports == -1) break;
00311     }
00312     // add last order node
00313     root.erase(std::remove(root.begin(), root.end(), cand), root.end());
00314     nodes->root.push_front (cand);
00315   }
00316 
00317   // store sorted node list in current object
00318   root = nodes->root;
00319   sorting = 1;
00320 
00321   // delete temporary node list: UGLY todo proper lifetime
00322   nodes->root.clear();
00323   delete nodes;
00324 }
00325 
00326 // The function returns the first two nodes of the sorted list.
00327 void nodelist::sortedNodes (node ** node1, node ** node2) {
00328   assert ((*root.begin())->size() == 2);
00329   *node1 = (**(root.begin()))[0];
00330   *node2 = (**(root.begin()))[1];
00331 }
00332 
00333 #if DEBUG
00334 // Debug function: Prints the entire nodelist.
00335 void nodelist::print (void) const {
00336   for (auto n: root) {
00337     logprint (LOG_STATUS, "DEBUG: node %s-%d [", n->name.c_str(), n->n);
00338     std::size_t i=0;
00339     for (const auto &currentnode : *n) {
00340       logprint (LOG_STATUS, "%s", currentnode->getCircuit()->getName ());
00341       if (i != n->size() - 1) logprint (LOG_STATUS, ",");
00342       ++i;
00343     }
00344     logprint (LOG_STATUS, "]\n");
00345   }
00346 }
00347 #endif /* DEBUG */
00348 
00349 } // namespace qucs