* equation.cpp - checker for the Qucs equations
*
* Copyright (C) 2004-2009 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cmath>
#include <ctype.h>
#include "logging.h"
#include "complex.h"
#include "object.h"
#include "vector.h"
#include "matrix.h"
#include "matvec.h"
#include "dataset.h"
#include "strlist.h"
#include "netdefs.h"
#include "equation.h"
#include "evaluate.h"
#include "differentiate.h"
#include "constants.h"
#include "range.h"
#include "exception.h"
#include "exceptionstack.h"
namespace qucs
{
using namespace eqn;
#define A(a) ((assignment *) (a))
#define N(n) ((node *) (n))
#define C(c) ((constant *) (c))
#define R(r) ((reference *) (r))
constant::constant () : node (CONSTANT)
{
type = TAG_UNKNOWN;
dataref = false;
d = 0.0;
setType (type);
}
constant::constant (int tag) : node (CONSTANT)
{
type = tag;
dataref = false;
d = 0.0;
setType (type);
}
based on the given constant. */
constant::constant (const constant & o) : node (o)
{
type = o.type;
dataref = o.dataref;
d = 0.0;
setType (type);
switch (type)
{
case TAG_BOOLEAN:
b = o.b;
break;
case TAG_DOUBLE:
d = o.d;
break;
case TAG_COMPLEX:
c = dataref ? o.c : new nr_complex_t (*o.c);
break;
case TAG_VECTOR:
v = dataref ? o.v : new qucs::vector (*o.v);
break;
case TAG_MATRIX:
m = dataref ? o.m : new matrix (*o.m);
break;
case TAG_MATVEC:
mv = dataref ? o.mv : new matvec (*o.mv);
break;
case TAG_STRING:
s = dataref ? o.s : strdup (s);
break;
case TAG_CHAR:
chr = o.chr;
break;
case TAG_RANGE:
r = dataref ? o.r : new range (*o.r);
break;
}
}
node * constant::recreate (void)
{
return new constant (*this);
}
constant::~constant ()
{
if (!dataref)
{
switch (type)
{
case TAG_COMPLEX:
delete c;
break;
case TAG_VECTOR:
delete v;
break;
case TAG_MATRIX:
delete m;
break;
case TAG_MATVEC:
delete mv;
break;
case TAG_STRING:
free (s);
break;
case TAG_RANGE:
delete r;
break;
}
}
}
representation of the object. */
void constant::print (void)
{
logprint (LOG_STATUS, "%s", toString ());
}
static char * Cplx2String (nr_complex_t c)
{
static char str[256];
if (imag (c) == 0.0)
{
sprintf (str, "%g", (double) real (c));
}
else
{
sprintf (str, "(%g%cj%g)", (double ) real (c),
imag (c) >= 0.0 ? '+' : '-', (double) fabs (imag (c)));
}
return str;
}
of constant. */
char * constant::toString (void)
{
char str[256];
free (txt);
switch (type)
{
case TAG_BOOLEAN:
sprintf (str, "%d", b ? 1 : 0);
txt = strdup (str);
break;
case TAG_DOUBLE:
sprintf (str, "%g", (double) d);
txt = strdup (str);
break;
case TAG_COMPLEX:
txt = strdup (Cplx2String (*c));
break;
case TAG_VECTOR:
{
int pos = 1, len = 3 + v->getSize () - 1;
txt = (char *) malloc (len);
strcpy (txt, "[");
for (int i = 0; i < v->getSize (); i++)
{
char * s = Cplx2String (v->get (i));
txt = (char *) realloc (txt, len += strlen (s));
strcpy (&txt[pos], s);
pos += strlen (s);
if (i != v->getSize () - 1) strcpy (&txt[pos++], ";");
}
strcpy (&txt[pos], "]");
}
break;
case TAG_MATRIX:
{
int len = 3 + (m->getRows () - 1) * m->getCols () + (m->getCols () - 1);
txt = (char *) malloc (len);
strcpy (txt, "[");
for (int r = 0; r < m->getRows (); r++)
{
for (int c = 0; c < m->getCols (); c++)
{
char * s = Cplx2String (m->get (r, c));
txt = (char *) realloc (txt, len += strlen (s));
strcat (txt, s);
if (c != m->getCols () - 1) strcat (txt, ",");
}
if (r != m->getRows () - 1) strcat (txt, ";");
}
strcat (txt, "]");
}
break;
case TAG_MATVEC:
sprintf (str, "[%dx%d](%d)",
mv->getRows (), mv->getCols (), mv->getSize ());
txt = strdup (str);
break;
case TAG_CHAR:
sprintf (str, "'%c'", chr);
txt = strdup (str);
break;
case TAG_STRING:
sprintf (str, "'%s'", s);
txt = strdup (str);
break;
case TAG_RANGE:
txt = strdup (r->toString ());
break;
default:
txt = strdup ("(no such type)");
break;
}
return txt;
}
int constant::evalType (void)
{
return getType ();
}
constant * constant::evaluate (void)
{
setResult (this);
return getResult ();
}
node * constant::differentiate (char *)
{
constant * res = new constant (TAG_DOUBLE);
res->d = 0;
return res;
}
reference::reference () : node (REFERENCE)
{
n = NULL;
ref = NULL;
}
based on the given reference. */
reference::reference (const reference & o) : node (o)
{
n = o.n ? strdup (o.n) : NULL;
ref = o.ref;
}
node * reference::recreate (void)
{
return new reference (*this);
}
void reference::replace (char * src, char * dst)
{
if (!strcmp (src, n))
{
free (n);
n = dst ? strdup (dst) : NULL;
}
}
reference::~reference ()
{
free (n);
}
void reference::print (void)
{
logprint (LOG_STATUS, "%s", toString ());
}
char * reference::toString (void)
{
free (txt);
txt = strdup (n);
return txt;
}
void reference::addDependencies (strlist * depends)
{
depends->add (n);
findVariable ();
}
void reference::findVariable (void)
{
ref = NULL;
if (!ref)
{
node * eqn;
if (checkee != NULL)
{
for (eqn = checkee->getEquations (); eqn; eqn = eqn->getNext ())
{
if (!strcmp (n, A(eqn)->result))
{
ref = eqn;
break;
}
}
}
if (solvee != NULL && !ref)
{
for (eqn = solvee->getEquations (); eqn; eqn = eqn->getNext ())
{
if (!strcmp (n, A(eqn)->result))
{
ref = eqn;
break;
}
}
}
}
}
int reference::evalType (void)
{
setType (TAG_UNKNOWN);
findVariable ();
if (ref != NULL)
{
setType (A(ref)->body->evalType ());
}
return getType ();
}
constant * reference::evaluate (void)
{
setResult (NULL);
findVariable ();
if (ref != NULL)
{
setResult (A(ref)->body->getResult ());
}
return getResult ();
}
node * reference::differentiate (char * derivative)
{
constant * res = new constant (TAG_DOUBLE);
if (n != NULL && !strcmp (n, derivative))
res->d = 1;
else
res->d = 0;
return res;
}
assignment::assignment () : node (ASSIGNMENT)
{
body = NULL;
result = NULL;
}
based on the given assignment. */
assignment::assignment (const assignment & o) : node (o)
{
body = o.body->recreate ();
result = o.result ? strdup (o.result) : NULL;
}
node * assignment::recreate (void)
{
return new assignment (*this);
}
void assignment::replace (char * src, char * dst)
{
body->replace (src, dst);
}
void assignment::rename (char * n)
{
free (result);
result = n ? strdup (n) : NULL;
}
assignment::~assignment ()
{
delete body;
free (result);
}
void assignment::print (void)
{
logprint (LOG_STATUS, "%s", toString ());
}
char * assignment::toString (void)
{
free (txt);
char * str = body->toString ();
txt = (char *) malloc (strlen (result) + strlen (str) + 4);
sprintf (txt, "%s = %s", result, str);
return txt;
}
void assignment::addDependencies (strlist * depends)
{
body->checkee = checkee;
body->addDependencies (depends);
}
int assignment::evalType (void)
{
setType (body->evalType ());
return getType ();
}
constant * assignment::evaluate (void)
{
body->solvee = solvee;
setResult (body->evaluate ());
if (body->getResult()->dropdeps)
{
getResult()->dropdeps = body->getResult()->dropdeps;
strlist * preps = body->getPrepDependencies ();
if (preps) getResult()->setPrepDependencies (new strlist (*preps));
}
return getResult ();
}
node * assignment::differentiate (char * derivative)
{
char * txt = (char *) malloc (strlen (result) + strlen (derivative) + 4);
sprintf (txt, "d%s_d%s", result, derivative);
assignment * res = new assignment ();
res->result = txt;
res->body = body->differentiate (derivative);
return res;
}
#define D(con) (C(con)->d)
#define isConst(n) ((n)->getTag()==CONSTANT && C(n)->getType()==TAG_DOUBLE)
#define isZero(n) (isConst(n) && D(n) == 0.0)
#define isOne(n) (isConst(n) && D(n) == 1.0)
#define defCon(res,val) res = new constant (TAG_DOUBLE); C(res)->d = val;
void assignment::mul (assignment * f)
{
node * factor = f->body->recreate ();
if (isZero (body) || isZero (factor))
{
delete body;
delete factor;
defCon (body, 0);
}
else if (isOne (body))
{
delete body;
body = factor;
}
else if (isOne (factor))
{
delete factor;
}
else
{
application * mul = new application ("*", 2);
mul->args = body;
mul->args->append (factor);
body = mul;
}
}
void assignment::mulref (assignment * f)
{
node * factor = f->body->recreate ();
reference * r = new reference ();
r->n = strdup (f->result);
if (isZero (body) || isZero (factor))
{
delete body;
defCon (body, 0);
}
else if (isOne (body))
{
body = r;
}
else if (isOne (factor))
{
}
else
{
application * mul = new application ("*", 2);
mul->args = body;
mul->args->append (r);
body = mul;
}
}
void assignment::add (assignment * f)
{
node * factor = f->body->recreate ();
if (isZero (body) && isZero (factor))
{
delete body;
delete factor;
defCon (body, 0);
}
else if (isZero (body))
{
delete body;
body = factor;
}
else if (isZero (factor))
{
delete factor;
}
else
{
application * add = new application ("+", 2);
add->args = body;
add->args->append (factor);
body = add;
}
}
application::application () : node (APPLICATION)
{
n = NULL;
nargs = 0;
args = NULL;
eval = NULL;
derive = NULL;
ddx = NULL;
}
given function name and the number of arguments. */
application::application (const char * func, int a) : node (APPLICATION)
{
n = func ? strdup (func) : NULL;
nargs = a;
args = NULL;
eval = NULL;
derive = NULL;
ddx = NULL;
}
based on the given application. */
application::application (const application & o) : node (o)
{
n = o.n ? strdup (o.n) : NULL;
nargs = o.nargs;
if (o.args != NULL)
{
node * arg = o.args;
args = arg->recreate ();
for (arg = arg->getNext (); arg != NULL; arg = arg->getNext ())
{
args->append (arg->recreate ());
}
}
else args = NULL;
eval = o.eval;
derive = o.derive;
ddx = o.ddx ? o.ddx->recreate () : NULL;
}
node * application::recreate (void)
{
return new application (*this);
}
void application::replace (char * src, char * dst)
{
for (node * arg = args; arg != NULL; arg = arg->getNext ())
{
arg->replace (src, dst);
}
if (ddx) ddx->replace (src, dst);
}
application::~application ()
{
node * next;
for (node * arg = args; arg != NULL; arg = next)
{
next = arg->getNext ();
delete arg;
}
delete getResult ();
free (n);
delete ddx;
}
void application::print (void)
{
logprint (LOG_STATUS, "%s", toString ());
}
char * application::toString (void)
{
int nparam = nargs > 0 ? (nargs - 1) : 0;
free (txt);
if ((!strcmp (n, "+") || !strcmp (n, "-") || !strcmp (n, "*") ||
!strcmp (n, "/") || !strcmp (n, "^") || !strcmp (n, "%") ||
!strcmp (n, "<") || !strcmp (n, ">") || !strcmp (n, "<=") ||
!strcmp (n, ">=") || !strcmp (n, "&&") || !strcmp (n, "||") ||
!strcmp (n, "==") || !strcmp (n, "!="))
&& nargs == 2)
{
char * arg1 = args->toString ();
char * arg2 = args->getNext()->toString ();
txt = (char *) malloc (strlen (n) + strlen (arg1) + strlen (arg2) + 3);
sprintf (txt, "(%s%s%s)", arg1, n, arg2);
}
else if (!strcmp (n, "?:"))
{
char * arg1 = args->toString ();
char * arg2 = args->getNext()->toString ();
char * arg3 = args->getNext()->getNext()->toString ();
txt = (char *) malloc (strlen (arg3) + strlen (arg1) + strlen (arg2) + 5);
sprintf (txt, "(%s?%s:%s)", arg1, arg2, arg3);
}
else if (!strcmp (n, "array"))
{
int len = strlen (args->toString ()) + 3 + nparam;
txt = (char *) malloc (len);
sprintf (txt, "%s[", args->toString ());
for (node * arg = args->getNext (); arg != NULL; arg = arg->getNext ())
{
char * str = arg->toString ();
txt = (char *) realloc (txt, len += strlen (str));
strcat (txt, str);
if (arg->getNext ()) strcat (txt, ",");
}
strcat (txt, "]");
}
else if (!strcmp (n, "vector") || !strcmp (n, "matrix"))
{
int len = 3 + nparam;
txt = (char *) malloc (len);
sprintf (txt, "[");
for (node * arg = args; arg != NULL; arg = arg->getNext ())
{
if (arg->getType () == TAG_CHAR)
{
txt = (char *) realloc (txt, len++);
strcat (txt, ";");
}
else
{
char * str = arg->toString ();
txt = (char *) realloc (txt, len += strlen (str));
strcat (txt, str);
node * next = arg->getNext ();
if (next && next->getType () != TAG_CHAR) strcat (txt, ",");
}
}
strcat (txt, "]");
}
else
{
int len = strlen (n) + 3 + nparam;
txt = (char *) malloc (len);
sprintf (txt, "%s(", n);
for (node * arg = args; arg != NULL; arg = arg->getNext ())
{
char * str = arg->toString ();
txt = (char *) realloc (txt, len += strlen (str));
strcat (txt, str);
if (arg->getNext ()) strcat (txt, ",");
}
strcat (txt, ")");
}
return txt;
}
void application::addDependencies (strlist * depends)
{
for (node * arg = args; arg != NULL; arg = arg->getNext ())
{
arg->checkee = checkee;
arg->addDependencies (depends);
}
}
evaluates their return types. */
void application::evalTypeArgs (void)
{
for (node * arg = args; arg != NULL; arg = arg->getNext ())
{
if (arg->getTag () == REFERENCE)
if (checker::isGenerated (R (arg)->n))
continue;
arg->evalType ();
}
}
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-register"
#endif
#include "gperfapphash.cpp"
application. */
char * application::createKey (void)
{
char * key = (char *) calloc (1, strlen (n) + nargs * 3 + 5);
strcat (key, n);
for (node * arg = args; arg != NULL; arg = arg->getNext ())
{
strcat (key, "_");
strcat (key, checker::tag2key (arg->getType ()));
}
return key;
}
gperf-generated hash. */
int application::evalTypeFast (void)
{
char * key = createKey ();
struct appindex * idx = gperfapphash::get (key, strlen (key));
free (key);
if (idx != NULL)
{
application_t * app = &applications[idx->index];
if (app->eval)
{
eval = app->eval;
setType (app->retval);
}
}
return getType ();
}
#define isDDX() (nargs == 2 && !strcmp (n, "ddx") && \
args->getNext()->getTag () == REFERENCE)
evaluation function if any. */
int application::evalType (void)
{
if (isDDX ())
{
args->evalType ();
if (!ddx) ddx = args->differentiate (R(args->getNext())->n);
setType (ddx->evalType ());
return getType ();
}
setType (TAG_UNKNOWN);
evalTypeArgs ();
findDifferentiator ();
if (evalTypeFast () != TAG_UNKNOWN) return getType ();
for (int i = 0; applications[i].application != NULL; i++)
{
application_t * app = &applications[i];
if (!strcmp (n, app->application))
{
int nr = 0;
if (app->nargs >= 0)
{
if (nargs != app->nargs) continue;
for (node * arg = args; arg != NULL; arg = arg->getNext (), nr++)
{
if (arg->getTag () == REFERENCE)
if (checker::isGenerated (R (arg)->n))
continue;
if (!(arg->getType () & app->args[nr]))
{
nr = -1;
break;
}
}
if (nr == -1) continue;
}
if (app->eval == NULL) continue;
eval = app->eval;
setType (app->retval);
break;
}
}
if (getType () == TAG_UNKNOWN)
{
logprint (LOG_ERROR, "checker error, no appropriate function for `%s'"
" found\n", toString ());
}
return getType ();
}
function could be found and otherwise non-zero. */
int application::findDifferentiator (void)
{
for (int i = 0; differentiations[i].application != NULL; i++)
{
if (!strcmp (n, differentiations[i].application) &&
nargs == differentiations[i].nargs)
{
derive = differentiations[i].derive;
return 0;
}
}
return -1;
}
the result. */
constant * application::evaluate (void)
{
if (isDDX ())
{
delete getResult ();
setResult (C (ddx->evaluate()->recreate ()));
return getResult ();
}
int errors = 0;
strlist * apreps = new strlist ();
for (node * arg = args; arg != NULL; arg = arg->getNext ())
{
if (arg->evaluated == 0 || 1)
{
arg->solvee = solvee;
arg->evaluate ();
if (arg->getResult () == NULL)
{
if (arg->getTag () == REFERENCE)
{
logprint (LOG_ERROR, "evaluate error, no such generated variable "
"`%s'\n", arg->toString ());
}
else
{
logprint (LOG_ERROR, "evaluate error, unable to evaluate "
"`%s'\n", arg->toString ());
}
errors++;
}
else
{
if (arg->getResult()->dropdeps)
{
strlist * preps = arg->getResult()->getPrepDependencies ();
if (preps && (preps->length () > apreps->length ()))
{
delete apreps;
apreps = new strlist (*preps);
}
}
arg->evaluated++;
}
}
}
if (!errors)
{
delete getResult ();
setResult (eval (C (args)));
if (getResult()->getType () != getType ())
{
logprint (LOG_ERROR, "evaluate error, function `%s' returned invalid "
"constant type\n", toString ());
}
}
if (!getResult()->dropdeps && apreps->length () > 0)
{
getResult()->dropdeps = 1;
getResult()->appendPrepDependencies (apreps);
}
delete apreps;
return getResult ();
}
node * application::differentiate (char * derivative)
{
if (isDDX ())
{
return ddx->differentiate (derivative);
}
if (derive)
return derive (this, derivative);
return recreate ();
}
node::node ()
{
tag = UNKNOWN;
setType(TAG_UNKNOWN);
dropdeps = output = evaluated = evalPossible = cycle = duplicate = skip = 0;
next = NULL;
dependencies = NULL;
dataDependencies = NULL;
dropDependencies = NULL;
prepDependencies = NULL;
txt = NULL;
res = NULL;
instance = NULL;
solvee = NULL;
checkee = NULL;
}
node::node (int type)
{
tag = type;
setType(TAG_UNKNOWN);
dropdeps = output = evaluated = evalPossible = cycle = duplicate = skip = 0;
next = NULL;
dependencies = NULL;
dataDependencies = NULL;
dropDependencies = NULL;
prepDependencies = NULL;
txt = NULL;
res = NULL;
instance = NULL;
solvee = NULL;
checkee = NULL;
}
the given node. */
node::node (const node & o)
{
tag = o.tag;
type = o.type;
dropdeps = output = evaluated = evalPossible = cycle = duplicate = skip = 0;
next = NULL;
dependencies = NULL;
dataDependencies = NULL;
dropDependencies = NULL;
prepDependencies = NULL;
txt = NULL;
res = NULL;
instance = NULL;
solvee = o.solvee;
checkee = o.checkee;
}
node::~node ()
{
delete dependencies;
delete dataDependencies;
delete dropDependencies;
delete prepDependencies;
free (txt);
free (instance);
}
void node::setInstance (const char * n)
{
free (instance);
instance = n ? strdup (n) : NULL;
}
char * node::getInstance (void)
{
return instance;
}
to any following node within the list up to the node with a valid
instance name. */
void node::applyInstance (void)
{
char * i = getInstance ();
for (node * n = getNext (); n != NULL; n = n->getNext ())
{
if (n->getInstance () == NULL)
n->setInstance (i);
else
break;
}
}
int node::count (void)
{
int c = 0;
for (node * n = this; n != NULL; n = n->getNext ()) c++;
return c;
}
void node::append (node * last)
{
if (!last) return;
node * n;
for (n = this; n->getNext () != NULL; n = n->getNext ()) ;
last->setNext (NULL);
n->setNext (last);
}
void node::appendNodes (node * last)
{
if (!last) return;
node * n;
for (n = this; n->getNext () != NULL; n = n->getNext ()) ;
n->setNext (last);
}
node * node::get (int pos)
{
node * n = this;
for (int i = 0; i < pos && n != NULL; n = n->getNext (), i++) ;
return n;
}
void node::setResult (constant * r)
{
res = r;
}
constant * node::getResult (int pos)
{
node * n = this;
for (int i = 0; i < pos && n != NULL; n = n->getNext (), i++) ;
return n ? n->getResult () : NULL;
}
result type. */
nr_double_t node::getResultDouble (void)
{
constant * c = getResult ();
if (c != NULL)
{
switch (getType ())
{
case TAG_DOUBLE:
return c->d;
break;
case TAG_COMPLEX:
return real (*(c->c));
break;
case TAG_BOOLEAN:
return c->b ? 1.0 : 0.0;
break;
}
}
return 0.0;
}
result type. */
nr_complex_t node::getResultComplex (void)
{
constant * c = getResult ();
if (c != NULL)
{
switch (getType ())
{
case TAG_DOUBLE:
return nr_complex_t (c->d, 0.0);
break;
case TAG_COMPLEX:
return *(c->c);
break;
case TAG_BOOLEAN:
return c->b ? 1.0 : 0.0;
break;
}
}
return 0.0;
}
nodes result type. */
qucs::vector node::getResultVector (void)
{
constant * c = getResult ();
qucs::vector v;
if (c != NULL)
{
switch (getType ())
{
case TAG_MATRIX:
{
int ro, co, n = 0;
v = qucs::vector (c->m->getRows () * c->m->getCols ());
for (co = 0; co < c->m->getCols (); co++)
for (ro = 0; ro < c->m->getRows (); ro++)
v (n++) = c->m->get (ro, co);
}
break;
case TAG_VECTOR:
v = *(c->v);
break;
case TAG_DOUBLE:
v = qucs::vector (1);
v (0) = c->d;
break;
case TAG_COMPLEX:
v = qucs::vector (1);
v (0) = *(c->c);
break;
case TAG_BOOLEAN:
v = qucs::vector (1);
v (0) = c->b ? 1.0 : 0.0;
break;
}
}
return v;
}
void node::setDependencies (strlist * depends)
{
delete dependencies;
dependencies = depends;
}
strlist * node::getDependencies (void)
{
return dependencies;
}
equation initially passed to the equation checker and returns the
list of variable dependencies regarding this equation instance.
The caller is responsible for deleting the returned string list
object. */
strlist * node::recurseDependencies (checker * check, strlist * deps)
{
strlist * res, * sub = NULL;
if (deps->contains (A(this)->result))
{
res = new strlist (*deps);
cycle = 1;
return res;
}
for (int i = 0; i < deps->length (); i++)
{
char * var = deps->get (i);
node * child = check->findEquation (check->equations, var);
if (child != NULL)
{
if (child->cycle == 0)
{
strlist * cdeps = child->getDependencies ();
if (cdeps->length () > 0)
{
res = strlist::join (sub, cdeps);
delete sub;
sub = res;
}
}
else
{
cycle = 1;
}
}
}
dependencies. */
if (cycle && sub && sub->length () > 0)
{
res = recurseDependencies (check, sub);
delete sub;
sub = res;
}
res = strlist::join (deps, sub);
delete (sub);
return res;
}
dependencies which are going to be dropped during the data
export. */
void node::addDropDependencies (char * dep)
{
if (dropDependencies == NULL) dropDependencies = new strlist ();
dropDependencies->add (dep);
}
dependencies which are going to be prepend. */
void node::addPrepDependencies (char * dep)
{
if (prepDependencies == NULL) prepDependencies = new strlist ();
prepDependencies->add (dep);
}
dependencies which are going to be prepend. */
void node::appendPrepDependencies (strlist * deps)
{
if (prepDependencies == NULL) prepDependencies = new strlist ();
prepDependencies->append (deps);
}
void node::setDataDependencies (strlist * deps)
{
delete dataDependencies;
dataDependencies = deps ? new strlist (*deps) : NULL;
}
constant * node::calculate (void)
{
constant * res = evaluate ();
if (getResult ())
{
strlist * deps = solvee->collectDataDependencies (this);
getResult()->setDataDependencies (deps);
delete deps;
}
else
{
qucs::exception * e = new qucs::exception (EXCEPTION_MATH);
e->setText ("evaluator exception");
throw_exception (e);
}
return res;
}
strlist * node::collectDependencies (void)
{
strlist * depends = new strlist ();
addDependencies (depends);
setDependencies (checker::foldDependencies (depends));
return getDependencies ();
}
strlist * node::collectDataDependencies (void)
{
strlist * deps = getResult()->getDataDependencies ();
if (deps)
{
setDataDependencies (deps);
return deps;
}
if (!getDependencies ())
collectDependencies ();
if (solvee)
{
deps = solvee->collectDataDependencies (this);
setDataDependencies (deps);
delete deps;
}
return getDataDependencies ();
}
checker::checker ()
{
defs = NULL;
equations = NULL;
consts = false;
}
checker::~checker ()
{
node * next;
for (node * eqn = equations; eqn != NULL; eqn = next)
{
next = eqn->getNext ();
delete eqn;
}
}
#define foreach_equation(eqn) \
for (assignment * (eqn) = A (equations); \
(eqn) != NULL; (eqn) = A ((eqn)->getNext ()))
checker and applies the dependency list. */
void checker::collectDependencies (void)
{
foreach_equation (eqn)
{
collectDependencies (eqn);
}
}
void checker::collectDependencies (node * eqn)
{
strlist * depends = new strlist ();
eqn->addDependencies (depends);
eqn->setDependencies (depends);
}
checks whether there is any kind of 'Export="yes|no"' assignment in
it. Depending on the value the referred equation results are saved
into the dataset or not. */
int checker::checkExport (void)
{
int errors = 0;
assignment * next;
for (assignment * eqn = A (equations); eqn != NULL; eqn = next)
{
next = A (eqn->getNext ());
if (!strcmp (eqn->result, "Export"))
{
if (eqn->body->getTag () != REFERENCE ||
(strcmp (R (eqn->body)->n, "yes") &&
strcmp (R (eqn->body)->n, "no")))
{
logprint (LOG_ERROR, "checker error, variable `%s' alternatives "
"are `yes' or `no'\n", eqn->result);
errors++;
}
else
{
int flag = !strcmp (R (eqn->body)->n, "yes") ? 1 : 0;
char * i = eqn->getInstance ();
int found = 0;
foreach_equation (res)
{
if (!strcmp (res->getInstance (), i))
res->output = flag;
if (!strcmp (res->result, "Export") &&
!strcmp (res->getInstance (), i))
{
found++;
}
}
if (found > 1)
{
logprint (LOG_ERROR, "checker error, variable `%s' "
"occurred %dx in `Eqn:%s'\n", eqn->result, found, i);
errors++;
}
dropEquation (eqn);
delete eqn;
}
}
}
return errors;
}
void checker::list (void)
{
for (node * eqn = equations; eqn != NULL; eqn = eqn->getNext ())
{
logprint (LOG_STATUS, "%s", eqn->evalPossible ? "!" : "?");
logprint (LOG_STATUS, "%s", eqn->evalPossible ?
(eqn->getType () == TAG_UNKNOWN ? "U!" :
eqn->getType () == TAG_DOUBLE ? "D!" :
eqn->getType () == TAG_BOOLEAN ? "B!" :
eqn->getType () == TAG_COMPLEX ? "C!" :
eqn->getType () == TAG_VECTOR ? "V!" :
eqn->getType () == TAG_CHAR ? "CHR!" :
eqn->getType () == TAG_STRING ? "STR!" :
eqn->getType () == TAG_MATVEC ? "MV!" :
eqn->getType () == TAG_RANGE ? "R!" :
eqn->getType () == TAG_MATRIX ? "M!" : "?!") : "");
eqn->print ();
logprint (LOG_STATUS, "\n");
}
}
identified by a ".[0-9]{4}" suffix. */
int checker::isGenerated (char * var)
{
int len = strlen (var);
if (len > 5)
{
if (isdigit (var[len-1]) && isdigit (var[len-2]) &&
isdigit (var[len-3]) && isdigit (var[len-4]) &&
var[len-5] == '.')
{
return 1;
}
}
return 0;
}
resolved within the equations and returns zero if so. */
int checker::findUndefined (int noundefined)
{
int err = 0;
strlist * idents = getVariables ();
foreach_equation (eqn)
{
strlist * depends = eqn->getDependencies ();
for (int i = 0; i < depends->length (); i++)
{
char * var = depends->get (i);
if (idents->contains (var) <= 0)
{
if (defs)
{
node * eqn = findProperty (var);
if (eqn)
{
idents->append (var);
eqn->collectDependencies ();
continue;
}
}
if (noundefined)
{
if (isGenerated (var))
continue;
logprint (LOG_ERROR, "checker error, undefined variable `%s' in "
"equation `%s'\n", var, eqn->result);
err++;
}
else
{
logprint (LOG_STATUS, "checker notice, variable `%s' in "
"equation `%s' not yet defined\n", var, eqn->result);
}
}
}
}
delete idents;
return err;
}
in an equation dependency in the netlist. If there is such a
circuit property it returns a new assignment equation. */
node * checker::findProperty (char * var)
{
node * eqn = NULL;
int found = 0;
char * ret, * inst, * prop;
if ((ret = strchr (var, '.')) != NULL)
{
int len = ret - var;
inst = (char *) calloc (1, len + 1);
memcpy (inst, var, len);
prop = &var[len + 1];
}
else return NULL;
for (struct definition_t * def = defs; def; def = def->next)
{
if (!strcmp (def->instance, inst))
{
for (struct pair_t * pair = def->pairs; pair; pair = pair->next)
{
if (!strcmp (pair->key, prop))
{
if (++found == 1)
{
if (pair->value->ident != NULL)
{
eqn = createReference ("#property", var, pair->value->ident);
}
else
{
eqn = createDouble ("#property", var, pair->value->value);
}
}
}
}
}
}
if (found > 1)
{
logprint (LOG_ERROR, "checker error, desired property variable `%s' found "
"%dx, is not unique'\n", var, found);
delete eqn;
eqn = NULL;
}
else if (found == 1)
appendEquation (eqn);
free (inst);
return eqn;
}
a string list. */
strlist * checker::getVariables (void)
{
strlist * idents = new strlist ();
foreach_equation (eqn)
{
idents->add (eqn->result);
}
return idents;
}
emits appropriate error messages and returns zero if everything is
ok. */
int checker::findDuplicate (void)
{
int err = 0;
strlist * idents = getVariables ();
strlist * dups = new strlist ();
foreach_equation (eqn)
{
if (!eqn->duplicate && dups->contains (eqn->result) == 0)
{
eqn->duplicate = idents->contains (eqn->result);
dups->add (eqn->result);
}
else
{
eqn->duplicate = 1;
}
}
foreach_equation (eqndups)
{
if (eqndups->duplicate > 1)
{
logprint (LOG_ERROR, "checker error, variable `%s' assigned %dx\n",
eqndups->result, eqndups->duplicate);
err++;
}
}
delete idents;
delete dups;
return err;
}
or NULL if there is no such equation. The function looks through
the passed equation root. */
node * checker::findEquation (node * root, const char * const n)
{
for (node * eqn = root; eqn != NULL; eqn = eqn->getNext ())
{
if (!strcmp (A(eqn)->result, n))
return eqn;
}
return NULL;
}
or NULL if there is no such equation. */
node * checker::findEquation (const char * const n) const
{
foreach_equation (eqn)
{
if (!strcmp (A(eqn)->result, n)) return eqn;
}
return NULL;
}
returns zero if there are no such cycles. */
int checker::detectCycles (void)
{
int err = 0;
foreach_equation (eqn)
{
strlist * deps = eqn->recurseDependencies (this, eqn->getDependencies ());
if (deps->contains (eqn->result) || eqn->cycle)
{
logprint (LOG_ERROR, "checker error, cyclic definition of variable "
"`%s' involves: `%s'\n", eqn->result, deps->toString ());
err++;
delete deps;
}
else
{
deps = foldDependencies (deps);
eqn->setDependencies (deps);
}
}
return err;
}
only. The given string list gets deleted and a new one is created
and returned. */
strlist * checker::foldDependencies (strlist * deps)
{
strlist * res = new strlist ();
for (int i = 0; deps && i < deps->length (); i++)
{
char * var = deps->get (i);
if (!res->contains (var)) res->append (var);
}
delete deps;
return res;
}
node * checker::appendEquation (node * root, node * last)
{
last->setNext (NULL);
if (root != NULL)
{
node * eqn = lastEquation (root);
eqn->setNext (last);
}
else root = last;
return root;
}
node * checker::lastEquation (node * root)
{
node * eqn;
for (eqn = root; eqn && eqn->getNext () != NULL; eqn = eqn->getNext ()) ;
return eqn;
}
void checker::dropEquation (node * eqn)
{
if (eqn == equations)
{
equations = eqn->getNext ();
}
else
{
node * prev;
for (prev = equations; prev->getNext () != eqn; prev = prev->getNext()) ;
prev->setNext (eqn->getNext ());
}
}
used to evaluate the list step by step. Each equation being
evaluable is properly marked, remaining equations are appended. */
void checker::reorderEquations (void)
{
node * root = NULL, * next, * last;
for (node * eqn = equations; eqn != NULL; eqn = next)
{
strlist * deps = eqn->getDependencies ();
int i, found, gens;
next = eqn->getNext ();
previous equations. */
for (found = gens = i = 0; i < deps->length (); i++)
{
char * var = deps->get (i);
if (findEquation (root, var) != NULL) found++;
if (isGenerated (var)) gens++;
}
if (found == (deps->length () - gens))
{
the new list. */
dropEquation (eqn);
root = appendEquation (root, eqn);
eqn->evalPossible = 1;
next = equations;
}
}
if (root != NULL)
{
last = lastEquation (root);
last->setNext (equations);
equations = root;
}
}
passes the checker instance to each equation. */
void checker::setEquations (node * eqns)
{
equations = eqns;
foreach_equation (eqn)
{
eqn->checkee = this;
}
}
checks the availability of the appropriate function. */
int checker::applyTypes (void)
{
int err = 0;
foreach_equation (eqn)
{
if (eqn->evalPossible)
{
if (eqn->evalType () == TAG_UNKNOWN)
{
logprint (LOG_ERROR, "checker error, type of equation `%s' "
"undefined\n", eqn->result);
err++;
}
}
else break;
}
return err;
}
returns zero on success or non-zero if the parsed equations
contained errors. */
int checker::check (int noundefined)
{
int err = 0;
err += checkExport ();
collectDependencies ();
err += findUndefined (noundefined);
err += findDuplicate ();
err += detectCycles ();
reorderEquations ();
err += applyTypes ();
#if DEBUG && 0
list ();
#endif
return err;
}
solver::solver (checker * c)
{
equations = NULL;
data = NULL;
generated = 0;
checkee = c;
}
solver::~solver ()
{
node * next;
for (node * eqn = equations; eqn != NULL; eqn = next)
{
next = eqn->getNext ();
delete eqn;
}
}
void solver::evaluate (void)
{
foreach_equation (eqn)
{
if (eqn->evalPossible && !eqn->skip )
{
try_running ()
{
eqn->solvee = this;
eqn->calculate ();
}
catch_exception ()
{
default:
estack.print ("evaluation");
break;
}
eqn->evaluated++;
#if DEBUG && 0
logprint (LOG_STATUS, "%s = %s\n", A(eqn)->result,
eqn->getResult () ? eqn->getResult()->toString () : "error");
#if TESTING_DERIVATIVE || 0
logprint (LOG_STATUS, "%s\n", eqn->toString ());
logprint (LOG_STATUS, "%s\n", eqn->differentiate("x")->toString ());
#endif
#endif
}
}
}
stored in the equation solver. */
node * solver::addEquationData (qucs::vector * v, bool ref)
{
constant * con = new constant (TAG_VECTOR);
con->v = v;
con->dataref = ref;
assignment * assign = new assignment ();
assign->result = strdup (v->getName ());
assign->body = con;
assign->setNext (equations);
equations = assign;
return assign;
}
resulting data vector is going to be copied and exported - given a
generated name based upon the second argument. */
node * solver::addGeneratedEquation (qucs::vector * v, const char * n)
{
char * str = (char *) malloc (strlen (n) + 6);
sprintf (str, "%s.%04d", n, ++generated);
qucs::vector * c = new qucs::vector (*v);
c->setName (str);
node * res = addEquationData (c);
res->setInstance ("#generated");
res->setDependencies (new strlist ());
res->evalType ();
res->solvee = this;
res->evaluate ();
res->output = 1;
free (str);
return res;
}
given equation node to one or more valid dataset vector(s). */
qucs::vector * solver::dataVector (node * eqn)
{
qucs::vector * v = NULL;
if (!eqn->getResult ()) return NULL;
switch (eqn->getType ())
{
case TAG_VECTOR:
v = new qucs::vector (* (eqn->getResult()->v));
v->setNext (NULL);
v->setPrev (NULL);
break;
case TAG_DOUBLE:
v = new qucs::vector ();
v->add (eqn->getResult()->d);
break;
case TAG_BOOLEAN:
v = new qucs::vector ();
v->add (eqn->getResult()->b ? 1 : 0);
break;
case TAG_COMPLEX:
v = new qucs::vector ();
v->add (* (eqn->getResult()->c));
break;
case TAG_MATVEC:
{
matvec * mv = eqn->getResult()->mv;
mv->setName (A(eqn)->result);
for (int r = 0; r < mv->getRows (); r++)
{
for (int c = 0; c < mv->getCols (); c++)
{
qucs::vector * t = new qucs::vector (mv->get (r, c));
t->setNext (v);
v = t;
}
}
}
return v;
case TAG_MATRIX:
{
matrix * m = eqn->getResult()->m;
for (int r = 0; r < m->getRows (); r++)
{
for (int c = 0; c < m->getCols (); c++)
{
qucs::vector * t = new qucs::vector ();
t->setName (matvec::createMatrixString (A(eqn)->result, r, c));
t->add (m->get (r, c));
t->setNext (v);
v = t;
}
}
}
return v;
default:
return NULL;
}
v->setName (A(eqn)->result);
return v;
}
these to the list of equation node inside the equation solver. */
void solver::checkinDataset (void)
{
if (data == NULL) return;
qucs::vector * v;
findMatrixVectors (data->getDependencies ());
findMatrixVectors (data->getVariables ());
for (v = data->getDependencies (); v != NULL; v = (qucs::vector *) v->getNext ())
{
if (v->getRequested () != -1)
{
node * eqn = addEquationData (v, true);
strlist * deps = new strlist ();
deps->add (v->getName ());
eqn->setDataDependencies (deps);
delete deps;
}
}
for (v = data->getVariables (); v != NULL; v = (qucs::vector *) v->getNext ())
{
if (v->getRequested () != -1)
{
node * eqn = addEquationData (v, true);
eqn->setDataDependencies (v->getDependencies ());
}
}
}
for possible matrix vectors. These are detected by the vectors'
names (e.g. S[1,1]). The matrix vectors found in the dataset get
converted and saved into the set of equations. */
void solver::findMatrixVectors (qucs::vector * v)
{
qucs::vector * vec;
strlist * deps;
char * p, * cand;
int s, r, c, a, b, n = 1;
for (vec = v; vec != NULL; vec = (qucs::vector *) vec->getNext ())
vec->setRequested (0);
do
{
r = c = s = -1;
cand = NULL;
deps = NULL;
for (vec = v; vec != NULL; vec = (qucs::vector *) vec->getNext ())
{
if (vec->getRequested ()) continue;
if ((p = matvec::isMatrixVector (vec->getName (), a, b)) != NULL)
{
if (cand != NULL)
{
if (!strcmp (p, cand) && s == vec->getSize ())
{
if (a > r) r = a;
if (b > c) c = b;
vec->setRequested (n);
}
}
else
{
save its name, row and column index, its size (length of
the vector) and data dependencies; then set the 'found' flag */
cand = strdup (p);
r = a;
c = b;
s = vec->getSize ();
vec->setRequested (n);
deps = vec->getDependencies ();
}
free (p);
}
}
if (cand != NULL)
{
matvec * mv = new matvec (s, r + 1, c + 1);
mv->setName (cand);
for (vec = v; vec != NULL; vec = (qucs::vector *) vec->getNext ())
{
if (vec->getRequested () == n)
{
p = matvec::isMatrixVector (vec->getName (), a, b);
mv->set (*vec, a, b);
free (p);
vec->setRequested (-1);
}
}
node * eqn = addEquationData (mv);
eqn->solvee = this;
eqn->evaluate ();
if (deps == NULL)
{
strlist * deps = new strlist ();
deps->add (mv->getName ());
eqn->setDataDependencies (deps);
delete deps;
}
else
{
eqn->setDataDependencies (deps);
}
free (cand);
cand = NULL;
}
n++;
}
while (cand != NULL);
}
vector and returns it. The new assignment is appended to the list
of available equations. */
node * solver::addEquationData (matvec * mv)
{
constant * con = new constant (TAG_MATVEC);
con->mv = mv;
assignment * assign = new assignment ();
assign->result = strdup (mv->getName ());
assign->body = con;
assign->setNext (equations);
equations = assign;
return assign;
}
node (a constant). The constant must already been evaluated when
this function is called. */
int solver::dataSize (constant * eqn)
{
int size = 0;
switch (eqn->getType ())
{
case TAG_VECTOR:
size = eqn->getResult()->v->getSize ();
break;
case TAG_MATVEC:
size = eqn->getResult()->mv->getSize ();
default:
size = 1;
}
return size;
}
variable name. It must be ensured that the variable actually
exists and is already evaluated. */
int solver::getDataSize (char * var)
{
node * eqn = checker::findEquation (equations, var);
return dataSize (C (eqn));
}
of the dataset entries stored in the given dependency list or one
if there are no data dependencies at all. */
int solver::getDependencySize (strlist * deps, int idx)
{
int size = 1;
if (deps == NULL) return 1;
for (int i = 0; i < deps->length () - idx; i++)
{
size *= getDataSize (deps->get (i));
}
return size;
}
data entries within these dataset dependencies. It returns at
least one no matter whether the data vectors can be found or not. */
int solver::dataSize (strlist * deps)
{
int size = 1;
for (int i = 0; deps != NULL && i < deps->length (); i++)
{
char * str = deps->get (i);
qucs::vector * dep = data->findDependency (str);
qucs::vector * var = data->findVariable (str);
size *= dep ? dep->getSize () : var ? var->getSize () : 1;
}
return size;
}
the given variable name. If there is no such variable, it returns
NULL. */
qucs::vector * solver::getDataVector (char * str)
{
qucs::vector * var;
if (data != NULL)
{
if ((var = data->findVariable (str)) != NULL)
return var;
if ((var = data->findDependency (str)) != NULL)
return var;
}
if (equations != NULL)
{
node * eqn = checker::findEquation (equations, str);
constant * res = eqn->getResult ();
if (res->getTag () == CONSTANT && res->getType () == TAG_VECTOR)
{
return res->v;
}
}
return NULL;
}
for the given equation node and returns it as a string list. It
returns NULL if there are no such dependencies. */
strlist * solver::collectDataDependencies (node * eqn)
{
strlist * sub = NULL, * datadeps = NULL;
if (!eqn->getResult()->dropdeps)
{
strlist * deps = eqn->getDependencies ();
datadeps = eqn->getDataDependencies ();
datadeps = datadeps ? new strlist (*datadeps) : NULL;
for (int i = 0; deps && i < deps->length (); i++)
{
char * var = deps->get (i);
node * n = checker::findEquation (equations, var);
if (n == NULL && eqn->solvee != NULL)
n = checker::findEquation (eqn->solvee->getEquations (), var);
if (n != NULL)
{
strlist * resdeps;
if ((resdeps = n->getResult()->getDataDependencies ()) != NULL)
n->setDataDependencies (resdeps);
sub = strlist::join (datadeps, n->getDataDependencies ());
sub->del (n->getResult()->getDropDependencies ());
sub->add (n->getResult()->getPrepDependencies ());
}
delete datadeps;
datadeps = sub;
}
}
strlist * preps = eqn->getResult()->getPrepDependencies ();
if (datadeps)
{
if (preps) datadeps->add (preps);
}
else
{
datadeps = new strlist ();
if (preps) datadeps->add (preps);
}
datadeps = checker::foldDependencies (datadeps);
datadeps->del (eqn->getResult()->getDropDependencies ());
if (datadeps->length () == 0)
{
delete datadeps;
datadeps = NULL;
}
return datadeps;
}
void solver::checkoutDataset (void)
{
if (data == NULL) return;
foreach_equation (eqn)
{
if (!eqn->output) continue;
if (!findEquationResult (eqn))
{
qucs::vector * v = dataVector (eqn);
if (v == NULL) continue;
strlist * datadeps = collectDataDependencies (eqn);
if (v->getSize () <= 1 && dataSize (datadeps) > v->getSize ())
{
delete datadeps;
datadeps = NULL;
}
if (datadeps && datadeps->length () > 0)
{
v->setDependencies (datadeps);
if (v->getNext () != NULL)
{
data->applyDependencies (v);
data->addVariables (v);
}
else
{
data->addVariable (v);
}
}
else
{
if (v->getNext () != NULL)
data->addDependencies (v);
else
data->addDependency (v);
delete datadeps;
}
}
}
}
already within the dataset. It returns non-zero if so, otherwise
the function returns zero. */
int solver::findEquationResult (node * eqn)
{
if (eqn->getType () == TAG_MATVEC)
{
matvec * mv = eqn->getResult()->mv;
for (int r = 0; r < mv->getRows (); r++)
{
for (int c = 0; c < mv->getCols (); c++)
{
char * str = matvec::createMatrixString (A(eqn)->result, r, c);
if (data->findDependency (str) || data->findVariable (str))
return 1;
}
}
}
else
{
char * str = A(eqn)->result;
if (data->findDependency (str) || data->findVariable (str))
return 1;
}
return 0;
}
the solver. The optional dataset passed to the function receives
the results of the calculations. */
int solver::solve (dataset * data)
{
setData (data);
checkinDataset ();
checkee->setEquations (equations);
if (checkee->check (data ? 1 : 0) != 0)
{
return -1;
}
equations = checkee->getEquations ();
evaluate ();
checkoutDataset ();
return 0;
}
a string list. */
strlist * checker::variables (void)
{
strlist * idents = new strlist ();
foreach_equation (eqn)
{
idents->add (eqn->result);
}
return idents;
}
bool checker::containsVariable (const char * const ident) const
{
foreach_equation (eqn)
{
if (!strcmp (ident, eqn->result))
return true;
}
return false;
}
struct pconstant
{
const char * ident;
nr_double_t value;
};
static struct pconstant pconstants[] =
{
{ "pi", pi },
{ "e", euler },
{ "kB", kB },
{ "q", Q_e },
{ NULL, 0 }
};
appends the predefined constants to the list of equations. */
void checker::constants (void)
{
if (consts) return;
for (int i = 0; pconstants[i].ident != NULL; i++)
{
addDouble ("#predefined", pconstants[i].ident, pconstants[i].value);
}
consts = true;
}
of an assignment of a reference. */
node * checker::addReference (const char * type, const char * ident,
char * value)
{
node * eqn = createReference (type, ident, value);
addEquation (eqn);
return eqn;
}
of an assignment of a double variable. */
node * checker::addDouble (const char * type, const char * ident,
nr_double_t value)
{
node * eqn = createDouble (type, ident, value);
addEquation (eqn);
return eqn;
}
of an assignment of a complex variable. */
node * checker::addComplex (const char * type, const char * ident,
nr_complex_t value)
{
node * eqn = createComplex (type, ident, value);
addEquation (eqn);
return eqn;
}
void checker::addEquation (node * eqn)
{
eqn->setNext (equations);
equations = eqn;
}
void checker::appendEquation (node * eqn)
{
eqn->setNext (NULL);
node * last = lastEquation (equations);
if (last != NULL)
last->setNext (eqn);
else
equations = eqn;
}
double variable. */
node * checker::createDouble (const char * type, const char * ident,
nr_double_t value)
{
constant * c = new constant (TAG_DOUBLE);
c->checkee = this;
c->d = value;
assignment * a = new assignment ();
a->checkee = this;
a->result = strdup (ident);
a->body = c;
a->output = 0;
a->setInstance (type);
return a;
}
complex variable. */
node * checker::createComplex (const char * type, const char * ident,
nr_complex_t value)
{
constant * c = new constant (TAG_COMPLEX);
c->checkee = this;
c->c = new nr_complex_t (value);
assignment * a = new assignment ();
a->checkee = this;
a->result = strdup (ident);
a->body = c;
a->output = 0;
a->setInstance (type);
return a;
}
reference. */
node * checker::createReference (const char * type, const char * ident,
char * value)
{
reference * r = new reference ();
r->checkee = this;
r->n = strdup (value);
assignment * a = new assignment ();
a->checkee = this;
a->result = strdup (ident);
a->body = r;
a->output = 0;
a->setInstance (type);
return a;
}
result and returns it. If there is no such assignment, zero is
returned. */
nr_double_t checker::getDouble (const char * const ident) const
{
foreach_equation (eqn)
{
if (!strcmp (ident, eqn->result))
{
return eqn->getResultDouble ();
}
}
return 0.0;
}
specified assignment. If found the given value is set. */
void checker::setDouble (const char * const ident, nr_double_t val)
{
foreach_equation (eqn)
{
if (!strcmp (ident, eqn->result))
{
if (eqn->body->getTag () == CONSTANT)
{
constant * c = C (eqn->body);
if (c->type == TAG_DOUBLE) c->d = val;
}
}
}
}
result and returns it. If there is no such assignment, an empty
vector is returned. */
qucs::vector checker::getVector (const char * const ident) const
{
foreach_equation (eqn)
{
if (!strcmp (ident, eqn->result))
{
return eqn->getResultVector ();
}
}
return qucs::vector ();
}
}