Qucs-core  0.0.19
environment.cpp
Go to the documentation of this file.
00001 /*
00002  * environment.cpp - variable environment class implementation
00003  *
00004  * Copyright (C) 2004, 2005, 2006, 2007, 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 <list>
00030 
00031 #include <stdio.h>
00032 #include <stdlib.h>
00033 #include <string.h>
00034 
00035 #include "complex.h"
00036 #include "variable.h"
00037 #include "equation.h"
00038 #include "logging.h"
00039 #include "environment.h"
00040 
00041 using namespace qucs::eqn;
00042 
00043 namespace qucs {
00044 
00045 // Constructor creates an unnamed instance of the environment class.
00046 environment::environment () :
00047   name(),
00048   children()
00049 {
00050   root = NULL;
00051   solvee = NULL;
00052   checkee = NULL;
00053   defs = NULL;
00054   iscopy = false;
00055 }
00056 
00057 
00058 // Constructor creates a named instance of the environment class.
00059 environment::environment (const std::string & p_name) :
00060   name(p_name),
00061   children()
00062 {
00063   root = NULL;
00064   solvee = NULL;
00065   checkee = NULL;
00066   defs = NULL;
00067   iscopy = false;
00068 }
00069 
00070 /* The copy constructor creates a new instance of the environment
00071    class based on the given environment object. */
00072 environment::environment (const environment & e)  {
00073   this->name = e.name;
00074   copyVariables (e.root);
00075   solvee = e.solvee;
00076   checkee = e.checkee;
00077   defs = e.defs;
00078   iscopy = true;
00079   children = std::list<environment *>();
00080 }
00081 
00082 /* Very alike the copy constructor the function copies the content of
00083    the given environment into the calling environment. */
00084 void environment::copy (const environment & e) {
00085   this->name = e.name;
00086   deleteVariables ();
00087   copyVariables (e.root);
00088   solvee = e.solvee;
00089   checkee = e.checkee;
00090   defs = e.defs;
00091   iscopy = true;
00092   children = std::list<environment *>();
00093 }
00094 
00095 // Destructor deletes the environment object.
00096 environment::~environment () {
00097   deleteVariables ();
00098   // delete solver and checker if this is not just a reference
00099   if (!iscopy) {
00100     if (solvee)
00101       delete solvee;
00102     if (checkee) {
00103       checkee->setEquations (NULL);
00104       delete checkee;
00105     }
00106   }
00107   // delete children
00108   for (auto it = children.begin(); it != children.end(); ++it) {
00109     environment * etmp = *it;
00110     delete etmp;
00111   }
00112 }
00113 
00114 
00115 /* This function copies all variables in the given variable list into
00116    an environment. */
00117 void environment::copyVariables (variable * org) {
00118   variable * var;
00119   root = NULL;
00120   while (org != NULL) {
00121     // copy variable (references only)
00122     var = new variable (*org);
00123     constant * c; reference * r;
00124     // depending on variable type copy values too
00125     switch (var->getType ()) {
00126     case VAR_CONSTANT:
00127       c = new constant (*(var->getConstant ()));
00128       var->setConstant (c);
00129       break;
00130     case VAR_VALUE:
00131       c = new constant (*(org->getValue ()));
00132       var->setValue (c);
00133       break;
00134     case VAR_REFERENCE:
00135       r = new reference ();
00136       r->n = strdup (var->getReference()->n);
00137       var->setReference (r);
00138       break;
00139     }
00140     var->setNext (root);
00141     root = var;
00142     org = org->getNext ();
00143   }
00144 }
00145 
00146 // Deletes all variable in the environment.
00147 void environment::deleteVariables (void) {
00148   variable * n;
00149   for (variable * var = root; var != NULL; var = n) {
00150     n = var->getNext ();
00151     if (var->getType () == VAR_CONSTANT)
00152       delete var->getConstant ();
00153     else if (var->getType () == VAR_VALUE)
00154       delete var->getValue ();
00155     else if (var->getType () == VAR_SUBSTRATE)
00156       delete var->getSubstrate ();
00157     else if (var->getType () == VAR_REFERENCE) {
00158       constant * c = var->getReference()->getResult ();
00159       delete c;
00160       delete var->getReference ();
00161     }
00162     delete var;
00163   }
00164   root = NULL;
00165 }
00166 
00167 /* This function adds a variable to the environment. */
00168 void environment::addVariable (variable * const var, const bool pass) {
00169   var->setNext (root);
00170   var->setPassing (pass);
00171   this->root = var;
00172 }
00173 
00174 /* This function looks for the variable name in the environment and
00175    returns it if possible.  Otherwise the function returns NULL. */
00176 variable * environment::getVariable (const char * const n) const {
00177   for (variable * var = root; var != NULL; var = var->getNext ()) {
00178     if (var->getType () != VAR_VALUE)
00179       if (!strcmp (var->getName (), n))
00180         return var;
00181   }
00182   return NULL;
00183 }
00184 
00185 // The function runs the equation checker for this environment.
00186 int environment::equationChecker (const int noundefined) const {
00187   checkee->setDefinitions (defs);
00188   return checkee->check (noundefined);
00189 }
00190 
00191 // The function runs the equation solver for this environment.
00192 int environment::equationSolver (dataset * const data) {
00193   checkee->setDefinitions (defs);
00194   solvee->setEquations (checkee->getEquations ());
00195   int err = solvee->solve (data);
00196   checkee->setEquations (solvee->getEquations ());
00197   return err;
00198 }
00199 
00200 // The function runs the equation solver for this environment without
00201 // checking it previously and without considering an additional
00202 // dataset.
00203 void environment::equationSolver (void) {
00204   checkee->setDefinitions (defs);
00205   solvee->setEquations (checkee->getEquations ());
00206   solvee->evaluate ();
00207   checkee->setEquations (solvee->getEquations ());
00208 }
00209 
00210 
00211 /* The function solves the equations of the current environment object
00212    as well as these of its children, updates the variables and passes
00213    the arguments to each children. */
00214 int environment::runSolver (void) {
00215   int ret = 0;
00216 
00217   // solve equations in current environment
00218   ret |= equationSolver (NULL);
00219   fetchConstants ();
00220 
00221   // cycle through children
00222   for(auto it = children.begin(); it != children.end(); ++it) {
00223     // pass constants to solver
00224     (*it)->passConstants ();
00225     // pass references
00226     (*it)->updateReferences (this);
00227     // actually run the solver
00228     ret |= (*it)->runSolver ();
00229 #if 0
00230     // save local results
00231     (*it)->saveResults ();
00232 #endif
00233   }
00234 
00235   return ret;
00236 }
00237 
00238 /* Passes the constants of the environment to the equation solver.
00239    This is necessary since equally typed environments use the same
00240    equation checker and solver. */
00241 void environment::passConstants (void) {
00242   for (variable * var = root; var != NULL; var = var->getNext ()) {
00243     if (var->getPassing () && var->getType () == VAR_CONSTANT) {
00244       constant * c = var->getConstant ();
00245       setDouble (var->getName (), c->d);
00246     }
00247   }
00248 }
00249 
00250 /* Fetches the values of variables from the equation solver. */
00251 void environment::fetchConstants (void) {
00252   for (variable * var = root; var != NULL; var = var->getNext ()) {
00253     if (var->getType () == VAR_CONSTANT) {
00254       constant * c = var->getConstant ();
00255       switch (c->getType ()) {
00256       case TAG_DOUBLE:
00257         c->d = getDouble (var->getName ());
00258         break;
00259       case TAG_VECTOR:
00260         *c->v = getVector (var->getName ());
00261         break;
00262       }
00263     }
00264   }
00265 }
00266 
00267 /* Looks through the environment variables for a given variable name
00268    being a saved value and returns the variable pointer or NULL if
00269    there is no such variable. */
00270 variable * environment::findValue (char * n) {
00271   for (variable * var = root; var != NULL; var = var->getNext ()) {
00272     if (var->getType () == VAR_VALUE)
00273       if (!strcmp (var->getName (), n))
00274         return var;
00275   }
00276   return NULL;
00277 }
00278 
00279 /* Puts the given variable name and its computed result into the list
00280    of environment variables. */
00281 void environment::setValue (char * n, constant * value) {
00282   variable * var = findValue (n);
00283   if (var != NULL) {
00284     // replace variable
00285     delete var->getValue ();
00286     var->setValue (new constant (*value));
00287   } else {
00288     // create new variable
00289     var = new variable (n);
00290     var->setValue (new constant (*value));
00291     addVariable (var);
00292   }
00293 }
00294 
00295 // Local macro definition to go through the list of equations.
00296 #define foreach_equation(eqn)                        \
00297   for (assignment * (eqn) = A (equations);           \
00298        (eqn) != NULL; (eqn) = A ((eqn)->getNext ()))
00299 
00300 // Short helper macro.
00301 #define A(a) ((assignment *) (a))
00302 
00303 /* The function puts local variables (prameters and equation results)
00304    into the set of environment variables. */
00305 void environment::saveResults (void) {
00306   node * equations = checkee->getEquations ();
00307   // go through equations
00308   foreach_equation (eqn) {
00309     char * inst = eqn->getInstance ();
00310     if (inst != NULL && eqn->evaluated) {
00311       char * result = A(eqn)->result;
00312       if ((inst[0] != '#' && !strchr (result, '.')) ||
00313           !strcmp (inst, "#subcircuit")) {
00314         setValue (result, eqn->getResult ());
00315       }
00316     }
00317   }
00318 }
00319 
00320 /* This function looks through all variables which are references.  If
00321    found the variable gets resolved in the upper (parent) environment
00322    and the value put into the result of the reference as well as into
00323    the equation checker of the current environment. */
00324 void environment::updateReferences (environment * up) {
00325   for (variable * var = root; var != NULL; var = var->getNext ()) {
00326     if (var->getType () == VAR_REFERENCE) {
00327       reference * r = var->getReference ();
00328       // possible because no self-referring subcircuit types possible
00329       nr_double_t d = up->getDouble (r->n);
00330       constant * c = r->getResult ();
00331       c->d = d;
00332       setDouble (var->getName (), d);
00333     }
00334   }
00335 }
00336 
00337 // Returns vector of an assignment in the equation checker.
00338 qucs::vector environment::getVector (const char * const ident) const {
00339   return checkee->getVector (ident);
00340 }
00341 
00342 // Returns double value of an assignment in the equation checker.
00343 nr_double_t environment::getDouble (const char * const ident) const {
00344   return checkee->getDouble (ident);
00345 }
00346 
00347 // Sets the double value of an assignment in the equation checker.
00348 void environment::setDouble (const char * const ident, const nr_double_t val) {
00349   checkee->setDouble (ident, val);
00350 }
00351 
00352 // Return double value of a variable in the environment.
00353 nr_double_t environment::getDoubleConstant (const char * const ident) const {
00354   variable * var = getVariable (ident);
00355   if (var != NULL && var->getType () == VAR_CONSTANT) {
00356     constant * c = var->getConstant ();
00357     return c->d;
00358   }
00359   return 0.0;
00360 }
00361 
00362 // Sets the double value of a variable in the environment.
00363 void environment::setDoubleConstant (const char * const ident, nr_double_t val) {
00364   variable * var = getVariable (ident);
00365   if (var != NULL && var->getType () == VAR_CONSTANT) {
00366     constant * c = var->getConstant ();
00367     c->d = val;
00368   }
00369 }
00370 
00371 // Returns the referenced value of a variable in the environment.
00372 char * environment::getDoubleReference (const char * const ident) const {
00373   variable * var = getVariable (ident);
00374   if (var != NULL &&  var->getType () == VAR_REFERENCE) {
00375     reference * r = var->getReference ();
00376     return r->n;
00377   }
00378   return NULL;
00379 }
00380 
00381 // Sets the referenced value of a variable in the environment.
00382 void environment::setDoubleReference (const char * const ident, char * val) {
00383   variable * var = getVariable (ident);
00384   if (var != NULL) {
00385     if (var->getType () == VAR_CONSTANT) {
00386       // its a constant, so make it a reference
00387       delete var->getConstant ();
00388       reference * r = new reference ();
00389       r->n = strdup (val);
00390       constant * c = new constant (TAG_DOUBLE);
00391       r->setResult (c);
00392       var->setReference (r);
00393     }
00394     else if (var->getType () == VAR_REFERENCE) {
00395       // just apply the reference
00396       reference * r = var->getReference ();
00397       free (r->n);
00398       r->n = strdup (val);
00399     }
00400   }
00401 }
00402 
00404 void environment::print (const bool all) const {
00405   logprint (LOG_STATUS, "environment %s\n",this->name.c_str());
00406   for (variable * var = root; var != NULL; var = var->getNext ()) {
00407     logprint (LOG_STATUS, "  %s [%s]\n", var->getName (), var->toString ());
00408   }
00409   for (auto it = children.begin(); it != children.end() ; ++it) {
00410     logprint (LOG_STATUS, "  %s\n", (*it)->name.c_str ());
00411   }
00412   if (all) {
00413     for (auto it = children.begin(); it != children.end() ; ++it)
00414       (*it)->print ();
00415   }
00416 }
00417 
00418 } // namespace qucs