* nodelist.cpp - node list class implementation
*
* Copyright (C) 2003, 2004, 2006, 2008 Stefan Jahn <stefan@lkcc.org>
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this package; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
* Boston, MA 02110-1301, USA.
*
* $Id$
*
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include <algorithm>
#include <cassert>
#include "logging.h"
#include "object.h"
#include "node.h"
#include "complex.h"
#include "circuit.h"
#include "net.h"
#include "nodelist.h"
namespace qucs {
nodelist is based on the circuit list and consists of unique nodes
inside the circuit list only. Each node in the list has references
to their actual circuit nodes and thereby to the circuits it is
connected to. */
nodelist::nodelist (net * subnet) {
sorting = 0;
circuit * c;
for (c = subnet->getRoot (); c != NULL; c = (circuit *) c->getNext ()) {
for (int i = 0; i < c->getSize (); i++) {
node * n = c->getNode (i);
if (contains (n->getName ()) == 0) {
root.push_front(new nodelist_t(n->getName (), n->getInternal ()));;
}
}
}
for (auto &n : this->root) {
for (c = subnet->getRoot (); c != NULL; c = (circuit *) c->getNext ()) {
for (int i = 0; i < c->getSize (); i++) {
assert (c->getNode(i)->getName () != NULL);
if (n->name == c->getNode(i)->getName ()) {
addCircuitNode(n, c->getNode (i));
}
}
}
}
}
nodelist::~nodelist () {
for (auto &n: root) {
delete n;
}
}
int nodelist::length (void) const {
return root.size();
}
bool nodelist::contains (const std::string &str) const {
return std::find_if(root.begin(),root.end(),[str](nodelist_t *n) { return n->name == str; }) != root.end();
}
int nodelist::getNodeNr (const std::string &str) const {
if(sorting) {
auto it = std::find_if(narray.begin(),narray.end(),[str](nodelist_t *n) { return n->name == str; });
if(it == narray.end())
return -1;
return (*it)->n;
}
auto it = std::find_if(root.begin(),root.end(),[str](nodelist_t *n) { return n->name == str; });
if(it == root.end())
return -1;
return (*it)->n;
}
location in the node name list. */
std::string nodelist::get (int nr) const {
return narray[nr + 1]->name;
}
specified location in the node name list is marked internal and
zero otherwise. */
bool nodelist::isInternal (int nr) const {
return narray[nr + 1]->internal;
}
the node name list. It returns NULL if there is no such node. */
struct nodelist_t * nodelist::getNode (const std::string &str) const {
auto it = std::find_if(root.begin(),root.end(),[str](nodelist_t *n) { return n->name == str; });
if(it != root.end())
return *it;
return nullptr;
}
node specified by the given number. */
std::string nodelist::getNodeString (int nr) const {
std::string txt;
struct nodelist_t * n = getNode (nr);
std::size_t i=0;
for (auto ¤tn: *n) {
const std::string str = currentn->getCircuit()->getName ();
txt+=str;
if (i != n->size() - 1)
txt+=",";
++i;
}
return txt;
}
void nodelist::assignNodes (void) {
int i = 1;
narray.clear();
narray.reserve(this->length());
narray.resize(1);
for (auto n: root) {
if (n->name=="gnd") {
n->n = 0;
narray[0] = n;
}
else {
narray.resize(i+1);
narray[i] = n;
n->n = i++;
}
}
}
structure. */
void nodelist::addCircuitNode (struct nodelist_t * nl, node * n) {
(*nl).push_back(n);
if (n->getInternal ()) nl->internal = n->getInternal ();
}
analysis. It returns the number of nodes a join of the two
circuits connected to the given node would yield. */
static int sortfunc (struct nodelist_t * n) {
int p;
circuit * c1 = (*n)[0]->getCircuit ();
circuit * c2 = (*n).size() > 1 ? (*n)[1]->getCircuit () : nullptr;
if (c1->getPort () || (c2 && c2->getPort ())) return -1;
if (c1 == c2) {
p = c1->getSize () - 2;
} else {
p = c1->getSize () + (c2 ? c2->getSize () - 2 : 0);
}
return p;
}
It returns non-zero if 'n1' should be inserted before 'n2'. */
static int insfunc (struct nodelist_t * n1, struct nodelist_t * n2) {
int p1 = sortfunc (n1);
int p2 = sortfunc (n2);
return p1 >= 0 && (p1 <= p2 || p2 < 0);
}
If the nodelist is sorted then the node gets inserted at a certain
position. */
void nodelist::insert (struct nodelist_t * n) {
if (root.empty()) {
root.push_front(n);
return;
}
if (sorting) {
int added = 0;
for (auto it = root.begin();it != root.end();it++) {
if (insfunc (n, *it)) {
root.insert(it,n);
added++;
break;
}
}
if (!added)
root.push_back (n);
return;
}
root.push_front(n);
}
from the node list. If the node list is sorted then the order gets
rearranged properly. */
void nodelist::remove (circuit * c) {
for (int i = 0; i < c->getSize (); i++) {
node * n = c->getNode (i);
struct nodelist_t * nl;
if ((nl = this->getNode (n->getName ())) != NULL) {
nl->erase(std::remove(nl->begin(), nl->end(), n), nl->end());
if (nl->empty()) {
root.erase(std::remove(root.begin(), root.end(), nl), root.end());
delete nl;
}
else if (sorting && sortfunc (nl) > 0) {
root.erase(std::remove(root.begin(), root.end(), nl), root.end());
insert (nl);
}
}
}
}
node list. It goes through each node of the circuit and rearranges
the node list appropriately. */
void nodelist::insert (circuit * c) {
for (int i = 0; i < c->getSize (); i++) {
struct nodelist_t * nl;
node * n = c->getNode (i);
if (contains (n->getName ()) == 0) {
nl = new nodelist_t(n->getName (), n->getInternal ());
addCircuitNode (nl, n);
if (sorting) {
if (c->getPort ())
root.push_back (nl);
else
insert (nl);
}
else root.push_front (nl);
}
else {
if ((nl = getNode (n->getName ())) != NULL) {
addCircuitNode (nl, n);
if (sorting && sortfunc (nl) > 0) {
root.erase(std::remove(root.begin(), root.end(), nl), root.end());
insert (nl);
}
}
}
}
}
keeps being sorted when removing or inserting new circuits. */
void nodelist::sort (void) {
nodelist * nodes = new nodelist ();
struct nodelist_t * cand;
int i, ports, MaxPorts, len = length ();
for (i = 0; i < len; i++) {
cand = NULL;
auto nl = root.begin();
for (MaxPorts = -1, nl = root.begin(); nl != root.end(); nl++) {
ports = sortfunc (*nl);
if (ports > MaxPorts || MaxPorts < 0 || ports == -1) {
cand = *nl;
MaxPorts = ports;
}
if (ports == -1) break;
}
root.erase(std::remove(root.begin(), root.end(), cand), root.end());
nodes->root.push_front (cand);
}
root = nodes->root;
sorting = 1;
nodes->root.clear();
delete nodes;
}
void nodelist::sortedNodes (node ** node1, node ** node2) {
assert ((*root.begin())->size() == 2);
*node1 = (**(root.begin()))[0];
*node2 = (**(root.begin()))[1];
}
#if DEBUG
void nodelist::print (void) const {
for (auto n: root) {
logprint (LOG_STATUS, "DEBUG: node %s-%d [", n->name.c_str(), n->n);
std::size_t i=0;
for (const auto ¤tnode : *n) {
logprint (LOG_STATUS, "%s", currentnode->getCircuit()->getName ());
if (i != n->size() - 1) logprint (LOG_STATUS, ",");
++i;
}
logprint (LOG_STATUS, "]\n");
}
}
#endif
}