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