Qucs-core
0.0.19
|
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