Qucs-core  0.0.19
equation.cpp
Go to the documentation of this file.
00001 /*
00002  * equation.cpp - checker for the Qucs equations
00003  *
00004  * Copyright (C) 2004-2009 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 <stdio.h>
00030 #include <stdlib.h>
00031 #include <string.h>
00032 #include <cmath>
00033 #include <ctype.h>
00034 
00035 #include "logging.h"
00036 #include "complex.h"
00037 #include "object.h"
00038 #include "vector.h"
00039 #include "matrix.h"
00040 #include "matvec.h"
00041 #include "dataset.h"
00042 #include "strlist.h"
00043 #include "netdefs.h"
00044 #include "equation.h"
00045 #include "evaluate.h"
00046 #include "differentiate.h"
00047 #include "constants.h"
00048 #include "range.h"
00049 #include "exception.h"
00050 #include "exceptionstack.h"
00051 
00052 namespace qucs
00053 {
00054 
00055 using namespace eqn;
00056 
00057 #define A(a) ((assignment *) (a))
00058 #define N(n) ((node *) (n))
00059 #define C(c) ((constant *) (c))
00060 #define R(r) ((reference *) (r))
00061 
00062 // Constructor creates an untyped instance of the constant class.
00063 constant::constant () : node (CONSTANT)
00064 {
00065     type = TAG_UNKNOWN;
00066     dataref = false;
00067     d = 0.0;
00068     setType (type);
00069 }
00070 
00071 // This constructor creates an typed instance of the constant class.
00072 constant::constant (int tag) : node (CONSTANT)
00073 {
00074     type = tag;
00075     dataref = false;
00076     d = 0.0;
00077     setType (type);
00078 }
00079 
00080 /* This copy constructor creates a instance of the constant class
00081    based on the given constant. */
00082 constant::constant (const constant & o) : node (o)
00083 {
00084     type = o.type;
00085     dataref = o.dataref;
00086     d = 0.0;
00087     setType (type);
00088     switch (type)
00089     {
00090     case TAG_BOOLEAN:
00091         b = o.b;
00092         break;
00093     case TAG_DOUBLE:
00094         d = o.d;
00095         break;
00096     case TAG_COMPLEX:
00097         c = dataref ? o.c : new nr_complex_t (*o.c);
00098         break;
00099     case TAG_VECTOR:
00100         v = dataref ? o.v : new qucs::vector (*o.v);
00101         break;
00102     case TAG_MATRIX:
00103         m = dataref ? o.m : new matrix (*o.m);
00104         break;
00105     case TAG_MATVEC:
00106         mv = dataref ? o.mv : new matvec (*o.mv);
00107         break;
00108     case TAG_STRING:
00109         s = dataref ? o.s : strdup (s);
00110         break;
00111     case TAG_CHAR:
00112         chr = o.chr;
00113         break;
00114     case TAG_RANGE:
00115         r = dataref ? o.r : new range (*o.r);
00116         break;
00117     }
00118 }
00119 
00120 // Re-creates the given instance.
00121 node * constant::recreate (void)
00122 {
00123     return new constant (*this);
00124 }
00125 
00126 // Destructor deletes an instance of the constant class.
00127 constant::~constant ()
00128 {
00129     if (!dataref)
00130     {
00131         switch (type)
00132         {
00133         case TAG_COMPLEX:
00134             delete c;
00135             break;
00136         case TAG_VECTOR:
00137             delete v;
00138             break;
00139         case TAG_MATRIX:
00140             delete m;
00141             break;
00142         case TAG_MATVEC:
00143             delete mv;
00144             break;
00145         case TAG_STRING:
00146             free (s);
00147             break;
00148         case TAG_RANGE:
00149             delete r;
00150             break;
00151         }
00152     }
00153 }
00154 
00155 /* Depending on the type of constant the function prints the textual
00156    representation of the object. */
00157 void constant::print (void)
00158 {
00159     logprint (LOG_STATUS, "%s", toString ());
00160 }
00161 
00162 // Returns the string representation of a complex value.
00163 static char * Cplx2String (nr_complex_t c)
00164 {
00165     static char str[256]; // enough for a real or complex number
00166     if (imag (c) == 0.0)
00167     {
00168         sprintf (str, "%g", (double) real (c));
00169     }
00170     else
00171     {
00172         sprintf (str, "(%g%cj%g)", (double ) real (c),
00173                  imag (c) >= 0.0 ? '+' : '-', (double) fabs (imag (c)));
00174     }
00175     return str;
00176 }
00177 
00178 /* This function returns a string representation depending on the type
00179    of constant. */
00180 char * constant::toString (void)
00181 {
00182     char str[256];
00183     free (txt);
00184     switch (type)
00185     {
00186     case TAG_BOOLEAN:
00187         sprintf (str, "%d", b ? 1 : 0);
00188         txt = strdup (str);
00189         break;
00190     case TAG_DOUBLE:
00191         sprintf (str, "%g", (double) d);
00192         txt = strdup (str);
00193         break;
00194     case TAG_COMPLEX:
00195         txt = strdup (Cplx2String (*c));
00196         break;
00197     case TAG_VECTOR:
00198     {
00199         int pos = 1, len = 3 + v->getSize () - 1;
00200         txt = (char *) malloc (len);
00201         strcpy (txt, "[");
00202         for (int i = 0; i < v->getSize (); i++)
00203         {
00204             char * s = Cplx2String (v->get (i));
00205             txt = (char *) realloc (txt, len += strlen (s));
00206             strcpy (&txt[pos], s);
00207             pos += strlen (s);
00208             if (i != v->getSize () - 1) strcpy (&txt[pos++], ";");
00209         }
00210         strcpy (&txt[pos], "]");
00211     }
00212     break;
00213     case TAG_MATRIX:
00214     {
00215         int len = 3 + (m->getRows () - 1) * m->getCols () + (m->getCols () - 1);
00216         txt = (char *) malloc (len);
00217         strcpy (txt, "[");
00218         for (int r = 0; r < m->getRows (); r++)
00219         {
00220             for (int c = 0; c < m->getCols (); c++)
00221             {
00222                 char * s = Cplx2String (m->get (r, c));
00223                 txt = (char *) realloc (txt, len += strlen (s));
00224                 strcat (txt, s);
00225                 if (c != m->getCols () - 1) strcat (txt, ",");
00226             }
00227             if (r != m->getRows () - 1) strcat (txt, ";");
00228         }
00229         strcat (txt, "]");
00230     }
00231     break;
00232     case TAG_MATVEC:
00233         sprintf (str, "[%dx%d](%d)",
00234                  mv->getRows (), mv->getCols (), mv->getSize ());
00235         txt = strdup (str);
00236         break;
00237     case TAG_CHAR:
00238         sprintf (str, "'%c'", chr);
00239         txt = strdup (str);
00240         break;
00241     case TAG_STRING:
00242         sprintf (str, "'%s'", s);
00243         txt = strdup (str);
00244         break;
00245     case TAG_RANGE:
00246         txt = strdup (r->toString ());
00247         break;
00248     default:
00249         txt = strdup ("(no such type)");
00250         break;
00251     }
00252     return txt;
00253 }
00254 
00255 // Returns the type of constant.
00256 int constant::evalType (void)
00257 {
00258     return getType ();
00259 }
00260 
00261 // Returns the result stored in the constant.
00262 constant * constant::evaluate (void)
00263 {
00264     setResult (this);
00265     return getResult ();
00266 }
00267 
00268 // Returns the derivative of a constant.
00269 node * constant::differentiate (char *)
00270 {
00271     constant * res = new constant (TAG_DOUBLE);
00272     res->d = 0;
00273     return res;
00274 }
00275 
00276 // Constructor creates an instance of the reference class.
00277 reference::reference () : node (REFERENCE)
00278 {
00279     n = NULL;
00280     ref = NULL;
00281 }
00282 
00283 /* This copy constructor creates a instance of the reference class
00284    based on the given reference. */
00285 reference::reference (const reference & o) : node (o)
00286 {
00287     n = o.n ? strdup (o.n) : NULL;
00288     ref = o.ref;
00289 }
00290 
00291 // Re-creates the given instance.
00292 node * reference::recreate (void)
00293 {
00294     return new reference (*this);
00295 }
00296 
00297 // Replaces reference name by the new given name.
00298 void reference::replace (char * src, char * dst)
00299 {
00300     if (!strcmp (src, n))
00301     {
00302         free (n);
00303         n = dst ? strdup (dst) : NULL;
00304     }
00305 }
00306 
00307 // Destructor deletes an instance of the reference class.
00308 reference::~reference ()
00309 {
00310     free (n);
00311 }
00312 
00313 // Prints textual representation of the reference object.
00314 void reference::print (void)
00315 {
00316     logprint (LOG_STATUS, "%s", toString ());
00317 }
00318 
00319 // Returns textual representation of the reference object.
00320 char * reference::toString (void)
00321 {
00322     free (txt);
00323     txt = strdup (n);
00324     return txt;
00325 }
00326 
00327 // Adds the name of the reference to the list of dependencies.
00328 void reference::addDependencies (strlist * depends)
00329 {
00330     depends->add (n);
00331     findVariable ();
00332 }
00333 
00334 // Find and save the actual equation reference.
00335 void reference::findVariable (void)
00336 {
00337     ref = NULL; // force reference to be updated
00338     if (!ref)
00339     {
00340         node * eqn;
00341         if (checkee != NULL)
00342         {
00343             for (eqn = checkee->getEquations (); eqn; eqn = eqn->getNext ())
00344             {
00345                 if (!strcmp (n, A(eqn)->result))
00346                 {
00347                     ref = eqn;
00348                     break;
00349                 }
00350             }
00351         }
00352         if (solvee != NULL && !ref)
00353         {
00354             for (eqn = solvee->getEquations (); eqn; eqn = eqn->getNext ())
00355             {
00356                 if (!strcmp (n, A(eqn)->result))
00357                 {
00358                     ref = eqn;
00359                     break;
00360                 }
00361             }
00362         }
00363     }
00364 }
00365 
00366 // Returns the type of reference.
00367 int reference::evalType (void)
00368 {
00369     setType (TAG_UNKNOWN);
00370     findVariable ();
00371     if (ref != NULL)
00372     {
00373         setType (A(ref)->body->evalType ());
00374     }
00375     return getType ();
00376 }
00377 
00378 // Returns the actual result of the reference.
00379 constant * reference::evaluate (void)
00380 {
00381     setResult (NULL);
00382     findVariable ();
00383     if (ref != NULL)
00384     {
00385         setResult (A(ref)->body->getResult ());
00386     }
00387     return getResult ();
00388 }
00389 
00390 // Returns the derivative of a reference.
00391 node * reference::differentiate (char * derivative)
00392 {
00393     constant * res = new constant (TAG_DOUBLE);
00394     if (n != NULL && !strcmp (n, derivative))
00395         res->d = 1;
00396     else
00397         res->d = 0;
00398     return res;
00399 }
00400 
00401 // Constructor creates an instance of the assignment class.
00402 assignment::assignment () : node (ASSIGNMENT)
00403 {
00404     body = NULL;
00405     result = NULL;
00406 }
00407 
00408 /* This copy constructor creates a instance of the assignment class
00409    based on the given assignment. */
00410 assignment::assignment (const assignment & o) : node (o)
00411 {
00412     body = o.body->recreate ();
00413     result = o.result ? strdup (o.result) : NULL;
00414 }
00415 
00416 // Re-creates the given instance.
00417 node * assignment::recreate (void)
00418 {
00419     return new assignment (*this);
00420 }
00421 
00422 // Replaces reference name by the new given name.
00423 void assignment::replace (char * src, char * dst)
00424 {
00425     body->replace (src, dst);
00426 }
00427 
00428 // Renames the left hand side of the assignment.
00429 void assignment::rename (char * n)
00430 {
00431     free (result);
00432     result = n ? strdup (n) : NULL;
00433 }
00434 
00435 // Destructor deletes an instance of the assignment class.
00436 assignment::~assignment ()
00437 {
00438     delete body;
00439     free (result);
00440 }
00441 
00442 // Prints textual representation of the assignment object.
00443 void assignment::print (void)
00444 {
00445     logprint (LOG_STATUS, "%s", toString ());
00446 }
00447 
00448 // Returns textual representation of the assignment object.
00449 char * assignment::toString (void)
00450 {
00451     free (txt);
00452     char * str = body->toString ();
00453     txt = (char *) malloc (strlen (result) + strlen (str) + 4);
00454     sprintf (txt, "%s = %s", result, str);
00455     return txt;
00456 }
00457 
00458 // Adds the right hand side of the assignment to the list of dependencies.
00459 void assignment::addDependencies (strlist * depends)
00460 {
00461     body->checkee = checkee;
00462     body->addDependencies (depends);
00463 }
00464 
00465 // Returns the type of assignment.
00466 int assignment::evalType (void)
00467 {
00468     setType (body->evalType ());
00469     return getType ();
00470 }
00471 
00472 // Returns the result of the assignment.
00473 constant * assignment::evaluate (void)
00474 {
00475     body->solvee = solvee;
00476     setResult (body->evaluate ());
00477     // inherit drop/prep dependencies of applications
00478     if (body->getResult()->dropdeps)
00479     {
00480         getResult()->dropdeps = body->getResult()->dropdeps;
00481         strlist * preps = body->getPrepDependencies ();
00482         if (preps) getResult()->setPrepDependencies (new strlist (*preps));
00483     }
00484     return getResult ();
00485 }
00486 
00487 // Returns the derivative of an assignment.
00488 node * assignment::differentiate (char * derivative)
00489 {
00490     char * txt = (char *) malloc (strlen (result) + strlen (derivative) + 4);
00491     sprintf (txt, "d%s_d%s", result, derivative);
00492     assignment * res = new assignment ();
00493     res->result = txt;
00494     res->body = body->differentiate (derivative);
00495     return res;
00496 }
00497 
00498 // Some small helpers.
00499 #define D(con) (C(con)->d)
00500 #define isConst(n) ((n)->getTag()==CONSTANT && C(n)->getType()==TAG_DOUBLE)
00501 #define isZero(n)  (isConst(n) && D(n) == 0.0)
00502 #define isOne(n)   (isConst(n) && D(n) == 1.0)
00503 #define defCon(res,val) res = new constant (TAG_DOUBLE); C(res)->d = val;
00504 
00505 /* Multiply two assignments. */
00506 void assignment::mul (assignment * f)
00507 {
00508     node * factor = f->body->recreate ();
00509     if (isZero (body) || isZero (factor))
00510     {
00511         delete body;
00512         delete factor;
00513         defCon (body, 0);
00514     }
00515     else if (isOne (body))
00516     {
00517         delete body;
00518         body = factor;
00519     }
00520     else if (isOne (factor))
00521     {
00522         delete factor;
00523         //body = body;
00524     }
00525     else
00526     {
00527         application * mul = new application ("*", 2);
00528         mul->args = body;
00529         mul->args->append (factor);
00530         body = mul;
00531     }
00532 }
00533 
00534 /* Multiply two assignments by reference. */
00535 void assignment::mulref (assignment * f)
00536 {
00537     node * factor = f->body->recreate ();
00538     reference * r = new reference ();
00539     r->n = strdup (f->result);
00540     if (isZero (body) || isZero (factor))
00541     {
00542         delete body;
00543         defCon (body, 0);
00544     }
00545     else if (isOne (body))
00546     {
00547         body = r;
00548     }
00549     else if (isOne (factor))
00550     {
00551         //body = body;
00552     }
00553     else
00554     {
00555         application * mul = new application ("*", 2);
00556         mul->args = body;
00557         mul->args->append (r);
00558         body = mul;
00559     }
00560 }
00561 
00562 /* Add two assignments. */
00563 void assignment::add (assignment * f)
00564 {
00565     node * factor = f->body->recreate ();
00566     if (isZero (body) && isZero (factor))
00567     {
00568         delete body;
00569         delete factor;
00570         defCon (body, 0);
00571     }
00572     else if (isZero (body))
00573     {
00574         delete body;
00575         body = factor;
00576     }
00577     else if (isZero (factor))
00578     {
00579         delete factor;
00580         //body = body;
00581     }
00582     else
00583     {
00584         application * add = new application ("+", 2);
00585         add->args = body;
00586         add->args->append (factor);
00587         body = add;
00588     }
00589 }
00590 
00591 // Constructor creates an instance of the application class.
00592 application::application () : node (APPLICATION)
00593 {
00594     n = NULL;
00595     nargs = 0;
00596     args = NULL;
00597     eval = NULL;
00598     derive = NULL;
00599     ddx = NULL;
00600 }
00601 
00602 /* Constructor creates an instance of the application class with a
00603    given function name and the number of arguments. */
00604 application::application (const char * func, int a) : node (APPLICATION)
00605 {
00606     n = func ? strdup (func) : NULL;
00607     nargs = a;
00608     args = NULL;
00609     eval = NULL;
00610     derive = NULL;
00611     ddx = NULL;
00612 }
00613 
00614 /* This copy constructor creates a instance of the application class
00615    based on the given application. */
00616 application::application (const application & o) : node (o)
00617 {
00618     n = o.n ? strdup (o.n) : NULL;
00619     nargs = o.nargs;
00620     if (o.args != NULL)
00621     {
00622         node * arg = o.args;
00623         args = arg->recreate ();
00624         for (arg = arg->getNext (); arg != NULL; arg = arg->getNext ())
00625         {
00626             args->append (arg->recreate ());
00627         }
00628     }
00629     else args = NULL;
00630     eval = o.eval;
00631     derive = o.derive;
00632     ddx = o.ddx ? o.ddx->recreate () : NULL;
00633 }
00634 
00635 // Re-creates the given instance.
00636 node * application::recreate (void)
00637 {
00638     return new application (*this);
00639 }
00640 
00641 // Replaces reference name by the new given name.
00642 void application::replace (char * src, char * dst)
00643 {
00644     for (node * arg = args; arg != NULL; arg = arg->getNext ())
00645     {
00646         arg->replace (src, dst);
00647     }
00648     if (ddx) ddx->replace (src, dst);
00649 }
00650 
00651 // Destructor deletes an instance of the application class.
00652 application::~application ()
00653 {
00654     node * next;
00655     for (node * arg = args; arg != NULL; arg = next)
00656     {
00657         next = arg->getNext ();
00658         delete arg;
00659     }
00660     delete getResult ();
00661     free (n);
00662     delete ddx;
00663 }
00664 
00665 // Prints textual representation of the application object.
00666 void application::print (void)
00667 {
00668     logprint (LOG_STATUS, "%s", toString ());
00669 }
00670 
00671 // Returns textual representation of the application object.
00672 char * application::toString (void)
00673 {
00674     int nparam = nargs > 0 ? (nargs - 1) : 0;
00675     free (txt);
00676     // binary operations
00677     if ((!strcmp (n, "+")  || !strcmp (n, "-")  || !strcmp (n, "*") ||
00678             !strcmp (n, "/")  || !strcmp (n, "^")  || !strcmp (n, "%") ||
00679             !strcmp (n, "<")  || !strcmp (n, ">")  || !strcmp (n, "<=") ||
00680             !strcmp (n, ">=") || !strcmp (n, "&&") || !strcmp (n, "||") ||
00681             !strcmp (n, "==") || !strcmp (n, "!="))
00682             && nargs == 2)
00683     {
00684         char * arg1 = args->toString ();
00685         char * arg2 = args->getNext()->toString ();
00686         txt = (char *) malloc (strlen (n) + strlen (arg1) + strlen (arg2) + 3);
00687         sprintf (txt, "(%s%s%s)", arg1, n, arg2);
00688     }
00689     // ternary ?: operator
00690     else if (!strcmp (n, "?:"))
00691     {
00692         char * arg1 = args->toString ();
00693         char * arg2 = args->getNext()->toString ();
00694         char * arg3 = args->getNext()->getNext()->toString ();
00695         txt = (char *) malloc (strlen (arg3) + strlen (arg1) + strlen (arg2) + 5);
00696         sprintf (txt, "(%s?%s:%s)", arg1, arg2, arg3);
00697     }
00698     // array indices
00699     else if (!strcmp (n, "array"))
00700     {
00701         int len = strlen (args->toString ()) + 3 + nparam;
00702         txt = (char *) malloc (len);
00703         sprintf (txt, "%s[", args->toString ());
00704         for (node * arg = args->getNext (); arg != NULL; arg = arg->getNext ())
00705         {
00706             char * str = arg->toString ();
00707             txt = (char *) realloc (txt, len += strlen (str));
00708             strcat (txt, str);
00709             if (arg->getNext ()) strcat (txt, ",");
00710         }
00711         strcat (txt, "]");
00712     }
00713     // vectors and matrices
00714     else if (!strcmp (n, "vector") || !strcmp (n, "matrix"))
00715     {
00716         int len = 3 + nparam;
00717         txt = (char *) malloc (len);
00718         sprintf (txt, "[");
00719         for (node * arg = args; arg != NULL; arg = arg->getNext ())
00720         {
00721             if (arg->getType () == TAG_CHAR)
00722             {
00723                 txt = (char *) realloc (txt, len++);
00724                 strcat (txt, ";");
00725             }
00726             else
00727             {
00728                 char * str = arg->toString ();
00729                 txt = (char *) realloc (txt, len += strlen (str));
00730                 strcat (txt, str);
00731                 node * next = arg->getNext ();
00732                 if (next && next->getType () != TAG_CHAR) strcat (txt, ",");
00733             }
00734         }
00735         strcat (txt, "]");
00736     }
00737     // unary and n-ary operations here
00738     else
00739     {
00740         int len = strlen (n) + 3 + nparam;
00741         txt = (char *) malloc (len);
00742         sprintf (txt, "%s(", n);
00743         for (node * arg = args; arg != NULL; arg = arg->getNext ())
00744         {
00745             char * str = arg->toString ();
00746             txt = (char *) realloc (txt, len += strlen (str));
00747             strcat (txt, str);
00748             if (arg->getNext ()) strcat (txt, ",");
00749         }
00750         strcat (txt, ")");
00751     }
00752     return txt;
00753 }
00754 
00755 // Adds the arguments of the application to the list of dependencies.
00756 void application::addDependencies (strlist * depends)
00757 {
00758     for (node * arg = args; arg != NULL; arg = arg->getNext ())
00759     {
00760         arg->checkee = checkee;
00761         arg->addDependencies (depends);
00762     }
00763 }
00764 
00765 /* This function goes through the arguments of an application and
00766    evaluates their return types. */
00767 void application::evalTypeArgs (void)
00768 {
00769     for (node * arg = args; arg != NULL; arg = arg->getNext ())
00770     {
00771         // Skip evaluating generated reference variables.
00772         if (arg->getTag () == REFERENCE)
00773             if (checker::isGenerated (R (arg)->n))
00774                 continue;
00775         // Evaluate the type of argument.
00776         arg->evalType ();
00777     }
00778 }
00779 
00780 
00781 // gperfapphash has register inside, ignore warning
00782 #if defined(__clang__)
00783 #pragma clang diagnostic push
00784 #pragma clang diagnostic ignored "-Wdeprecated-register"
00785 #endif
00786 #include "gperfapphash.cpp"
00787 
00788 /* The function creates a hash key for the given type of
00789    application. */
00790 char * application::createKey (void)
00791 {
00792     char * key = (char *) calloc (1, strlen (n) + nargs * 3 + 5);
00793     strcat (key, n);
00794     for (node * arg = args; arg != NULL; arg = arg->getNext ())
00795     {
00796         strcat (key, "_");
00797         strcat (key, checker::tag2key (arg->getType ()));
00798     }
00799     return key;
00800 }
00801 
00802 /* This function returns the return type of the application using a
00803    gperf-generated hash. */
00804 int application::evalTypeFast (void)
00805 {
00806     char * key = createKey ();
00807     struct appindex * idx = gperfapphash::get (key, strlen (key));
00808     free (key);
00809     if (idx != NULL)
00810     {
00811         application_t * app = &applications[idx->index];
00812         if (app->eval)
00813         {
00814             eval = app->eval;
00815             setType (app->retval);
00816         }
00817     }
00818     return getType ();
00819 }
00820 
00821 // Macro to identify ddx() application.
00822 #define isDDX() (nargs == 2 && !strcmp (n, "ddx") && \
00823                  args->getNext()->getTag () == REFERENCE)
00824 
00825 /* Returns the type of application and applies the appropriate
00826    evaluation function if any. */
00827 int application::evalType (void)
00828 {
00829     // Evaluate type of ddx().
00830     if (isDDX ())
00831     {
00832         args->evalType ();
00833         if (!ddx) ddx = args->differentiate (R(args->getNext())->n);
00834         setType (ddx->evalType ());
00835         return getType ();
00836     }
00837     setType (TAG_UNKNOWN);
00838     // Evaluate type of arguments.
00839     evalTypeArgs ();
00840     // Find an appropriate differentiator.
00841     findDifferentiator ();
00842     // Try the fast method.
00843     if (evalTypeFast () != TAG_UNKNOWN) return getType ();
00844 
00845     // Go through the list of available applications.
00846     for (int i = 0; applications[i].application != NULL; i++)
00847     {
00848         application_t * app = &applications[i];
00849         // The correct application?
00850         if (!strcmp (n, app->application))
00851         {
00852             int nr = 0;
00853             if (app->nargs >= 0)
00854             {
00855                 // The correct number of arguments?
00856                 if (nargs != app->nargs) continue;
00857                 // The correct types of arguments?
00858                 for (node * arg = args; arg != NULL; arg = arg->getNext (), nr++)
00859                 {
00860                     if (arg->getTag () == REFERENCE)
00861                         // Skip checking generated reference variables.
00862                         if (checker::isGenerated (R (arg)->n))
00863                             continue;
00864                     // Evaluate and check the type of argument.
00865                     if (!(arg->getType () & app->args[nr]))
00866                     {
00867                         nr = -1;
00868                         break;
00869                     }
00870                 }
00871                 if (nr == -1) continue;
00872             }
00873             // A valid application function?
00874             if (app->eval == NULL) continue;
00875             // Everything just fine here.
00876             eval = app->eval;
00877             setType (app->retval);
00878             break;
00879         }
00880     }
00881     // Emit error message if necessary.
00882     if (getType () == TAG_UNKNOWN)
00883     {
00884         logprint (LOG_ERROR, "checker error, no appropriate function for `%s'"
00885                   " found\n", toString ());
00886     }
00887     return getType ();
00888 }
00889 
00890 /* This function returns zero if the applications differentiation
00891    function could be found and otherwise non-zero. */
00892 int application::findDifferentiator (void)
00893 {
00894     for (int i = 0; differentiations[i].application != NULL; i++)
00895     {
00896         if (!strcmp (n, differentiations[i].application) &&
00897                 nargs == differentiations[i].nargs)
00898         {
00899             derive = differentiations[i].derive;
00900             return 0;
00901         }
00902     }
00903     return -1;
00904 }
00905 
00906 /* This function runs the actual evaluation function and the returns
00907    the result. */
00908 constant * application::evaluate (void)
00909 {
00910     // Evaluate ddx() function.
00911     if (isDDX ())
00912     {
00913         delete getResult ();
00914         setResult (C (ddx->evaluate()->recreate ()));
00915         return getResult ();
00916     }
00917 
00918     int errors = 0;
00919     strlist * apreps = new strlist ();
00920 
00921     // first evaluate each argument
00922     for (node * arg = args; arg != NULL; arg = arg->getNext ())
00923     {
00924         // FIXME: Can save evaluation of already evaluated equations?
00925         if (arg->evaluated == 0 || 1)
00926         {
00927             arg->solvee = solvee;
00928             arg->evaluate ();
00929             if (arg->getResult () == NULL)
00930             {
00931                 if (arg->getTag () == REFERENCE)
00932                 {
00933                     logprint (LOG_ERROR, "evaluate error, no such generated variable "
00934                               "`%s'\n", arg->toString ());
00935                 }
00936                 else
00937                 {
00938                     logprint (LOG_ERROR, "evaluate error, unable to evaluate "
00939                               "`%s'\n", arg->toString ());
00940                 }
00941                 errors++;
00942             }
00943             else
00944             {
00945                 // inherit drop/prep dependencies
00946                 if (arg->getResult()->dropdeps)
00947                 {
00948                     strlist * preps = arg->getResult()->getPrepDependencies ();
00949                     // recall longest prep dependencies' list of arguments
00950                     if (preps && (preps->length () > apreps->length ()))
00951                     {
00952                         delete apreps;
00953                         apreps = new strlist (*preps);
00954                     }
00955                 }
00956                 arg->evaluated++;
00957             }
00958         }
00959     }
00960 
00961     // then evaluate application itself
00962     if (!errors)
00963     {
00964         // delete previous result if necessary
00965         delete getResult ();
00966         // then evaluate the application
00967         setResult (eval (C (args)));
00968         // check the returned type once again
00969         if (getResult()->getType () != getType ())
00970         {
00971             logprint (LOG_ERROR, "evaluate error, function `%s' returned invalid "
00972                       "constant type\n", toString ());
00973         }
00974     }
00975 
00976     // inherit prep dependencies of arguments if necessary
00977     if (!getResult()->dropdeps && apreps->length () > 0)
00978     {
00979         getResult()->dropdeps = 1;
00980         getResult()->appendPrepDependencies (apreps);
00981     }
00982     delete apreps;
00983 
00984     return getResult ();
00985 }
00986 
00987 // Returns the derivative of an application.
00988 node * application::differentiate (char * derivative)
00989 {
00990     if (isDDX ())
00991     {
00992         return ddx->differentiate (derivative);
00993     }
00994     if (derive)
00995         return derive (this, derivative);
00996     return recreate ();
00997 }
00998 
00999 // Constructor creates an untyped instance of the equation node class.
01000 node::node ()
01001 {
01002     tag = UNKNOWN;
01003     setType(TAG_UNKNOWN);
01004     dropdeps = output = evaluated = evalPossible = cycle = duplicate = skip = 0;
01005     next = NULL;
01006     dependencies = NULL;
01007     dataDependencies = NULL;
01008     dropDependencies = NULL;
01009     prepDependencies = NULL;
01010     txt = NULL;
01011     res = NULL;
01012     instance = NULL;
01013     solvee = NULL;
01014     checkee = NULL;
01015 }
01016 
01017 // This constructor creates an typed instance of the equation node class.
01018 node::node (int type)
01019 {
01020     tag = type;
01021     setType(TAG_UNKNOWN);
01022     dropdeps = output = evaluated = evalPossible = cycle = duplicate = skip = 0;
01023     next = NULL;
01024     dependencies = NULL;
01025     dataDependencies = NULL;
01026     dropDependencies = NULL;
01027     prepDependencies = NULL;
01028     txt = NULL;
01029     res = NULL;
01030     instance = NULL;
01031     solvee = NULL;
01032     checkee = NULL;
01033 }
01034 
01035 /* This copy constructor creates a instance of the node class based on
01036    the given node. */
01037 node::node (const node & o)
01038 {
01039     tag = o.tag;
01040     type = o.type;
01041     dropdeps = output = evaluated = evalPossible = cycle = duplicate = skip = 0;
01042     next = NULL;
01043     dependencies = NULL;
01044     dataDependencies = NULL;
01045     dropDependencies = NULL;
01046     prepDependencies = NULL;
01047     txt = NULL;
01048     res = NULL;
01049     instance = NULL;
01050     solvee = o.solvee;
01051     checkee = o.checkee;
01052 }
01053 
01054 // Destructor deletes an instance of the equation node class.
01055 node::~node ()
01056 {
01057     delete dependencies;
01058     delete dataDependencies;
01059     delete dropDependencies;
01060     delete prepDependencies;
01061     free (txt);
01062     free (instance);
01063 }
01064 
01065 // Sets the instance name where the node occurred.
01066 void node::setInstance (const char * n)
01067 {
01068     free (instance);
01069     instance = n ? strdup (n) : NULL;
01070 }
01071 
01072 // Returns the instance name where the node occurred.
01073 char * node::getInstance (void)
01074 {
01075     return instance;
01076 }
01077 
01078 /* The function applies the instance name of the current equation node
01079    to any following node within the list up to the node with a valid
01080    instance name. */
01081 void node::applyInstance (void)
01082 {
01083     char * i = getInstance ();
01084     for (node * n = getNext (); n != NULL; n = n->getNext ())
01085     {
01086         if (n->getInstance () == NULL)
01087             n->setInstance (i);
01088         else
01089             break;
01090     }
01091 }
01092 
01093 // Counts the number of equations node attached to the node.
01094 int node::count (void)
01095 {
01096     int c = 0;
01097     for (node * n = this; n != NULL; n = n->getNext ()) c++;
01098     return c;
01099 }
01100 
01101 // Appends yet another node to the equation node object.
01102 void node::append (node * last)
01103 {
01104     if (!last) return;
01105     node * n;
01106     for (n = this; n->getNext () != NULL; n = n->getNext ()) ;
01107     last->setNext (NULL);
01108     n->setNext (last);
01109 }
01110 
01111 // Appends othere nodes to the equation node object.
01112 void node::appendNodes (node * last)
01113 {
01114     if (!last) return;
01115     node * n;
01116     for (n = this; n->getNext () != NULL; n = n->getNext ()) ;
01117     n->setNext (last);
01118 }
01119 
01120 // Returns the equation node at the given argument position.
01121 node * node::get (int pos)
01122 {
01123     node * n = this;
01124     for (int i = 0; i < pos && n != NULL; n = n->getNext (), i++) ;
01125     return n;
01126 }
01127 
01128 // Sets the constant equation node result.
01129 void node::setResult (constant * r)
01130 {
01131     res = r;
01132 }
01133 
01134 // Returns the constant equation node at the given argument position.
01135 constant * node::getResult (int pos)
01136 {
01137     node * n = this;
01138     for (int i = 0; i < pos && n != NULL; n = n->getNext (), i++) ;
01139     return n ? n->getResult () : NULL;
01140 }
01141 
01142 /* Returns a double value depending on the type of the equation nodes
01143    result type. */
01144 nr_double_t node::getResultDouble (void)
01145 {
01146     constant * c = getResult ();
01147     if (c != NULL)
01148     {
01149         switch (getType ())
01150         {
01151         case TAG_DOUBLE:
01152             return c->d;
01153             break;
01154         case TAG_COMPLEX:
01155             return real (*(c->c));
01156             break;
01157         case TAG_BOOLEAN:
01158             return c->b ? 1.0 : 0.0;
01159             break;
01160         }
01161     }
01162     return 0.0;
01163 }
01164 
01165 /* Returns a complex value depending on the type of the equation nodes
01166    result type. */
01167 nr_complex_t node::getResultComplex (void)
01168 {
01169     constant * c = getResult ();
01170     if (c != NULL)
01171     {
01172         switch (getType ())
01173         {
01174         case TAG_DOUBLE:
01175             return nr_complex_t (c->d, 0.0);
01176             break;
01177         case TAG_COMPLEX:
01178             return *(c->c);
01179             break;
01180         case TAG_BOOLEAN:
01181             return c->b ? 1.0 : 0.0;
01182             break;
01183         }
01184     }
01185     return 0.0;
01186 }
01187 
01188 /* Returns an immediate vector depending on the type of the equation
01189    nodes result type. */
01190 qucs::vector node::getResultVector (void)
01191 {
01192     constant * c = getResult ();
01193     qucs::vector v;
01194     if (c != NULL)
01195     {
01196         switch (getType ())
01197         {
01198         case TAG_MATRIX:
01199         {
01200             int ro, co, n = 0;
01201             v = qucs::vector (c->m->getRows () * c->m->getCols ());
01202             for (co = 0; co < c->m->getCols (); co++)
01203                 for (ro = 0; ro < c->m->getRows (); ro++)
01204                     v (n++) = c->m->get (ro, co);
01205         }
01206         break;
01207         case TAG_VECTOR:
01208             v = *(c->v);
01209             break;
01210         case TAG_DOUBLE:
01211             v = qucs::vector (1);
01212             v (0) = c->d;
01213             break;
01214         case TAG_COMPLEX:
01215             v = qucs::vector (1);
01216             v (0) = *(c->c);
01217             break;
01218         case TAG_BOOLEAN:
01219             v = qucs::vector (1);
01220             v (0) = c->b ? 1.0 : 0.0;
01221             break;
01222         }
01223     }
01224     return v;
01225 }
01226 
01227 // Assigns the dependency list to the equation node object.
01228 void node::setDependencies (strlist * depends)
01229 {
01230     delete dependencies;
01231     dependencies = depends;
01232 }
01233 
01234 // Returns the dependency list of the equation node object.
01235 strlist * node::getDependencies (void)
01236 {
01237     return dependencies;
01238 }
01239 
01240 /* This function recursively finds the variable dependencies for each
01241    equation initially passed to the equation checker and returns the
01242    list of variable dependencies regarding this equation instance.
01243    The caller is responsible for deleting the returned string list
01244    object. */
01245 strlist * node::recurseDependencies (checker * check, strlist * deps)
01246 {
01247 
01248     strlist * res, * sub = NULL;
01249 
01250     /* The abort condition for recursion first. */
01251     if (deps->contains (A(this)->result))
01252     {
01253         res = new strlist (*deps);
01254         cycle = 1;
01255         return res;
01256     }
01257 
01258     /* Go through the list of passed dependency variables. */
01259     for (int i = 0; i < deps->length (); i++)
01260     {
01261         char * var = deps->get (i);
01262         node * child = check->findEquation (check->equations, var);
01263         /* Check each child equation. */
01264         if (child != NULL)
01265         {
01266             if (child->cycle == 0)
01267             {
01268                 strlist * cdeps = child->getDependencies ();
01269                 /* And append the dependencies of the child equation. */
01270                 if (cdeps->length () > 0)
01271                 {
01272                     res = strlist::join (sub, cdeps);
01273                     delete sub;
01274                     sub = res;
01275                 }
01276             }
01277             /* If any child is cyclic, the parent is too. */
01278             else
01279             {
01280                 cycle = 1;
01281             }
01282         }
01283     }
01284 
01285     /* Recurse once again if the child equations revealed any more
01286        dependencies. */
01287     if (cycle && sub && sub->length () > 0)
01288     {
01289         res = recurseDependencies (check, sub);
01290         delete sub;
01291         sub = res;
01292     }
01293 
01294     /* Return the result. */
01295     res = strlist::join (deps, sub);
01296     delete (sub);
01297     return res;
01298 }
01299 
01300 /* The function adds the given data dependency to the list of
01301    dependencies which are going to be dropped during the data
01302    export. */
01303 void node::addDropDependencies (char * dep)
01304 {
01305     if (dropDependencies == NULL) dropDependencies = new strlist ();
01306     dropDependencies->add (dep);
01307 }
01308 
01309 /* The function adds the given data dependency to the list of
01310    dependencies which are going to be prepend. */
01311 void node::addPrepDependencies (char * dep)
01312 {
01313     if (prepDependencies == NULL) prepDependencies = new strlist ();
01314     prepDependencies->add (dep);
01315 }
01316 
01317 /* This function appends the given dependency list to the list of
01318    dependencies which are going to be prepend. */
01319 void node::appendPrepDependencies (strlist * deps)
01320 {
01321     if (prepDependencies == NULL) prepDependencies = new strlist ();
01322     prepDependencies->append (deps);
01323 }
01324 
01325 /* The function sets the data dependency list of the equation node. */
01326 void node::setDataDependencies (strlist * deps)
01327 {
01328     delete dataDependencies;
01329     dataDependencies = deps ? new strlist (*deps) : NULL;
01330 }
01331 
01332 /* Evaluates the equation node and applies the data dependencies. */
01333 constant * node::calculate (void)
01334 {
01335     constant * res = evaluate ();
01336     if (getResult ())
01337     {
01338         strlist * deps = solvee->collectDataDependencies (this);
01339         getResult()->setDataDependencies (deps);
01340         delete deps;
01341     }
01342     else
01343     {
01344         qucs::exception * e = new qucs::exception (EXCEPTION_MATH);
01345         e->setText ("evaluator exception");
01346         throw_exception (e);
01347     }
01348     return res;
01349 }
01350 
01351 /* Collects the equation dependencies for a specific node. */
01352 strlist * node::collectDependencies (void)
01353 {
01354     strlist * depends = new strlist ();
01355     addDependencies (depends);
01356     setDependencies (checker::foldDependencies (depends));
01357     return getDependencies ();
01358 }
01359 
01360 /* Collects the data dependencies for a specific node. */
01361 strlist * node::collectDataDependencies (void)
01362 {
01363     strlist * deps = getResult()->getDataDependencies ();
01364     if (deps)
01365     {
01366         // data dependencies already collected
01367         setDataDependencies (deps);
01368         return deps;
01369     }
01370     // collect equation dependencies
01371     if (!getDependencies ())
01372         collectDependencies ();
01373     if (solvee)
01374     {
01375         // finally collect the appropriate data dependencies
01376         deps = solvee->collectDataDependencies (this);
01377         setDataDependencies (deps);
01378         delete deps;
01379     }
01380     return getDataDependencies ();
01381 }
01382 
01383 // Constructor creates an instance of the checker class.
01384 checker::checker ()
01385 {
01386     defs = NULL;
01387     equations = NULL;
01388     consts = false;
01389 }
01390 
01391 // Destructor deletes an instance of the checker class.
01392 checker::~checker ()
01393 {
01394     node * next;
01395     for (node * eqn = equations; eqn != NULL; eqn = next)
01396     {
01397         next = eqn->getNext ();
01398         delete eqn;
01399     }
01400 }
01401 
01402 // Local macro definition to go through the list of equations.
01403 #define foreach_equation(eqn)                        \
01404   for (assignment * (eqn) = A (equations);           \
01405        (eqn) != NULL; (eqn) = A ((eqn)->getNext ()))
01406 
01407 /* The function goes through the list of equations assigned to the
01408    checker and applies the dependency list. */
01409 void checker::collectDependencies (void)
01410 {
01411     foreach_equation (eqn)
01412     {
01413         collectDependencies (eqn);
01414     }
01415 }
01416 
01417 // Creates dependency list of given equation node.
01418 void checker::collectDependencies (node * eqn)
01419 {
01420     strlist * depends = new strlist ();
01421     eqn->addDependencies (depends);
01422     eqn->setDependencies (depends);
01423 }
01424 
01425 /* The following function goes through the list of equations and
01426    checks whether there is any kind of 'Export="yes|no"' assignment in
01427    it.  Depending on the value the referred equation results are saved
01428    into the dataset or not. */
01429 int checker::checkExport (void)
01430 {
01431     int errors = 0;
01432     assignment * next;
01433     // go through all equations
01434     for (assignment * eqn = A (equations); eqn != NULL; eqn = next)
01435     {
01436         next = A (eqn->getNext ());
01437         // 'Export' equation found ?
01438         if (!strcmp (eqn->result, "Export"))
01439         {
01440             // is the type and value correct ?
01441             if (eqn->body->getTag () != REFERENCE ||
01442                     (strcmp (R (eqn->body)->n, "yes") &&
01443                      strcmp (R (eqn->body)->n, "no")))
01444             {
01445                 logprint (LOG_ERROR, "checker error, variable `%s' alternatives "
01446                           "are `yes' or `no'\n", eqn->result);
01447                 errors++;
01448             }
01449             else
01450             {
01451                 int flag = !strcmp (R (eqn->body)->n, "yes") ? 1 : 0;
01452                 char * i = eqn->getInstance ();
01453                 int found = 0;
01454                 // set output flag for each equation with the same instance name
01455                 foreach_equation (res)
01456                 {
01457                     if (!strcmp (res->getInstance (), i))
01458                         res->output = flag;
01459                     if (!strcmp (res->result, "Export") &&
01460                             !strcmp (res->getInstance (), i))
01461                     {
01462                         found++;
01463                     }
01464                 }
01465                 // check for duplicate definitions of 'Export'
01466                 if (found > 1)
01467                 {
01468                     logprint (LOG_ERROR, "checker error, variable `%s' "
01469                               "occurred %dx in `Eqn:%s'\n", eqn->result, found, i);
01470                     errors++;
01471                 }
01472                 // drop the 'Export' equation being useless now
01473                 dropEquation (eqn);
01474                 delete eqn;
01475             }
01476         }
01477     }
01478     return errors;
01479 }
01480 
01481 // Logs the textual representation of all equations.
01482 void checker::list (void)
01483 {
01484     for (node * eqn = equations; eqn != NULL; eqn = eqn->getNext ())
01485     {
01486         logprint (LOG_STATUS, "%s", eqn->evalPossible ? "!" : "?");
01487         logprint (LOG_STATUS, "%s", eqn->evalPossible ?
01488                   (eqn->getType () == TAG_UNKNOWN ? "U!" :
01489                    eqn->getType () == TAG_DOUBLE  ? "D!" :
01490                    eqn->getType () == TAG_BOOLEAN ? "B!" :
01491                    eqn->getType () == TAG_COMPLEX ? "C!" :
01492                    eqn->getType () == TAG_VECTOR  ? "V!" :
01493                    eqn->getType () == TAG_CHAR    ? "CHR!" :
01494                    eqn->getType () == TAG_STRING  ? "STR!" :
01495                    eqn->getType () == TAG_MATVEC  ? "MV!" :
01496                    eqn->getType () == TAG_RANGE   ? "R!" :
01497                    eqn->getType () == TAG_MATRIX  ? "M!" : "?!") : "");
01498         eqn->print ();
01499         logprint (LOG_STATUS, "\n");
01500     }
01501 }
01502 
01503 /* Checks whether the variable name is a generated name which is
01504    identified by a ".[0-9]{4}" suffix. */
01505 int checker::isGenerated (char * var)
01506 {
01507     int len = strlen (var);
01508     if (len > 5)
01509     {
01510         if (isdigit (var[len-1]) && isdigit (var[len-2]) &&
01511                 isdigit (var[len-3]) && isdigit (var[len-4]) &&
01512                 var[len-5] == '.')
01513         {
01514             return 1;
01515         }
01516     }
01517     return 0;
01518 }
01519 
01520 /* This function checks whether the variable references could be
01521    resolved within the equations and returns zero if so. */
01522 int checker::findUndefined (int noundefined)
01523 {
01524     int err = 0;
01525     strlist * idents = getVariables ();
01526 
01527     foreach_equation (eqn)
01528     {
01529         strlist * depends = eqn->getDependencies ();
01530         for (int i = 0; i < depends->length (); i++)
01531         {
01532             char * var = depends->get (i);
01533             if (idents->contains (var) <= 0)
01534             {
01535                 // check if this is a circuit property
01536                 if (defs)
01537                 {
01538                     node * eqn = findProperty (var);
01539                     if (eqn)
01540                     {
01541                         idents->append (var);
01542                         eqn->collectDependencies ();
01543                         continue;
01544                     }
01545                 }
01546                 // give an error
01547                 if (noundefined)
01548                 {
01549                     if (isGenerated (var)) // skip probably generated variables
01550                         continue;
01551                     logprint (LOG_ERROR, "checker error, undefined variable `%s' in "
01552                               "equation `%s'\n", var, eqn->result);
01553                     err++;
01554                 }
01555                 // give a notice only
01556                 else
01557                 {
01558                     logprint (LOG_STATUS, "checker notice, variable `%s' in "
01559                               "equation `%s' not yet defined\n", var, eqn->result);
01560                 }
01561             }
01562         }
01563     }
01564     delete idents;
01565     return err;
01566 }
01567 
01568 /* This function tries to find the given variable name which occurred
01569    in an equation dependency in the netlist.  If there is such a
01570    circuit property it returns a new assignment equation. */
01571 node * checker::findProperty (char * var)
01572 {
01573 
01574     node * eqn = NULL;
01575     int found = 0;
01576 
01577     // split into instance and property name
01578     char * ret, * inst, * prop;
01579     if ((ret = strchr (var, '.')) != NULL)
01580     {
01581         int len = ret - var;
01582         inst = (char *) calloc (1, len + 1);
01583         memcpy (inst, var, len);
01584         prop = &var[len + 1];
01585     }
01586     else return NULL;
01587 
01588     // go through list of circuit elements
01589     for (struct definition_t * def = defs; def; def = def->next)
01590     {
01591         if (!strcmp (def->instance, inst))
01592         {
01593             for (struct pair_t * pair = def->pairs; pair; pair = pair->next)
01594             {
01595                 if (!strcmp (pair->key, prop))
01596                 {
01597                     if (++found == 1)
01598                     {
01599                         if (pair->value->ident != NULL)
01600                         {
01601                             // reference
01602                             eqn = createReference ("#property", var, pair->value->ident);
01603                         }
01604                         else
01605                         {
01606                             // value
01607                             eqn = createDouble ("#property", var, pair->value->value);
01608                         }
01609                     }
01610                 }
01611             }
01612         }
01613     }
01614     if (found > 1)
01615     {
01616         logprint (LOG_ERROR, "checker error, desired property variable `%s' found "
01617                   "%dx, is not unique'\n", var, found);
01618         delete eqn;
01619         eqn = NULL;
01620     }
01621     else if (found == 1)
01622         appendEquation (eqn);
01623     free (inst);
01624     return eqn;
01625 }
01626 
01627 /* Go through the list of equations and store the left hand side in
01628    a string list. */
01629 strlist * checker::getVariables (void)
01630 {
01631     strlist * idents = new strlist ();
01632     foreach_equation (eqn)
01633     {
01634         idents->add (eqn->result);
01635     }
01636     return idents;
01637 }
01638 
01639 /* Finds duplicate equation definitions in the list of equations,
01640    emits appropriate error messages and returns zero if everything is
01641    ok. */
01642 int checker::findDuplicate (void)
01643 {
01644     int err = 0;
01645     strlist * idents = getVariables ();
01646     strlist * dups = new strlist ();
01647 
01648     // Collect duplicate entries.
01649     foreach_equation (eqn)
01650     {
01651         if (!eqn->duplicate && dups->contains (eqn->result) == 0)
01652         {
01653             eqn->duplicate = idents->contains (eqn->result);
01654             dups->add (eqn->result);
01655         }
01656         else
01657         {
01658             eqn->duplicate = 1;
01659         }
01660     }
01661     // Emit appropriate error messages.
01662     foreach_equation (eqndups)
01663     {
01664         if (eqndups->duplicate > 1)
01665         {
01666             logprint (LOG_ERROR, "checker error, variable `%s' assigned %dx\n",
01667                       eqndups->result, eqndups->duplicate);
01668             err++;
01669         }
01670     }
01671     delete idents;
01672     delete dups;
01673     return err;
01674 }
01675 
01676 /* The function returns the equation resulting in the passed variable
01677    or NULL if there is no such equation.  The function looks through
01678    the passed equation root. */
01679 node * checker::findEquation (node * root, const char * const n)
01680 {
01681     for (node * eqn = root; eqn != NULL; eqn = eqn->getNext ())
01682     {
01683         if (!strcmp (A(eqn)->result, n))
01684           return eqn;
01685     }
01686     return NULL;
01687 }
01688 
01689 /* The function returns the equation resulting in the passed variable
01690    or NULL if there is no such equation. */
01691 node * checker::findEquation (const char * const n) const
01692 {
01693     foreach_equation (eqn)
01694     {
01695         if (!strcmp (A(eqn)->result, n)) return eqn;
01696     }
01697     return NULL;
01698 }
01699 
01700 /* This function display the error messages due to equation cycles and
01701    returns zero if there are no such cycles. */
01702 int checker::detectCycles (void)
01703 {
01704     int err = 0;
01705 
01706     foreach_equation (eqn)
01707     {
01708         strlist * deps = eqn->recurseDependencies (this, eqn->getDependencies ());
01709         if (deps->contains (eqn->result) || eqn->cycle)
01710         {
01711             logprint (LOG_ERROR, "checker error, cyclic definition of variable "
01712                       "`%s' involves: `%s'\n", eqn->result, deps->toString ());
01713             err++;
01714             delete deps;
01715         }
01716         else
01717         {
01718             // Set folded variable dependencies.
01719             deps = foldDependencies (deps);
01720             eqn->setDependencies (deps);
01721         }
01722     }
01723     return err;
01724 }
01725 
01726 /* The function returns a variable dependency list with unique entries
01727    only.  The given string list gets deleted and a new one is created
01728    and returned. */
01729 strlist * checker::foldDependencies (strlist * deps)
01730 {
01731     strlist * res = new strlist ();
01732     for (int i = 0; deps && i < deps->length (); i++)
01733     {
01734         char * var = deps->get (i);
01735         if (!res->contains (var)) res->append (var);
01736     }
01737     delete deps;
01738     return res;
01739 }
01740 
01741 // The function appends the given last node to the given equation root.
01742 node * checker::appendEquation (node * root, node * last)
01743 {
01744     last->setNext (NULL);
01745     if (root != NULL)
01746     {
01747         node * eqn = lastEquation (root);
01748         eqn->setNext (last);
01749     }
01750     else root = last;
01751     return root;
01752 }
01753 
01754 // Returns the last node in the given equation root.
01755 node * checker::lastEquation (node * root)
01756 {
01757     node * eqn;
01758     for (eqn = root; eqn && eqn->getNext () != NULL; eqn = eqn->getNext ()) ;
01759     return eqn;
01760 }
01761 
01762 // Removes the given equation node from the list of known equations.
01763 void checker::dropEquation (node * eqn)
01764 {
01765     if (eqn == equations)
01766     {
01767         equations = eqn->getNext ();
01768     }
01769     else
01770     {
01771         node * prev;
01772         for (prev = equations; prev->getNext () != eqn; prev = prev->getNext()) ;
01773         prev->setNext (eqn->getNext ());
01774     }
01775 }
01776 
01777 /* This function reorders the list of equations.  The new order can be
01778    used to evaluate the list step by step.  Each equation being
01779    evaluable is properly marked, remaining equations are appended. */
01780 void checker::reorderEquations (void)
01781 {
01782     node * root = NULL, * next, * last;
01783 
01784     // Go through the list of equations.
01785     for (node * eqn = equations; eqn != NULL; eqn = next)
01786     {
01787         strlist * deps = eqn->getDependencies ();
01788         int i, found, gens;
01789         next = eqn->getNext ();
01790         /* Check whether the variable dependencies can be found in
01791            previous equations. */
01792         for (found = gens = i = 0; i < deps->length (); i++)
01793         {
01794             char * var = deps->get (i);
01795             if (findEquation (root, var) != NULL) found++;
01796             if (isGenerated (var)) gens++;
01797         }
01798         // Yes.
01799         if (found == (deps->length () - gens))
01800         {
01801             /* Remove the equation from the current list and append it to
01802                the new list. */
01803             dropEquation (eqn);
01804             root = appendEquation (root, eqn);
01805             eqn->evalPossible = 1;
01806             // Now start over from the beginning.
01807             next = equations;
01808         }
01809     }
01810     // Any remaining equations get appended.
01811     if (root != NULL)
01812     {
01813         last = lastEquation (root);
01814         last->setNext (equations);
01815         equations = root;
01816     }
01817 }
01818 
01819 
01820 /* The function passes a list of equations to the checker and also
01821    passes the checker instance to each equation. */
01822 void checker::setEquations (node * eqns)
01823 {
01824     equations = eqns;
01825     foreach_equation (eqn)
01826     {
01827         eqn->checkee = this;
01828     }
01829 }
01830 
01831 /* The function evaluates the types for each equation and recursively
01832    checks the availability of the appropriate function. */
01833 int checker::applyTypes (void)
01834 {
01835     int err = 0;
01836     foreach_equation (eqn)
01837     {
01838         if (eqn->evalPossible)
01839         {
01840             if (eqn->evalType () == TAG_UNKNOWN)
01841             {
01842                 logprint (LOG_ERROR, "checker error, type of equation `%s' "
01843                           "undefined\n", eqn->result);
01844                 err++;
01845             }
01846         }
01847         else break;
01848     }
01849     return err;
01850 }
01851 
01852 /* This function is the checker routine for a parsed equations.  It
01853    returns zero on success or non-zero if the parsed equations
01854    contained errors. */
01855 int checker::check (int noundefined)
01856 {
01857     int err = 0;
01858     err += checkExport ();
01859     collectDependencies ();
01860     err += findUndefined (noundefined);
01861     err += findDuplicate ();
01862     err += detectCycles ();
01863     reorderEquations ();
01864     err += applyTypes ();
01865 #if DEBUG && 0
01866     list ();
01867 #endif /* DEBUG */
01868     return err;
01869 }
01870 
01871 // Constructor creates an instance of the solver class.
01872 solver::solver (checker * c)
01873 {
01874     equations = NULL;
01875     data = NULL;
01876     generated = 0;
01877     checkee = c;
01878 }
01879 
01880 // Destructor deletes an instance of the solver class.
01881 solver::~solver ()
01882 {
01883     node * next;
01884     for (node * eqn = equations; eqn != NULL; eqn = next)
01885     {
01886         next = eqn->getNext ();
01887         delete eqn;
01888     }
01889 }
01890 
01891 // The function finally evaluates each equation passed to the solver.
01892 void solver::evaluate (void)
01893 {
01894     foreach_equation (eqn)
01895     {
01896         // FIXME: Can save evaluation of already evaluated equations?
01897         if (eqn->evalPossible && !eqn->skip /* && eqn->evaluated == 0 */)
01898         {
01899             // exception handling around evaluation
01900             try_running ()
01901             {
01902                 eqn->solvee = this;
01903                 eqn->calculate ();
01904             }
01905             // handle evaluation exceptions
01906             catch_exception ()
01907             {
01908             default:
01909                 estack.print ("evaluation");
01910                 break;
01911             }
01912             eqn->evaluated++;
01913 #if DEBUG && 0
01914             // print equation results
01915             logprint (LOG_STATUS, "%s = %s\n", A(eqn)->result,
01916                       eqn->getResult () ? eqn->getResult()->toString () : "error");
01917 #if TESTING_DERIVATIVE || 0
01918             // print equation
01919             logprint (LOG_STATUS, "%s\n", eqn->toString ());
01920             // print derivations
01921             logprint (LOG_STATUS, "%s\n", eqn->differentiate("x")->toString ());
01922 #endif
01923 #endif
01924         }
01925     }
01926 }
01927 
01928 /* This function adds the given dataset vector to the set of equations
01929    stored in the equation solver. */
01930 node * solver::addEquationData (qucs::vector * v, bool ref)
01931 {
01932     constant * con = new constant (TAG_VECTOR);
01933     con->v = v;
01934     con->dataref = ref;
01935     assignment * assign = new assignment ();
01936     assign->result = strdup (v->getName ());
01937     assign->body = con;
01938     assign->setNext (equations);
01939     equations = assign;
01940     return assign;
01941 }
01942 
01943 /* The function puts the given vector into the equation set.  The
01944    resulting data vector is going to be copied and exported - given a
01945    generated name based upon the second argument. */
01946 node * solver::addGeneratedEquation (qucs::vector * v, const char * n)
01947 {
01948     // create generated name
01949     char * str = (char *) malloc (strlen (n) + 6);
01950     sprintf (str, "%s.%04d", n, ++generated);
01951     // copy data vector
01952     qucs::vector * c = new qucs::vector (*v);
01953     c->setName (str);
01954     // put vector into the equation set and ensure data export as
01955     // independent variable
01956     node * res = addEquationData (c);
01957     res->setInstance ("#generated");
01958     res->setDependencies (new strlist ());
01959     res->evalType ();
01960     res->solvee = this;
01961     res->evaluate ();
01962     res->output = 1;
01963     free (str);
01964     return res;
01965 }
01966 
01967 /* Depending on the type of equation result the function converts the
01968    given equation node to one or more valid dataset vector(s). */
01969 qucs::vector * solver::dataVector (node * eqn)
01970 {
01971     qucs::vector * v = NULL;
01972     if (!eqn->getResult ()) return NULL;
01973     switch (eqn->getType ())
01974     {
01975     case TAG_VECTOR: // simple vector
01976         v = new qucs::vector (* (eqn->getResult()->v));
01977         v->setNext (NULL);
01978         v->setPrev (NULL);
01979         break;
01980     case TAG_DOUBLE: // double value
01981         v = new qucs::vector ();
01982         v->add (eqn->getResult()->d);
01983         break;
01984     case TAG_BOOLEAN: // boolean value
01985         v = new qucs::vector ();
01986         v->add (eqn->getResult()->b ? 1 : 0);
01987         break;
01988     case TAG_COMPLEX: // complex value
01989         v = new qucs::vector ();
01990         v->add (* (eqn->getResult()->c));
01991         break;
01992     case TAG_MATVEC: // matrix vector
01993     {
01994         // convert matrix vector to a list of vectors
01995         matvec * mv = eqn->getResult()->mv;
01996         mv->setName (A(eqn)->result);
01997         for (int r = 0; r < mv->getRows (); r++)
01998         {
01999             for (int c = 0; c < mv->getCols (); c++)
02000             {
02001                 // name gets automatically assigned
02002                 qucs::vector * t = new qucs::vector (mv->get (r, c));
02003                 // chain the vectors appropriately
02004                 t->setNext (v);
02005                 v = t;
02006             }
02007         }
02008     }
02009     return v;
02010     case TAG_MATRIX: // single matrix
02011     {
02012         // convert matrix to a list of vectors
02013         matrix * m = eqn->getResult()->m;
02014         for (int r = 0; r < m->getRows (); r++)
02015         {
02016             for (int c = 0; c < m->getCols (); c++)
02017             {
02018                 qucs::vector * t = new qucs::vector ();
02019                 t->setName (matvec::createMatrixString (A(eqn)->result, r, c));
02020                 t->add (m->get (r, c));
02021                 // chain the vectors appropriately
02022                 t->setNext (v);
02023                 v = t;
02024             }
02025         }
02026     }
02027     return v;
02028     default:
02029         return NULL;
02030     }
02031     v->setName (A(eqn)->result);
02032     return v;
02033 }
02034 
02035 /* This function collects the data vectors in a dataset and appends
02036    these to the list of equation node inside the equation solver. */
02037 void solver::checkinDataset (void)
02038 {
02039     if (data == NULL) return;
02040     qucs::vector * v;
02041     findMatrixVectors (data->getDependencies ());
02042     findMatrixVectors (data->getVariables ());
02043     for (v = data->getDependencies (); v != NULL; v = (qucs::vector *) v->getNext ())
02044     {
02045         if (v->getRequested () != -1)
02046         {
02047             node * eqn = addEquationData (v, true);
02048             strlist * deps = new strlist ();
02049             deps->add (v->getName ());
02050             eqn->setDataDependencies (deps);
02051             delete deps;
02052         }
02053     }
02054     for (v = data->getVariables (); v != NULL; v = (qucs::vector *) v->getNext ())
02055     {
02056         if (v->getRequested () != -1)
02057         {
02058             node * eqn = addEquationData (v, true);
02059             eqn->setDataDependencies (v->getDependencies ());
02060         }
02061     }
02062 }
02063 
02064 /* This function searches through the dataset of the equation solver
02065    for possible matrix vectors.  These are detected by the vectors'
02066    names (e.g. S[1,1]).  The matrix vectors found in the dataset get
02067    converted and saved into the set of equations.  */
02068 void solver::findMatrixVectors (qucs::vector * v)
02069 {
02070     qucs::vector * vec;
02071     strlist * deps;
02072     char * p, * cand;
02073     int s, r, c, a, b, n = 1;
02074 
02075     // initialize the  'found' flag
02076     for (vec = v; vec != NULL; vec = (qucs::vector *) vec->getNext ())
02077         vec->setRequested (0);
02078 
02079     // loop through the dataset vector until no more matrix vector is found
02080     do
02081     {
02082         r = c = s = -1;
02083         cand = NULL;
02084         deps = NULL;
02085         // go through the dataset
02086         for (vec = v; vec != NULL; vec = (qucs::vector *) vec->getNext ())
02087         {
02088             // skip detected vectors
02089             if (vec->getRequested ()) continue;
02090             // is the vector a possible matrix vector element ?
02091             if ((p = matvec::isMatrixVector (vec->getName (), a, b)) != NULL)
02092             {
02093                 if (cand != NULL)
02094                 {
02095                     // does this vectors name equals the current one ?
02096                     if (!strcmp (p, cand) && s == vec->getSize ())
02097                     {
02098                         // save largest row and column index and set the 'found' flag
02099                         if (a > r) r = a;
02100                         if (b > c) c = b;
02101                         vec->setRequested (n);
02102                     }
02103                 }
02104                 else
02105                 {
02106                     /* new possible matrix vector:
02107                        save its name, row and column index, its size (length of
02108                        the vector) and data dependencies; then set the 'found' flag */
02109                     cand = strdup (p);
02110                     r = a;
02111                     c = b;
02112                     s = vec->getSize ();
02113                     vec->setRequested (n);
02114                     deps = vec->getDependencies ();
02115                 }
02116                 free (p);
02117             }
02118         }
02119 
02120         // new matrix vector detected
02121         if (cand != NULL)
02122         {
02123             // create a new matrix vector and set the appropriate name
02124             matvec * mv = new matvec (s, r + 1, c + 1);
02125             mv->setName (cand);
02126             // go through the dataset vector once again
02127             for (vec = v; vec != NULL; vec = (qucs::vector *) vec->getNext ())
02128             {
02129                 // and collect the vectors with the same 'found' flags
02130                 if (vec->getRequested () == n)
02131                 {
02132                     p = matvec::isMatrixVector (vec->getName (), a, b);
02133                     mv->set (*vec, a, b);
02134                     free (p);
02135                     vec->setRequested (-1);
02136                 }
02137             }
02138             // now store this new matrix vector into the set of equations
02139             node * eqn = addEquationData (mv);
02140             eqn->solvee = this;
02141             eqn->evaluate ();
02142             if (deps == NULL)
02143             {
02144                 strlist * deps = new strlist ();
02145                 deps->add (mv->getName ());
02146                 eqn->setDataDependencies (deps);
02147                 delete deps;
02148             }
02149             else
02150             {
02151                 eqn->setDataDependencies (deps);
02152             }
02153             free (cand);
02154             cand = NULL;
02155         }
02156         // increase the current 'found' flag
02157         n++;
02158     }
02159     while (cand != NULL);
02160 }
02161 
02162 /* The function creates an assignment equation from the given matrix
02163    vector and returns it.  The new assignment is appended to the list
02164    of available equations. */
02165 node * solver::addEquationData (matvec * mv)
02166 {
02167     constant * con = new constant (TAG_MATVEC);
02168     con->mv = mv;
02169     assignment * assign = new assignment ();
02170     assign->result = strdup (mv->getName ());
02171     assign->body = con;
02172     assign->setNext (equations);
02173     equations = assign;
02174     return assign;
02175 }
02176 
02177 /* The function returns the dataset entry length of the given equation
02178    node (a constant).  The constant must already been evaluated when
02179    this function is called. */
02180 int solver::dataSize (constant * eqn)
02181 {
02182     int size = 0;
02183     switch (eqn->getType ())
02184     {
02185     case TAG_VECTOR: // simple vector
02186         size = eqn->getResult()->v->getSize ();
02187         break;
02188     case TAG_MATVEC: // matrix vector
02189         size = eqn->getResult()->mv->getSize ();
02190     default:
02191         size = 1;
02192     }
02193     return size;
02194 }
02195 
02196 /* This function returns the dataset entry length of the given
02197    variable name.  It must be ensured that the variable actually
02198    exists and is already evaluated. */
02199 int solver::getDataSize (char * var)
02200 {
02201     node * eqn = checker::findEquation (equations, var);
02202     return dataSize (C (eqn));
02203 }
02204 
02205 /* Depending on the index the function returns the cumulative product
02206    of the dataset entries stored in the given dependency list or one
02207    if there are no data dependencies at all. */
02208 int solver::getDependencySize (strlist * deps, int idx)
02209 {
02210     int size = 1;
02211     if (deps == NULL) return 1;
02212     for (int i = 0; i < deps->length () - idx; i++)
02213     {
02214         size *= getDataSize (deps->get (i));
02215     }
02216     return size;
02217 }
02218 
02219 /* This function goes through the given string list and calculates the
02220    data entries within these dataset dependencies.  It returns at
02221    least one no matter whether the data vectors can be found or not. */
02222 int solver::dataSize (strlist * deps)
02223 {
02224     int size = 1;
02225     for (int i = 0; deps != NULL && i < deps->length (); i++)
02226     {
02227         char * str = deps->get (i);
02228         qucs::vector * dep = data->findDependency (str);
02229         qucs::vector * var = data->findVariable (str);
02230         size *= dep ? dep->getSize () : var ? var->getSize () : 1;
02231     }
02232     return size;
02233 }
02234 
02235 /* The function returns the data vector in the dataset according to
02236    the given variable name.  If there is no such variable, it returns
02237    NULL. */
02238 qucs::vector * solver::getDataVector (char * str)
02239 {
02240     qucs::vector * var;
02241     /* search for variables in dataset */
02242     if (data != NULL)
02243     {
02244         if ((var = data->findVariable (str)) != NULL)
02245             return var;
02246         if ((var = data->findDependency (str)) != NULL)
02247             return var;
02248     }
02249     /* search for variables in equation set */
02250     if (equations != NULL)
02251     {
02252         node * eqn = checker::findEquation (equations, str);
02253         constant * res = eqn->getResult ();
02254         if (res->getTag () == CONSTANT && res->getType () == TAG_VECTOR)
02255         {
02256             return res->v;
02257         }
02258     }
02259     return NULL;
02260 }
02261 
02262 /* The following function collects the inherited dataset dependencies
02263    for the given equation node and returns it as a string list.  It
02264    returns NULL if there are no such dependencies. */
02265 strlist * solver::collectDataDependencies (node * eqn)
02266 {
02267     strlist * sub = NULL, * datadeps = NULL;
02268     // should all data dependencies be dropped?
02269     if (!eqn->getResult()->dropdeps)
02270     {
02271         strlist * deps = eqn->getDependencies ();
02272         datadeps = eqn->getDataDependencies ();
02273         datadeps = datadeps ? new strlist (*datadeps) : NULL;
02274         // go through equation dependencies
02275         for (int i = 0; deps && i < deps->length (); i++)
02276         {
02277             char * var = deps->get (i);
02278             // find equation node for the dependency
02279             node * n = checker::findEquation (equations, var);
02280             // try again in the solver equations
02281             if (n == NULL && eqn->solvee != NULL)
02282                 n = checker::findEquation (eqn->solvee->getEquations (), var);
02283             // if finally founf the equation node
02284             if (n != NULL)
02285             {
02286                 // pass resulting data dependencies up
02287                 strlist * resdeps;
02288                 if ((resdeps = n->getResult()->getDataDependencies ()) != NULL)
02289                     n->setDataDependencies (resdeps);
02290                 // add data dependencies
02291                 sub = strlist::join (datadeps, n->getDataDependencies ());
02292                 sub->del (n->getResult()->getDropDependencies ());
02293                 sub->add (n->getResult()->getPrepDependencies ());
02294             }
02295             delete datadeps;
02296             datadeps = sub;
02297         }
02298     }
02299     // prepend dependencies if necessary
02300     strlist * preps = eqn->getResult()->getPrepDependencies ();
02301     if (datadeps)
02302     {
02303         if (preps) datadeps->add (preps);
02304     }
02305     else
02306     {
02307         datadeps = new strlist ();
02308         if (preps) datadeps->add (preps);
02309     }
02310     // drop duplicate entries
02311     datadeps = checker::foldDependencies (datadeps);
02312     // delete the dependencies to be dropped intentionally
02313     datadeps->del (eqn->getResult()->getDropDependencies ());
02314     // finally return the correct data dependencies
02315     if (datadeps->length () == 0)
02316     {
02317         delete datadeps;
02318         datadeps = NULL;
02319     }
02320     return datadeps;
02321 }
02322 
02323 // The function stores the equation solver results back into a dataset.
02324 void solver::checkoutDataset (void)
02325 {
02326     // return if nothing todo
02327     if (data == NULL) return;
02328     // go through each equation
02329     foreach_equation (eqn)
02330     {
02331 
02332         // skip variables which don't need to be exported
02333         if (!eqn->output) continue;
02334 
02335         // is the equation result already in the dataset ?
02336         if (!findEquationResult (eqn))
02337         {
02338             qucs::vector * v = dataVector (eqn);
02339             if (v == NULL) continue;
02340 
02341             // collect inherited dataset dependencies
02342             strlist * datadeps = collectDataDependencies (eqn);
02343 
02344             // check whether dataset is smaller than its dependencies
02345             if (v->getSize () <= 1 && dataSize (datadeps) > v->getSize ())
02346             {
02347                 delete datadeps;
02348                 datadeps = NULL;
02349             }
02350 
02351             // store variable vector(s)
02352             if (datadeps && datadeps->length () > 0)
02353             {
02354                 v->setDependencies (datadeps);
02355                 if (v->getNext () != NULL)
02356                 {
02357                     data->applyDependencies (v);
02358                     data->addVariables (v);
02359                 }
02360                 else
02361                 {
02362                     data->addVariable (v);
02363                 }
02364             }
02365             // store independent vector(s)
02366             else
02367             {
02368                 if (v->getNext () != NULL)
02369                     data->addDependencies (v);
02370                 else
02371                     data->addDependency (v);
02372                 delete datadeps;
02373             }
02374         }
02375     }
02376 }
02377 
02378 /* This function checks whether the given equation solver result is
02379    already within the dataset.  It returns non-zero if so, otherwise
02380    the function returns zero. */
02381 int solver::findEquationResult (node * eqn)
02382 {
02383     // check each vector of a given matrix vector
02384     if (eqn->getType () == TAG_MATVEC)
02385     {
02386         matvec * mv = eqn->getResult()->mv;
02387         for (int r = 0; r < mv->getRows (); r++)
02388         {
02389             for (int c = 0; c < mv->getCols (); c++)
02390             {
02391                 char * str = matvec::createMatrixString (A(eqn)->result, r, c);
02392                 if (data->findDependency (str) || data->findVariable (str))
02393                     return 1;
02394             }
02395         }
02396     }
02397     // check normal data vectors
02398     else
02399     {
02400         char * str = A(eqn)->result;
02401         if (data->findDependency (str) || data->findVariable (str))
02402             return 1;
02403     }
02404     return 0;
02405 }
02406 
02407 /* This function is called in order to run the equation checker and
02408    the solver.  The optional dataset passed to the function receives
02409    the results of the calculations. */
02410 int solver::solve (dataset * data)
02411 {
02412     // load additional dataset equations
02413     setData (data);
02414     checkinDataset ();
02415     // put these into the checker
02416     checkee->setEquations (equations);
02417     // and check
02418     if (checkee->check (data ? 1 : 0) != 0)
02419     {
02420         return -1;
02421     }
02422     equations = checkee->getEquations ();
02423     // finally evaluate equations
02424     evaluate ();
02425     // put results into the dataset
02426     checkoutDataset ();
02427     return 0;
02428 }
02429 
02430 /* Go through the list of equations and store the left hand side in
02431    a string list. */
02432 strlist * checker::variables (void)
02433 {
02434     strlist * idents = new strlist ();
02435     foreach_equation (eqn)
02436     {
02437         idents->add (eqn->result);
02438     }
02439     return idents;
02440 }
02441 
02442 // Checks if the given variable name is an equation.
02443 bool checker::containsVariable (const char * const ident) const
02444 {
02445     foreach_equation (eqn)
02446     {
02447         if (!strcmp (ident, eqn->result))
02448             return true;
02449     }
02450     return false;
02451 }
02452 
02453 // Structure defining a predefined constant.
02454 struct pconstant
02455 {
02456     const char * ident;
02457     nr_double_t value;
02458 };
02459 
02460 // List of global constant variables.
02461 static struct pconstant pconstants[] =
02462 {
02463     { "pi", pi },
02464     { "e",  euler  },
02465     { "kB", kB   },
02466     { "q",  Q_e    },
02467     { NULL, 0    }
02468 };
02469 
02470 /* The function should be called before parsing the netlist.  It
02471    appends the predefined constants to the list of equations. */
02472 void checker::constants (void)
02473 {
02474 
02475     // return if nothing to do
02476     if (consts) return;
02477 
02478     // go through constants and add these to the equations
02479     for (int i = 0; pconstants[i].ident != NULL; i++)
02480     {
02481         addDouble ("#predefined", pconstants[i].ident, pconstants[i].value);
02482     }
02483 
02484     // indicate that constants have been added
02485     consts = true;
02486 }
02487 
02488 /* The function adds a new equation to the equation checker consisting
02489    of an assignment of a reference. */
02490 node * checker::addReference (const char * type, const char * ident,
02491                               char * value)
02492 {
02493     node * eqn = createReference (type, ident, value);
02494     addEquation (eqn);
02495     return eqn;
02496 }
02497 
02498 /* The function adds a new equation to the equation checker consisting
02499    of an assignment of a double variable. */
02500 node * checker::addDouble (const char * type, const char * ident,
02501                            nr_double_t value)
02502 {
02503     node * eqn = createDouble (type, ident, value);
02504     addEquation (eqn);
02505     return eqn;
02506 }
02507 
02508 /* The function adds a new equation to the equation checker consisting
02509    of an assignment of a complex variable. */
02510 node * checker::addComplex (const char * type, const char * ident,
02511                             nr_complex_t value)
02512 {
02513     node * eqn = createComplex (type, ident, value);
02514     addEquation (eqn);
02515     return eqn;
02516 }
02517 
02518 // Adds given equation to the equation list.
02519 void checker::addEquation (node * eqn)
02520 {
02521     eqn->setNext (equations);
02522     equations = eqn;
02523 }
02524 
02525 // Appends the given equation to the equation list.
02526 void checker::appendEquation (node * eqn)
02527 {
02528     eqn->setNext (NULL);
02529     node * last = lastEquation (equations);
02530     if (last != NULL)
02531         last->setNext (eqn);
02532     else
02533         equations = eqn;
02534 }
02535 
02536 /* This function creates a equation consisting of an assignment of a
02537    double variable. */
02538 node * checker::createDouble (const char * type, const char * ident,
02539                               nr_double_t value)
02540 {
02541     // create constant double value
02542     constant * c = new constant (TAG_DOUBLE);
02543     c->checkee = this;
02544     c->d = value;
02545     // create the appropriate assignment
02546     assignment * a = new assignment ();
02547     a->checkee = this;
02548     a->result = strdup (ident);
02549     a->body = c;
02550     a->output = 0;
02551     a->setInstance (type);
02552     return a;
02553 }
02554 
02555 /* This function creates a equation consisting of an assignment of a
02556    complex variable. */
02557 node * checker::createComplex (const char * type, const char * ident,
02558                                nr_complex_t value)
02559 {
02560     // create constant double value
02561     constant * c = new constant (TAG_COMPLEX);
02562     c->checkee = this;
02563     c->c = new nr_complex_t (value);
02564     // create the appropriate assignment
02565     assignment * a = new assignment ();
02566     a->checkee = this;
02567     a->result = strdup (ident);
02568     a->body = c;
02569     a->output = 0;
02570     a->setInstance (type);
02571     return a;
02572 }
02573 
02574 /* This function creates a equation consisting of an assignment of a
02575    reference. */
02576 node * checker::createReference (const char * type, const char * ident,
02577                                  char * value)
02578 {
02579     // create reference value
02580     reference * r = new reference ();
02581     r->checkee = this;
02582     r->n = strdup (value);
02583     // create the appropriate assignment
02584     assignment * a = new assignment ();
02585     a->checkee = this;
02586     a->result = strdup (ident);
02587     a->body = r;
02588     a->output = 0;
02589     a->setInstance (type);
02590     return a;
02591 }
02592 
02593 /* The functions looks through the set of equations for a real valued
02594    result and returns it.  If there is no such assignment, zero is
02595    returned. */
02596 nr_double_t checker::getDouble (const char * const ident) const
02597 {
02598     foreach_equation (eqn)
02599     {
02600         if (!strcmp (ident, eqn->result))
02601         {
02602             return eqn->getResultDouble ();
02603         }
02604     }
02605     return 0.0;
02606 }
02607 
02608 /* The function goes through the equation set and looks for the
02609    specified assignment.  If found the given value is set. */
02610 void checker::setDouble (const char * const ident, nr_double_t val)
02611 {
02612     foreach_equation (eqn)
02613     {
02614         if (!strcmp (ident, eqn->result))
02615         {
02616             if (eqn->body->getTag () == CONSTANT)
02617             {
02618                 constant * c = C (eqn->body);
02619                 if (c->type == TAG_DOUBLE) c->d = val;
02620             }
02621         }
02622     }
02623 }
02624 
02625 /* The functions looks through the set of equations for a vector
02626    result and returns it.  If there is no such assignment, an empty
02627    vector is returned. */
02628 qucs::vector checker::getVector (const char * const ident) const
02629 {
02630     foreach_equation (eqn)
02631     {
02632         if (!strcmp (ident, eqn->result))
02633         {
02634             return eqn->getResultVector ();
02635         }
02636     }
02637     return qucs::vector ();
02638 }
02639 
02640 } // namespace qucs