Branch data Line data Source code
1 : : /*
2 : : * environment.cpp - variable environment class implementation
3 : : *
4 : : * Copyright (C) 2004, 2005, 2006, 2007, 2009 Stefan Jahn <stefan@lkcc.org>
5 : : *
6 : : * This is free software; you can redistribute it and/or modify
7 : : * it under the terms of the GNU General Public License as published by
8 : : * the Free Software Foundation; either version 2, or (at your option)
9 : : * any later version.
10 : : *
11 : : * This software is distributed in the hope that it will be useful,
12 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : : * GNU General Public License for more details.
15 : : *
16 : : * You should have received a copy of the GNU General Public License
17 : : * along with this package; see the file COPYING. If not, write to
18 : : * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
19 : : * Boston, MA 02110-1301, USA.
20 : : *
21 : : * $Id$
22 : : *
23 : : */
24 : :
25 : : #if HAVE_CONFIG_H
26 : : # include <config.h>
27 : : #endif
28 : :
29 : : #include <list>
30 : :
31 : : #include <stdio.h>
32 : : #include <stdlib.h>
33 : : #include <string.h>
34 : :
35 : : #include "complex.h"
36 : : #include "variable.h"
37 : : #include "equation.h"
38 : : #include "logging.h"
39 : : #include "environment.h"
40 : :
41 : : using namespace qucs::eqn;
42 : :
43 : : namespace qucs {
44 : :
45 : : // Constructor creates an unnamed instance of the environment class.
46 : 0 : environment::environment () :
47 : : name(),
48 [ # # ][ # # ]: 0 : children()
49 : : {
50 : 0 : root = NULL;
51 : 0 : solvee = NULL;
52 : 0 : checkee = NULL;
53 : 0 : defs = NULL;
54 : 0 : iscopy = false;
55 : 0 : }
56 : :
57 : :
58 : : // Constructor creates a named instance of the environment class.
59 : 219 : environment::environment (const std::string & p_name) :
60 : : name(p_name),
61 [ + - ][ # # ]: 219 : children()
62 : : {
63 : 219 : root = NULL;
64 : 219 : solvee = NULL;
65 : 219 : checkee = NULL;
66 : 219 : defs = NULL;
67 : 219 : iscopy = false;
68 : 219 : }
69 : :
70 : : /* The copy constructor creates a new instance of the environment
71 : : class based on the given environment object. */
72 [ + - ][ # # ]: 23 : environment::environment (const environment & e) {
73 [ + - ][ # # ]: 23 : this->name = e.name;
74 [ + - ][ # # ]: 23 : copyVariables (e.root);
75 : 23 : solvee = e.solvee;
76 : 23 : checkee = e.checkee;
77 : 23 : defs = e.defs;
78 : 23 : iscopy = true;
79 [ + - ][ + - ]: 23 : children = std::list<environment *>();
[ # # ][ # # ]
80 : 23 : }
81 : :
82 : : /* Very alike the copy constructor the function copies the content of
83 : : the given environment into the calling environment. */
84 : 103 : void environment::copy (const environment & e) {
85 : 103 : this->name = e.name;
86 : 103 : deleteVariables ();
87 : 103 : copyVariables (e.root);
88 : 103 : solvee = e.solvee;
89 : 103 : checkee = e.checkee;
90 : 103 : defs = e.defs;
91 : 103 : iscopy = true;
92 [ + - ]: 103 : children = std::list<environment *>();
93 : 103 : }
94 : :
95 : : // Destructor deletes the environment object.
96 : 242 : environment::~environment () {
97 [ + - ][ # # ]: 242 : deleteVariables ();
98 : : // delete solver and checker if this is not just a reference
99 [ + + ][ # # ]: 242 : if (!iscopy) {
100 [ + - ][ # # ]: 116 : if (solvee)
101 [ + - ][ + - ]: 116 : delete solvee;
[ # # ][ # # ]
102 [ + - ][ # # ]: 116 : if (checkee) {
103 [ + - ][ # # ]: 116 : checkee->setEquations (NULL);
104 [ + - ][ + - ]: 116 : delete checkee;
[ # # ][ # # ]
105 : : }
106 : : }
107 : : // delete children
108 [ + + ][ # # ]: 278 : for (auto it = children.begin(); it != children.end(); ++it) {
109 : 36 : environment * etmp = *it;
110 [ + - ]: 36 : delete etmp;
[ + - # # ]
[ # # ]
111 : : }
112 [ - + ][ # # ]: 484 : }
113 : :
114 : :
115 : : /* This function copies all variables in the given variable list into
116 : : an environment. */
117 : 126 : void environment::copyVariables (variable * org) {
118 : : variable * var;
119 : 126 : root = NULL;
120 [ + + ]: 207 : while (org != NULL) {
121 : : // copy variable (references only)
122 [ + - ]: 81 : var = new variable (*org);
123 : : constant * c; reference * r;
124 : : // depending on variable type copy values too
125 [ + - - - ]: 81 : switch (var->getType ()) {
126 : : case VAR_CONSTANT:
127 [ + - ]: 81 : c = new constant (*(var->getConstant ()));
128 : 81 : var->setConstant (c);
129 : 81 : break;
130 : : case VAR_VALUE:
131 [ # # ]: 0 : c = new constant (*(org->getValue ()));
132 : 0 : var->setValue (c);
133 : 0 : break;
134 : : case VAR_REFERENCE:
135 [ # # ]: 0 : r = new reference ();
136 : 0 : r->n = strdup (var->getReference()->n);
137 : 0 : var->setReference (r);
138 : 0 : break;
139 : : }
140 : 81 : var->setNext (root);
141 : 81 : root = var;
142 : 81 : org = org->getNext ();
143 : : }
144 : 126 : }
145 : :
146 : : // Deletes all variable in the environment.
147 : 345 : void environment::deleteVariables (void) {
148 : : variable * n;
149 [ + + ]: 510 : for (variable * var = root; var != NULL; var = n) {
150 : 165 : n = var->getNext ();
151 [ + + ]: 165 : if (var->getType () == VAR_CONSTANT)
152 [ + - ]: 162 : delete var->getConstant ();
153 [ - + ]: 3 : else if (var->getType () == VAR_VALUE)
154 [ # # ]: 0 : delete var->getValue ();
155 [ + - ]: 3 : else if (var->getType () == VAR_SUBSTRATE)
156 [ + - ]: 3 : delete var->getSubstrate ();
157 [ # # ]: 0 : else if (var->getType () == VAR_REFERENCE) {
158 : 0 : constant * c = var->getReference()->getResult ();
159 [ # # ][ # # ]: 0 : if (c) delete c;
160 [ # # ]: 0 : delete var->getReference ();
161 : : }
162 [ + - ]: 165 : delete var;
163 : : }
164 : 345 : root = NULL;
165 : 345 : }
166 : :
167 : : /* This function adds a variable to the environment. */
168 : 84 : void environment::addVariable (variable * const var, const bool pass) {
169 : 84 : var->setNext (root);
170 : 84 : var->setPassing (pass);
171 : 84 : this->root = var;
172 : 84 : }
173 : :
174 : : /* This function looks for the variable name in the environment and
175 : : returns it if possible. Otherwise the function returns NULL. */
176 : 22955 : variable * environment::getVariable (const char * const n) const {
177 [ + + ]: 31270 : for (variable * var = root; var != NULL; var = var->getNext ()) {
178 [ + - ]: 31248 : if (var->getType () != VAR_VALUE)
179 [ + + ]: 31248 : if (!strcmp (var->getName (), n))
180 : 22933 : return var;
181 : : }
182 : 22955 : return NULL;
183 : : }
184 : :
185 : : // The function runs the equation checker for this environment.
186 : 116 : int environment::equationChecker (const int noundefined) const {
187 : 116 : checkee->setDefinitions (defs);
188 : 116 : return checkee->check (noundefined);
189 : : }
190 : :
191 : : // The function runs the equation solver for this environment.
192 : 23187 : int environment::equationSolver (dataset * const data) {
193 : 23187 : checkee->setDefinitions (defs);
194 : 23187 : solvee->setEquations (checkee->getEquations ());
195 : 23187 : int err = solvee->solve (data);
196 : 23187 : checkee->setEquations (solvee->getEquations ());
197 : 23187 : return err;
198 : : }
199 : :
200 : : // The function runs the equation solver for this environment without
201 : : // checking it previously and without considering an additional
202 : : // dataset.
203 : 0 : void environment::equationSolver (void) {
204 : 0 : checkee->setDefinitions (defs);
205 : 0 : solvee->setEquations (checkee->getEquations ());
206 : 0 : solvee->evaluate ();
207 : 0 : checkee->setEquations (solvee->getEquations ());
208 : 0 : }
209 : :
210 : :
211 : : /* The function solves the equations of the current environment object
212 : : as well as these of its children, updates the variables and passes
213 : : the arguments to each children. */
214 : 23084 : int environment::runSolver (void) {
215 : 23084 : int ret = 0;
216 : :
217 : : // solve equations in current environment
218 : 23084 : ret |= equationSolver (NULL);
219 : 23084 : fetchConstants ();
220 : :
221 : : // cycle through children
222 [ + + ]: 23366 : for(auto it = children.begin(); it != children.end(); ++it) {
223 : : // pass constants to solver
224 [ + - ]: 282 : (*it)->passConstants ();
225 : : // pass references
226 [ + - ]: 282 : (*it)->updateReferences (this);
227 : : // actually run the solver
228 [ + - ]: 282 : ret |= (*it)->runSolver ();
229 : : #if 0
230 : : // save local results
231 : : (*it)->saveResults ();
232 : : #endif
233 : : }
234 : :
235 : 23084 : return ret;
236 : : }
237 : :
238 : : /* Passes the constants of the environment to the equation solver.
239 : : This is necessary since equally typed environments use the same
240 : : equation checker and solver. */
241 : 282 : void environment::passConstants (void) {
242 [ - + ]: 282 : for (variable * var = root; var != NULL; var = var->getNext ()) {
243 [ # # ][ # # ]: 0 : if (var->getPassing () && var->getType () == VAR_CONSTANT) {
[ # # ]
244 : 0 : constant * c = var->getConstant ();
245 : 0 : setDouble (var->getName (), c->d);
246 : : }
247 : : }
248 : 282 : }
249 : :
250 : : /* Fetches the values of variables from the equation solver. */
251 : 23084 : void environment::fetchConstants (void) {
252 [ + + ]: 55772 : for (variable * var = root; var != NULL; var = var->getNext ()) {
253 [ + + ]: 32688 : if (var->getType () == VAR_CONSTANT) {
254 : 32685 : constant * c = var->getConstant ();
255 [ + - - ]: 32685 : switch (c->getType ()) {
256 : : case TAG_DOUBLE:
257 : 32685 : c->d = getDouble (var->getName ());
258 : 32685 : break;
259 : : case TAG_VECTOR:
260 [ # # ]: 0 : *c->v = getVector (var->getName ());
261 : 32685 : break;
262 : : }
263 : : }
264 : : }
265 : 23084 : }
266 : :
267 : : /* Looks through the environment variables for a given variable name
268 : : being a saved value and returns the variable pointer or NULL if
269 : : there is no such variable. */
270 : 0 : variable * environment::findValue (char * n) {
271 [ # # ]: 0 : for (variable * var = root; var != NULL; var = var->getNext ()) {
272 [ # # ]: 0 : if (var->getType () == VAR_VALUE)
273 [ # # ]: 0 : if (!strcmp (var->getName (), n))
274 : 0 : return var;
275 : : }
276 : 0 : return NULL;
277 : : }
278 : :
279 : : /* Puts the given variable name and its computed result into the list
280 : : of environment variables. */
281 : 0 : void environment::setValue (char * n, constant * value) {
282 : 0 : variable * var = findValue (n);
283 [ # # ]: 0 : if (var != NULL) {
284 : : // replace variable
285 [ # # ]: 0 : delete var->getValue ();
286 [ # # ]: 0 : var->setValue (new constant (*value));
287 : : } else {
288 : : // create new variable
289 [ # # ]: 0 : var = new variable (n);
290 [ # # ]: 0 : var->setValue (new constant (*value));
291 : 0 : addVariable (var);
292 : : }
293 : 0 : }
294 : :
295 : : // Local macro definition to go through the list of equations.
296 : : #define foreach_equation(eqn) \
297 : : for (assignment * (eqn) = A (equations); \
298 : : (eqn) != NULL; (eqn) = A ((eqn)->getNext ()))
299 : :
300 : : // Short helper macro.
301 : : #define A(a) ((assignment *) (a))
302 : :
303 : : /* The function puts local variables (prameters and equation results)
304 : : into the set of environment variables. */
305 : 0 : void environment::saveResults (void) {
306 : 0 : node * equations = checkee->getEquations ();
307 : : // go through equations
308 [ # # ]: 0 : foreach_equation (eqn) {
309 : 0 : char * inst = eqn->getInstance ();
310 [ # # ][ # # ]: 0 : if (inst != NULL && eqn->evaluated) {
311 : 0 : char * result = A(eqn)->result;
312 [ # # ][ # # ]: 0 : if ((inst[0] != '#' && !strchr (result, '.')) ||
[ # # ]
313 : 0 : !strcmp (inst, "#subcircuit")) {
314 : 0 : setValue (result, eqn->getResult ());
315 : : }
316 : : }
317 : : }
318 : 0 : }
319 : :
320 : : /* This function looks through all variables which are references. If
321 : : found the variable gets resolved in the upper (parent) environment
322 : : and the value put into the result of the reference as well as into
323 : : the equation checker of the current environment. */
324 : 282 : void environment::updateReferences (environment * up) {
325 [ - + ]: 282 : for (variable * var = root; var != NULL; var = var->getNext ()) {
326 [ # # ]: 0 : if (var->getType () == VAR_REFERENCE) {
327 : 0 : reference * r = var->getReference ();
328 : : // possible because no self-referring subcircuit types possible
329 : 0 : nr_double_t d = up->getDouble (r->n);
330 : 0 : constant * c = r->getResult ();
331 : 0 : c->d = d;
332 : 0 : setDouble (var->getName (), d);
333 : : }
334 : : }
335 : 282 : }
336 : :
337 : : // Returns vector of an assignment in the equation checker.
338 : 0 : qucs::vector environment::getVector (const char * const ident) const {
339 : 0 : return checkee->getVector (ident);
340 : : }
341 : :
342 : : // Returns double value of an assignment in the equation checker.
343 : 32685 : nr_double_t environment::getDouble (const char * const ident) const {
344 : 32685 : return checkee->getDouble (ident);
345 : : }
346 : :
347 : : // Sets the double value of an assignment in the equation checker.
348 : 22739 : void environment::setDouble (const char * const ident, const nr_double_t val) {
349 : 22739 : checkee->setDouble (ident, val);
350 : 22739 : }
351 : :
352 : : // Return double value of a variable in the environment.
353 : 0 : nr_double_t environment::getDoubleConstant (const char * const ident) const {
354 : 0 : variable * var = getVariable (ident);
355 [ # # ][ # # ]: 0 : if (var != NULL && var->getType () == VAR_CONSTANT) {
[ # # ]
356 : 0 : constant * c = var->getConstant ();
357 : 0 : return c->d;
358 : : }
359 : 0 : return 0.0;
360 : : }
361 : :
362 : : // Sets the double value of a variable in the environment.
363 : 22739 : void environment::setDoubleConstant (const char * const ident, nr_double_t val) {
364 : 22739 : variable * var = getVariable (ident);
365 [ + - ][ + - ]: 22739 : if (var != NULL && var->getType () == VAR_CONSTANT) {
[ + - ]
366 : 22739 : constant * c = var->getConstant ();
367 : 22739 : c->d = val;
368 : : }
369 : 22739 : }
370 : :
371 : : // Returns the referenced value of a variable in the environment.
372 : 0 : char * environment::getDoubleReference (const char * const ident) const {
373 : 0 : variable * var = getVariable (ident);
374 [ # # ][ # # ]: 0 : if (var != NULL && var->getType () == VAR_REFERENCE) {
[ # # ]
375 : 0 : reference * r = var->getReference ();
376 : 0 : return r->n;
377 : : }
378 : 0 : return NULL;
379 : : }
380 : :
381 : : // Sets the referenced value of a variable in the environment.
382 : 0 : void environment::setDoubleReference (const char * const ident, char * val) {
383 : 0 : variable * var = getVariable (ident);
384 [ # # ]: 0 : if (var != NULL) {
385 [ # # ]: 0 : if (var->getType () == VAR_CONSTANT) {
386 : : // its a constant, so make it a reference
387 [ # # ]: 0 : delete var->getConstant ();
388 [ # # ]: 0 : reference * r = new reference ();
389 : 0 : r->n = strdup (val);
390 [ # # ]: 0 : constant * c = new constant (TAG_DOUBLE);
391 : 0 : r->setResult (c);
392 : 0 : var->setReference (r);
393 : : }
394 [ # # ]: 0 : else if (var->getType () == VAR_REFERENCE) {
395 : : // just apply the reference
396 : 0 : reference * r = var->getReference ();
397 [ # # ]: 0 : if (r->n) free (r->n);
398 : 0 : r->n = strdup (val);
399 : : }
400 : : }
401 : 0 : }
402 : :
403 : : //! Prints the environment.
404 : 0 : void environment::print (const bool all) const {
405 : 0 : logprint (LOG_STATUS, "environment %s\n",this->name.c_str());
406 [ # # ]: 0 : for (variable * var = root; var != NULL; var = var->getNext ()) {
407 : 0 : logprint (LOG_STATUS, " %s [%s]\n", var->getName (), var->toString ());
408 : : }
409 [ # # ]: 0 : for (auto it = children.begin(); it != children.end() ; ++it) {
410 [ # # ]: 0 : logprint (LOG_STATUS, " %s\n", (*it)->name.c_str ());
411 : : }
412 [ # # ]: 0 : if (all) {
413 [ # # ]: 0 : for (auto it = children.begin(); it != children.end() ; ++it)
414 [ # # ]: 0 : (*it)->print ();
415 : : }
416 : 0 : }
417 : :
418 : : } // namespace qucs
|