Branch data Line data Source code
1 : : /*
2 : : * equation.cpp - checker for the Qucs equations
3 : : *
4 : : * Copyright (C) 2004-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 <stdio.h>
30 : : #include <stdlib.h>
31 : : #include <string.h>
32 : : #include <cmath>
33 : : #include <ctype.h>
34 : :
35 : : #include "logging.h"
36 : : #include "complex.h"
37 : : #include "object.h"
38 : : #include "vector.h"
39 : : #include "matrix.h"
40 : : #include "matvec.h"
41 : : #include "dataset.h"
42 : : #include "strlist.h"
43 : : #include "netdefs.h"
44 : : #include "equation.h"
45 : : #include "evaluate.h"
46 : : #include "differentiate.h"
47 : : #include "constants.h"
48 : : #include "range.h"
49 : : #include "exception.h"
50 : : #include "exceptionstack.h"
51 : :
52 : : namespace qucs
53 : : {
54 : :
55 : : using namespace eqn;
56 : :
57 : : #define A(a) ((assignment *) (a))
58 : : #define N(n) ((node *) (n))
59 : : #define C(c) ((constant *) (c))
60 : : #define R(r) ((reference *) (r))
61 : :
62 : : // Constructor creates an untyped instance of the constant class.
63 : 0 : constant::constant () : node (CONSTANT)
64 : : {
65 : 0 : type = TAG_UNKNOWN;
66 : 0 : dataref = false;
67 : 0 : d = 0.0;
68 : 0 : setType (type);
69 : 0 : }
70 : :
71 : : // This constructor creates an typed instance of the constant class.
72 : 2627 : constant::constant (int tag) : node (CONSTANT)
73 : : {
74 : 2627 : type = tag;
75 : 2627 : dataref = false;
76 : 2627 : d = 0.0;
77 : 2627 : setType (type);
78 : 2627 : }
79 : :
80 : : /* This copy constructor creates a instance of the constant class
81 : : based on the given constant. */
82 : 81 : constant::constant (const constant & o) : node (o)
83 : : {
84 : 81 : type = o.type;
85 : 81 : dataref = o.dataref;
86 : 81 : d = 0.0;
87 : 81 : setType (type);
88 [ - + - - : 81 : switch (type)
- - - - -
- # # # #
# # # # #
# ]
89 : : {
90 : : case TAG_BOOLEAN:
91 : 0 : b = o.b;
92 : 0 : break;
93 : : case TAG_DOUBLE:
94 : 81 : d = o.d;
95 : 81 : break;
96 : : case TAG_COMPLEX:
97 [ # # ][ # # ]: 0 : c = dataref ? o.c : new nr_complex_t (*o.c);
[ # # ][ # # ]
98 : 0 : break;
99 : : case TAG_VECTOR:
100 [ # # ][ # # ]: 0 : v = dataref ? o.v : new qucs::vector (*o.v);
[ # # ][ # # ]
[ # # ][ # # ]
101 : 0 : break;
102 : : case TAG_MATRIX:
103 [ # # ][ # # ]: 0 : m = dataref ? o.m : new matrix (*o.m);
[ # # ][ # # ]
[ # # ][ # # ]
104 : 0 : break;
105 : : case TAG_MATVEC:
106 [ # # ][ # # ]: 0 : mv = dataref ? o.mv : new matvec (*o.mv);
[ # # ][ # # ]
[ # # ][ # # ]
107 : 0 : break;
108 : : case TAG_STRING:
109 [ # # ][ # # ]: 0 : s = dataref ? o.s : strdup (s);
[ # # ][ # # ]
110 : 0 : break;
111 : : case TAG_CHAR:
112 : 0 : chr = o.chr;
113 : 0 : break;
114 : : case TAG_RANGE:
115 [ # # ][ # # ]: 0 : r = dataref ? o.r : new range (*o.r);
[ # # ][ # # ]
[ # # ][ # # ]
116 : 0 : break;
117 : : }
118 : 81 : }
119 : :
120 : : // Re-creates the given instance.
121 : 0 : node * constant::recreate (void)
122 : : {
123 [ # # ]: 0 : return new constant (*this);
124 : : }
125 : :
126 : : // Destructor deletes an instance of the constant class.
127 : 2702 : constant::~constant ()
128 : : {
129 [ + + ][ # # ]: 2702 : if (!dataref)
130 : : {
131 [ + + - + : 1668 : switch (type)
- - + ][ #
# # # # #
# ]
132 : : {
133 : : case TAG_COMPLEX:
134 : 14 : delete c;
135 : 14 : break;
136 : : case TAG_VECTOR:
137 [ + - ][ + - ]: 226 : delete v;
[ # # ][ # # ]
138 : 226 : break;
139 : : case TAG_MATRIX:
140 [ # # ][ # # ]: 0 : delete m;
[ # # ][ # # ]
141 : 0 : break;
142 : : case TAG_MATVEC:
143 [ + - ][ + - ]: 18 : delete mv;
[ # # ][ # # ]
144 : 18 : break;
145 : : case TAG_STRING:
146 : 0 : free (s);
147 : 0 : break;
148 : : case TAG_RANGE:
149 [ # # ][ # # ]: 0 : delete r;
[ # # ][ # # ]
150 : 1668 : break;
151 : : }
152 : : }
153 [ - + ][ # # ]: 5404 : }
154 : :
155 : : /* Depending on the type of constant the function prints the textual
156 : : representation of the object. */
157 : 0 : void constant::print (void)
158 : : {
159 : 0 : logprint (LOG_STATUS, "%s", toString ());
160 : 0 : }
161 : :
162 : : // Returns the string representation of a complex value.
163 : 0 : static char * Cplx2String (nr_complex_t c)
164 : : {
165 : : static char str[256]; // enough for a real or complex number
166 [ # # ]: 0 : if (imag (c) == 0.0)
167 : : {
168 : 0 : sprintf (str, "%g", (double) real (c));
169 : : }
170 : : else
171 : : {
172 : : sprintf (str, "(%g%cj%g)", (double ) real (c),
173 [ # # ]: 0 : imag (c) >= 0.0 ? '+' : '-', (double) fabs (imag (c)));
174 : : }
175 : 0 : return str;
176 : : }
177 : :
178 : : /* This function returns a string representation depending on the type
179 : : of constant. */
180 : 0 : char * constant::toString (void)
181 : : {
182 : : char str[256];
183 [ # # ]: 0 : if (txt != NULL) free (txt);
184 [ # # # # : 0 : switch (type)
# # # # #
# ]
185 : : {
186 : : case TAG_BOOLEAN:
187 [ # # ]: 0 : sprintf (str, "%d", b ? 1 : 0);
188 [ # # ]: 0 : txt = strdup (str);
189 : 0 : break;
190 : : case TAG_DOUBLE:
191 : 0 : sprintf (str, "%g", (double) d);
192 [ # # ]: 0 : txt = strdup (str);
193 : 0 : break;
194 : : case TAG_COMPLEX:
195 [ # # ]: 0 : txt = strdup (Cplx2String (*c));
196 : 0 : break;
197 : : case TAG_VECTOR:
198 : : {
199 [ # # ]: 0 : int pos = 1, len = 3 + v->getSize () - 1;
200 : 0 : txt = (char *) malloc (len);
201 : 0 : strcpy (txt, "[");
202 [ # # ][ # # ]: 0 : for (int i = 0; i < v->getSize (); i++)
203 : : {
204 [ # # ]: 0 : char * s = Cplx2String (v->get (i));
205 : 0 : txt = (char *) realloc (txt, len += strlen (s));
206 : 0 : strcpy (&txt[pos], s);
207 : 0 : pos += strlen (s);
208 [ # # ][ # # ]: 0 : if (i != v->getSize () - 1) strcpy (&txt[pos++], ";");
209 : : }
210 : 0 : strcpy (&txt[pos], "]");
211 : : }
212 : 0 : break;
213 : : case TAG_MATRIX:
214 : : {
215 : 0 : int len = 3 + (m->getRows () - 1) * m->getCols () + (m->getCols () - 1);
216 : 0 : txt = (char *) malloc (len);
217 : 0 : strcpy (txt, "[");
218 [ # # ]: 0 : for (int r = 0; r < m->getRows (); r++)
219 : : {
220 [ # # ]: 0 : for (int c = 0; c < m->getCols (); c++)
221 : : {
222 [ # # ]: 0 : char * s = Cplx2String (m->get (r, c));
223 : 0 : txt = (char *) realloc (txt, len += strlen (s));
224 : 0 : strcat (txt, s);
225 [ # # ]: 0 : if (c != m->getCols () - 1) strcat (txt, ",");
226 : : }
227 [ # # ]: 0 : if (r != m->getRows () - 1) strcat (txt, ";");
228 : : }
229 : 0 : strcat (txt, "]");
230 : : }
231 : 0 : break;
232 : : case TAG_MATVEC:
233 : : sprintf (str, "[%dx%d](%d)",
234 : 0 : mv->getRows (), mv->getCols (), mv->getSize ());
235 [ # # ]: 0 : txt = strdup (str);
236 : 0 : break;
237 : : case TAG_CHAR:
238 : 0 : sprintf (str, "'%c'", chr);
239 [ # # ]: 0 : txt = strdup (str);
240 : 0 : break;
241 : : case TAG_STRING:
242 : 0 : sprintf (str, "'%s'", s);
243 [ # # ]: 0 : txt = strdup (str);
244 : 0 : break;
245 : : case TAG_RANGE:
246 [ # # ][ # # ]: 0 : txt = strdup (r->toString ());
247 : 0 : break;
248 : : default:
249 [ # # ]: 0 : txt = strdup ("(no such type)");
250 : 0 : break;
251 : : }
252 : 0 : return txt;
253 : : }
254 : :
255 : : // Returns the type of constant.
256 : 128116 : int constant::evalType (void)
257 : : {
258 : 128116 : return getType ();
259 : : }
260 : :
261 : : // Returns the result stored in the constant.
262 : 126864 : constant * constant::evaluate (void)
263 : : {
264 : 126864 : setResult (this);
265 : 126864 : return getResult ();
266 : : }
267 : :
268 : : // Returns the derivative of a constant.
269 : 0 : node * constant::differentiate (char *)
270 : : {
271 [ # # ]: 0 : constant * res = new constant (TAG_DOUBLE);
272 : 0 : res->d = 0;
273 : 0 : return res;
274 : : }
275 : :
276 : : // Constructor creates an instance of the reference class.
277 : 259 : reference::reference () : node (REFERENCE)
278 : : {
279 : 259 : n = NULL;
280 : 259 : ref = NULL;
281 : 259 : }
282 : :
283 : : /* This copy constructor creates a instance of the reference class
284 : : based on the given reference. */
285 : 0 : reference::reference (const reference & o) : node (o)
286 : : {
287 [ # # ][ # # ]: 0 : n = o.n ? strdup (o.n) : NULL;
[ # # ][ # # ]
288 : 0 : ref = o.ref;
289 : 0 : }
290 : :
291 : : // Re-creates the given instance.
292 : 0 : node * reference::recreate (void)
293 : : {
294 [ # # ]: 0 : return new reference (*this);
295 : : }
296 : :
297 : : // Replaces reference name by the new given name.
298 : 0 : void reference::replace (char * src, char * dst)
299 : : {
300 [ # # ]: 0 : if (!strcmp (src, n))
301 : : {
302 : 0 : free (n);
303 [ # # ]: 0 : n = dst ? strdup (dst) : NULL;
304 : : }
305 : 0 : }
306 : :
307 : : // Destructor deletes an instance of the reference class.
308 : 259 : reference::~reference ()
309 : : {
310 [ + - ][ # # ]: 259 : if (n) free (n);
311 [ - + ][ # # ]: 518 : }
312 : :
313 : : // Prints textual representation of the reference object.
314 : 0 : void reference::print (void)
315 : : {
316 : 0 : logprint (LOG_STATUS, "%s", toString ());
317 : 0 : }
318 : :
319 : : // Returns textual representation of the reference object.
320 : 0 : char * reference::toString (void)
321 : : {
322 [ # # ]: 0 : if (txt) free (txt);
323 : 0 : txt = strdup (n);
324 : 0 : return txt;
325 : : }
326 : :
327 : : // Adds the name of the reference to the list of dependencies.
328 : 9108 : void reference::addDependencies (strlist * depends)
329 : : {
330 : 9108 : depends->add (n);
331 : 9108 : findVariable ();
332 : 9108 : }
333 : :
334 : : // Find and save the actual equation reference.
335 : 10527 : void reference::findVariable (void)
336 : : {
337 : 10527 : ref = NULL; // force reference to be updated
338 [ + - ]: 10527 : if (!ref)
339 : : {
340 : : node * eqn;
341 [ + - ]: 10527 : if (checkee != NULL)
342 : : {
343 [ + + ]: 82371 : for (eqn = checkee->getEquations (); eqn; eqn = eqn->getNext ())
344 : : {
345 [ + + ]: 71844 : if (!strcmp (n, A(eqn)->result))
346 : : {
347 : 3854 : ref = eqn;
348 : 3854 : break;
349 : : }
350 : : }
351 : : }
352 [ + + ][ - + ]: 10527 : if (solvee != NULL && !ref)
353 : : {
354 [ # # ]: 0 : for (eqn = solvee->getEquations (); eqn; eqn = eqn->getNext ())
355 : : {
356 [ # # ]: 0 : if (!strcmp (n, A(eqn)->result))
357 : : {
358 : 0 : ref = eqn;
359 : 0 : break;
360 : : }
361 : : }
362 : : }
363 : : }
364 : 10527 : }
365 : :
366 : : // Returns the type of reference.
367 : 797 : int reference::evalType (void)
368 : : {
369 : 797 : setType (TAG_UNKNOWN);
370 : 797 : findVariable ();
371 [ + - ]: 797 : if (ref != NULL)
372 : : {
373 : 797 : setType (A(ref)->body->evalType ());
374 : : }
375 : 797 : return getType ();
376 : : }
377 : :
378 : : // Returns the actual result of the reference.
379 : 622 : constant * reference::evaluate (void)
380 : : {
381 : 622 : setResult (NULL);
382 : 622 : findVariable ();
383 [ + - ]: 622 : if (ref != NULL)
384 : : {
385 : 622 : setResult (A(ref)->body->getResult ());
386 : : }
387 : 622 : return getResult ();
388 : : }
389 : :
390 : : // Returns the derivative of a reference.
391 : 0 : node * reference::differentiate (char * derivative)
392 : : {
393 [ # # ]: 0 : constant * res = new constant (TAG_DOUBLE);
394 [ # # ][ # # ]: 0 : if (n != NULL && !strcmp (n, derivative))
395 : 0 : res->d = 1;
396 : : else
397 : 0 : res->d = 0;
398 : 0 : return res;
399 : : }
400 : :
401 : : // Constructor creates an instance of the assignment class.
402 : 1787 : assignment::assignment () : node (ASSIGNMENT)
403 : : {
404 : 1787 : body = NULL;
405 : 1787 : result = NULL;
406 : 1787 : }
407 : :
408 : : /* This copy constructor creates a instance of the assignment class
409 : : based on the given assignment. */
410 : 0 : assignment::assignment (const assignment & o) : node (o)
411 : : {
412 [ # # # # ]: 0 : body = o.body->recreate ();
413 [ # # ][ # # ]: 0 : result = o.result ? strdup (o.result) : NULL;
[ # # ][ # # ]
414 : 0 : }
415 : :
416 : : // Re-creates the given instance.
417 : 0 : node * assignment::recreate (void)
418 : : {
419 [ # # ]: 0 : return new assignment (*this);
420 : : }
421 : :
422 : : // Replaces reference name by the new given name.
423 : 0 : void assignment::replace (char * src, char * dst)
424 : : {
425 : 0 : body->replace (src, dst);
426 : 0 : }
427 : :
428 : : // Renames the left hand side of the assignment.
429 : 0 : void assignment::rename (char * n)
430 : : {
431 [ # # ]: 0 : if (result) free (result);
432 [ # # ]: 0 : result = n ? strdup (n) : NULL;
433 : 0 : }
434 : :
435 : : // Destructor deletes an instance of the assignment class.
436 : 1787 : assignment::~assignment ()
437 : : {
438 [ + - ][ + - ]: 1787 : delete body;
[ # # ][ # # ]
439 [ + - ][ # # ]: 1787 : if (result) free (result);
440 [ - + ][ # # ]: 3574 : }
441 : :
442 : : // Prints textual representation of the assignment object.
443 : 0 : void assignment::print (void)
444 : : {
445 : 0 : logprint (LOG_STATUS, "%s", toString ());
446 : 0 : }
447 : :
448 : : // Returns textual representation of the assignment object.
449 : 0 : char * assignment::toString (void)
450 : : {
451 [ # # ]: 0 : if (txt) free (txt);
452 : 0 : char * str = body->toString ();
453 : 0 : txt = (char *) malloc (strlen (result) + strlen (str) + 4);
454 : 0 : sprintf (txt, "%s = %s", result, str);
455 : 0 : return txt;
456 : : }
457 : :
458 : : // Adds the right hand side of the assignment to the list of dependencies.
459 : 132971 : void assignment::addDependencies (strlist * depends)
460 : : {
461 : 132971 : body->checkee = checkee;
462 : 132971 : body->addDependencies (depends);
463 : 132971 : }
464 : :
465 : : // Returns the type of assignment.
466 : 127444 : int assignment::evalType (void)
467 : : {
468 : 127444 : setType (body->evalType ());
469 : 127444 : return getType ();
470 : : }
471 : :
472 : : // Returns the result of the assignment.
473 : 126963 : constant * assignment::evaluate (void)
474 : : {
475 : 126963 : body->solvee = solvee;
476 : 126963 : setResult (body->evaluate ());
477 : : // inherit drop/prep dependencies of applications
478 [ + + ]: 126963 : if (body->getResult()->dropdeps)
479 : : {
480 : 7 : getResult()->dropdeps = body->getResult()->dropdeps;
481 : 7 : strlist * preps = body->getPrepDependencies ();
482 [ - + ][ # # ]: 7 : if (preps) getResult()->setPrepDependencies (new strlist (*preps));
483 : : }
484 : 126963 : return getResult ();
485 : : }
486 : :
487 : : // Returns the derivative of an assignment.
488 : 0 : node * assignment::differentiate (char * derivative)
489 : : {
490 : 0 : char * txt = (char *) malloc (strlen (result) + strlen (derivative) + 4);
491 : 0 : sprintf (txt, "d%s_d%s", result, derivative);
492 [ # # ]: 0 : assignment * res = new assignment ();
493 : 0 : res->result = txt;
494 : 0 : res->body = body->differentiate (derivative);
495 : 0 : return res;
496 : : }
497 : :
498 : : // Some small helpers.
499 : : #define D(con) (C(con)->d)
500 : : #define isConst(n) ((n)->getTag()==CONSTANT && C(n)->getType()==TAG_DOUBLE)
501 : : #define isZero(n) (isConst(n) && D(n) == 0.0)
502 : : #define isOne(n) (isConst(n) && D(n) == 1.0)
503 : : #define defCon(res,val) res = new constant (TAG_DOUBLE); C(res)->d = val;
504 : :
505 : : /* Multiply two assignments. */
506 : 0 : void assignment::mul (assignment * f)
507 : : {
508 : 0 : node * factor = f->body->recreate ();
509 [ # # ][ # # ]: 0 : if (isZero (body) || isZero (factor))
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
510 : : {
511 [ # # ]: 0 : delete body;
512 [ # # ]: 0 : delete factor;
513 [ # # ]: 0 : defCon (body, 0);
514 : : }
515 [ # # ][ # # ]: 0 : else if (isOne (body))
[ # # ][ # # ]
516 : : {
517 [ # # ]: 0 : delete body;
518 : 0 : body = factor;
519 : : }
520 [ # # ][ # # ]: 0 : else if (isOne (factor))
[ # # ][ # # ]
521 : : {
522 [ # # ]: 0 : delete factor;
523 : 0 : body = body;
524 : : }
525 : : else
526 : : {
527 [ # # ]: 0 : application * mul = new application ("*", 2);
528 : 0 : mul->args = body;
529 : 0 : mul->args->append (factor);
530 : 0 : body = mul;
531 : : }
532 : 0 : }
533 : :
534 : : /* Multiply two assignments by reference. */
535 : 0 : void assignment::mulref (assignment * f)
536 : : {
537 : 0 : node * factor = f->body->recreate ();
538 [ # # ]: 0 : reference * r = new reference ();
539 : 0 : r->n = strdup (f->result);
540 [ # # ][ # # ]: 0 : if (isZero (body) || isZero (factor))
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
541 : : {
542 [ # # ]: 0 : delete body;
543 [ # # ]: 0 : defCon (body, 0);
544 : : }
545 [ # # ][ # # ]: 0 : else if (isOne (body))
[ # # ][ # # ]
546 : : {
547 : 0 : body = r;
548 : : }
549 [ # # ][ # # ]: 0 : else if (isOne (factor))
[ # # ][ # # ]
550 : : {
551 : 0 : body = body;
552 : : }
553 : : else
554 : : {
555 [ # # ]: 0 : application * mul = new application ("*", 2);
556 : 0 : mul->args = body;
557 : 0 : mul->args->append (r);
558 : 0 : body = mul;
559 : : }
560 : 0 : }
561 : :
562 : : /* Add two assignments. */
563 : 0 : void assignment::add (assignment * f)
564 : : {
565 : 0 : node * factor = f->body->recreate ();
566 [ # # ][ # # ]: 0 : if (isZero (body) && isZero (factor))
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
567 : : {
568 [ # # ]: 0 : delete body;
569 [ # # ]: 0 : delete factor;
570 [ # # ]: 0 : defCon (body, 0);
571 : : }
572 [ # # ][ # # ]: 0 : else if (isZero (body))
[ # # ][ # # ]
573 : : {
574 [ # # ]: 0 : delete body;
575 : 0 : body = factor;
576 : : }
577 [ # # ][ # # ]: 0 : else if (isZero (factor))
[ # # ][ # # ]
578 : : {
579 [ # # ]: 0 : delete factor;
580 : 0 : body = body;
581 : : }
582 : : else
583 : : {
584 [ # # ]: 0 : application * add = new application ("+", 2);
585 : 0 : add->args = body;
586 : 0 : add->args->append (factor);
587 : 0 : body = add;
588 : : }
589 : 0 : }
590 : :
591 : : // Constructor creates an instance of the application class.
592 : 285 : application::application () : node (APPLICATION)
593 : : {
594 : 285 : n = NULL;
595 : 285 : nargs = 0;
596 : 285 : args = NULL;
597 : 285 : eval = NULL;
598 : 285 : derive = NULL;
599 : 285 : ddx = NULL;
600 : 285 : }
601 : :
602 : : /* Constructor creates an instance of the application class with a
603 : : given function name and the number of arguments. */
604 : 0 : application::application (const char * func, int a) : node (APPLICATION)
605 : : {
606 [ # # ][ # # ]: 0 : n = func ? strdup (func) : NULL;
[ # # ][ # # ]
607 : 0 : nargs = a;
608 : 0 : args = NULL;
609 : 0 : eval = NULL;
610 : 0 : derive = NULL;
611 : 0 : ddx = NULL;
612 : 0 : }
613 : :
614 : : /* This copy constructor creates a instance of the application class
615 : : based on the given application. */
616 : 0 : application::application (const application & o) : node (o)
617 : : {
618 [ # # ][ # # ]: 0 : n = o.n ? strdup (o.n) : NULL;
[ # # ][ # # ]
619 : 0 : nargs = o.nargs;
620 [ # # ][ # # ]: 0 : if (o.args != NULL)
621 : : {
622 : 0 : node * arg = o.args;
623 [ # # ][ # # ]: 0 : args = arg->recreate ();
624 [ # # ][ # # ]: 0 : for (arg = arg->getNext (); arg != NULL; arg = arg->getNext ())
625 : : {
626 [ # # ][ # # ]: 0 : args->append (arg->recreate ());
627 : : }
628 : : }
629 : 0 : else args = NULL;
630 : 0 : eval = o.eval;
631 : 0 : derive = o.derive;
632 [ # # ][ # # ]: 0 : ddx = o.ddx ? o.ddx->recreate () : NULL;
[ # # ][ # # ]
633 : 0 : }
634 : :
635 : : // Re-creates the given instance.
636 : 0 : node * application::recreate (void)
637 : : {
638 [ # # ]: 0 : return new application (*this);
639 : : }
640 : :
641 : : // Replaces reference name by the new given name.
642 : 0 : void application::replace (char * src, char * dst)
643 : : {
644 [ # # ]: 0 : for (node * arg = args; arg != NULL; arg = arg->getNext ())
645 : : {
646 : 0 : arg->replace (src, dst);
647 : : }
648 [ # # ]: 0 : if (ddx) ddx->replace (src, dst);
649 : 0 : }
650 : :
651 : : // Destructor deletes an instance of the application class.
652 : 285 : application::~application ()
653 : : {
654 : : node * next, * res;
655 [ + + ][ # # ]: 766 : for (node * arg = args; arg != NULL; arg = next)
656 : : {
657 : 481 : next = arg->getNext ();
658 [ + - ]: 481 : delete arg;
[ + - # # ]
[ # # ]
659 : : }
660 [ + - ][ + - ]: 285 : if ((res = getResult ()) != NULL) delete res;
[ + - ][ # # ]
[ # # ][ # # ]
661 [ + - ][ # # ]: 285 : if (n) free (n);
662 [ - + ][ # # ]: 285 : if (ddx) delete ddx;
[ # # ][ # # ]
[ # # ][ # # ]
663 [ - + ][ # # ]: 570 : }
664 : :
665 : : // Prints textual representation of the application object.
666 : 0 : void application::print (void)
667 : : {
668 : 0 : logprint (LOG_STATUS, "%s", toString ());
669 : 0 : }
670 : :
671 : : // Returns textual representation of the application object.
672 : 0 : char * application::toString (void)
673 : : {
674 [ # # ]: 0 : if (txt) free (txt);
675 : : // binary operations
676 [ # # ][ # # ]: 0 : if ((!strcmp (n, "+") || !strcmp (n, "-") || !strcmp (n, "*") ||
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
677 : 0 : !strcmp (n, "/") || !strcmp (n, "^") || !strcmp (n, "%") ||
678 : 0 : !strcmp (n, "<") || !strcmp (n, ">") || !strcmp (n, "<=") ||
679 : 0 : !strcmp (n, ">=") || !strcmp (n, "&&") || !strcmp (n, "||") ||
680 : 0 : !strcmp (n, "==") || !strcmp (n, "!="))
681 : : && nargs == 2)
682 : : {
683 : 0 : char * arg1 = args->toString ();
684 : 0 : char * arg2 = args->getNext()->toString ();
685 : 0 : txt = (char *) malloc (strlen (n) + strlen (arg1) + strlen (arg2) + 3);
686 : 0 : sprintf (txt, "(%s%s%s)", arg1, n, arg2);
687 : : }
688 : : // ternary ?: operator
689 [ # # ]: 0 : else if (!strcmp (n, "?:"))
690 : : {
691 : 0 : char * arg1 = args->toString ();
692 : 0 : char * arg2 = args->getNext()->toString ();
693 : 0 : char * arg3 = args->getNext()->getNext()->toString ();
694 : 0 : txt = (char *) malloc (strlen (arg3) + strlen (arg1) + strlen (arg2) + 5);
695 : 0 : sprintf (txt, "(%s?%s:%s)", arg1, arg2, arg3);
696 : : }
697 : : // array indices
698 [ # # ]: 0 : else if (!strcmp (n, "array"))
699 : : {
700 : 0 : int len = strlen (args->toString ()) + 3 + nargs - 1;
701 : 0 : txt = (char *) malloc (len);
702 : 0 : sprintf (txt, "%s[", args->toString ());
703 [ # # ]: 0 : for (node * arg = args->getNext (); arg != NULL; arg = arg->getNext ())
704 : : {
705 : 0 : char * str = arg->toString ();
706 : 0 : txt = (char *) realloc (txt, len += strlen (str));
707 : 0 : strcat (txt, str);
708 [ # # ]: 0 : if (arg->getNext ()) strcat (txt, ",");
709 : : }
710 : 0 : strcat (txt, "]");
711 : : }
712 : : // vectors and matrices
713 [ # # ][ # # ]: 0 : else if (!strcmp (n, "vector") || !strcmp (n, "matrix"))
714 : : {
715 : 0 : int len = 3 + nargs - 1;
716 : 0 : txt = (char *) malloc (len);
717 : 0 : sprintf (txt, "[");
718 [ # # ]: 0 : for (node * arg = args; arg != NULL; arg = arg->getNext ())
719 : : {
720 [ # # ]: 0 : if (arg->getType () == TAG_CHAR)
721 : : {
722 : 0 : txt = (char *) realloc (txt, len++);
723 : 0 : strcat (txt, ";");
724 : : }
725 : : else
726 : : {
727 : 0 : char * str = arg->toString ();
728 : 0 : txt = (char *) realloc (txt, len += strlen (str));
729 : 0 : strcat (txt, str);
730 : 0 : node * next = arg->getNext ();
731 [ # # ][ # # ]: 0 : if (next && next->getType () != TAG_CHAR) strcat (txt, ",");
[ # # ]
732 : : }
733 : : }
734 : 0 : strcat (txt, "]");
735 : : }
736 : : // unary and n-ary operations here
737 : : else
738 : : {
739 : 0 : int len = strlen (n) + 3 + nargs - 1;
740 : 0 : txt = (char *) malloc (len);
741 : 0 : sprintf (txt, "%s(", n);
742 [ # # ]: 0 : for (node * arg = args; arg != NULL; arg = arg->getNext ())
743 : : {
744 : 0 : char * str = arg->toString ();
745 : 0 : txt = (char *) realloc (txt, len += strlen (str));
746 : 0 : strcat (txt, str);
747 [ # # ]: 0 : if (arg->getNext ()) strcat (txt, ",");
748 : : }
749 : 0 : strcat (txt, ")");
750 : : }
751 : 0 : return txt;
752 : : }
753 : :
754 : : // Adds the arguments of the application to the list of dependencies.
755 : 8611 : void application::addDependencies (strlist * depends)
756 : : {
757 [ + + ]: 22715 : for (node * arg = args; arg != NULL; arg = arg->getNext ())
758 : : {
759 : 14104 : arg->checkee = checkee;
760 : 14104 : arg->addDependencies (depends);
761 : : }
762 : 8611 : }
763 : :
764 : : /* This function goes through the arguments of an application and
765 : : evaluates their return types. */
766 : 1008 : void application::evalTypeArgs (void)
767 : : {
768 [ + + ]: 2688 : for (node * arg = args; arg != NULL; arg = arg->getNext ())
769 : : {
770 : : // Skip evaluating generated reference variables.
771 [ + + ]: 1680 : if (arg->getTag () == REFERENCE)
772 [ - + ]: 797 : if (checker::isGenerated (R (arg)->n))
773 : 0 : continue;
774 : : // Evaluate the type of argument.
775 : 1680 : arg->evalType ();
776 : : }
777 : 1008 : }
778 : :
779 : : #include "gperfapphash.cpp"
780 : :
781 : : /* The function creates a hash key for the given type of
782 : : application. */
783 : 1008 : char * application::createKey (void)
784 : : {
785 : 1008 : char * key = (char *) calloc (1, strlen (n) + nargs * 3 + 5);
786 : 1008 : strcat (key, n);
787 [ + + ]: 2688 : for (node * arg = args; arg != NULL; arg = arg->getNext ())
788 : : {
789 : 1680 : strcat (key, "_");
790 : 1680 : strcat (key, checker::tag2key (arg->getType ()));
791 : : }
792 : 1008 : return key;
793 : : }
794 : :
795 : : /* This function returns the return type of the application using a
796 : : gperf-generated hash. */
797 : 1008 : int application::evalTypeFast (void)
798 : : {
799 : 1008 : char * key = createKey ();
800 : 1008 : struct appindex * idx = gperfapphash::get (key, strlen (key));
801 : 1008 : free (key);
802 [ + - ]: 1008 : if (idx != NULL)
803 : : {
804 : 1008 : application_t * app = &applications[idx->index];
805 [ + - ]: 1008 : if (app->eval)
806 : : {
807 : 1008 : eval = app->eval;
808 : 1008 : setType (app->retval);
809 : : }
810 : : }
811 : 1008 : return getType ();
812 : : }
813 : :
814 : : // Macro to identify ddx() application.
815 : : #define isDDX() (nargs == 2 && !strcmp (n, "ddx") && \
816 : : args->getNext()->getTag () == REFERENCE)
817 : :
818 : : /* Returns the type of application and applies the appropriate
819 : : evaluation function if any. */
820 : 1008 : int application::evalType (void)
821 : : {
822 : : // Evaluate type of ddx().
823 [ + + ][ - + ]: 1008 : if (isDDX ())
[ # # ][ - + ]
824 : : {
825 : 0 : args->evalType ();
826 [ # # ]: 0 : if (!ddx) ddx = args->differentiate (R(args->getNext())->n);
827 : 0 : setType (ddx->evalType ());
828 : 0 : return getType ();
829 : : }
830 : 1008 : setType (TAG_UNKNOWN);
831 : : // Evaluate type of arguments.
832 : 1008 : evalTypeArgs ();
833 : : // Find an appropriate differentiator.
834 : 1008 : findDifferentiator ();
835 : : // Try the fast method.
836 [ + - ]: 1008 : if (evalTypeFast () != TAG_UNKNOWN) return getType ();
837 : :
838 : : // Go through the list of available applications.
839 [ # # ]: 0 : for (int i = 0; applications[i].application != NULL; i++)
840 : : {
841 : 0 : application_t * app = &applications[i];
842 : : // The correct application?
843 [ # # ]: 0 : if (!strcmp (n, app->application))
844 : : {
845 : 0 : int nr = 0;
846 [ # # ]: 0 : if (app->nargs >= 0)
847 : : {
848 : : // The correct number of arguments?
849 [ # # ]: 0 : if (nargs != app->nargs) continue;
850 : : // The correct types of arguments?
851 [ # # ]: 0 : for (node * arg = args; arg != NULL; arg = arg->getNext (), nr++)
852 : : {
853 [ # # ]: 0 : if (arg->getTag () == REFERENCE)
854 : : // Skip checking generated reference variables.
855 [ # # ]: 0 : if (checker::isGenerated (R (arg)->n))
856 : 0 : continue;
857 : : // Evaluate and check the type of argument.
858 [ # # ]: 0 : if (!(arg->getType () & app->args[nr]))
859 : : {
860 : 0 : nr = -1;
861 : 0 : break;
862 : : }
863 : : }
864 [ # # ]: 0 : if (nr == -1) continue;
865 : : }
866 : : // A valid application function?
867 [ # # ]: 0 : if (app->eval == NULL) continue;
868 : : // Everything just fine here.
869 : 0 : eval = app->eval;
870 : 0 : setType (app->retval);
871 : 0 : break;
872 : : }
873 : : }
874 : : // Emit error message if necessary.
875 [ # # ]: 0 : if (getType () == TAG_UNKNOWN)
876 : : {
877 : : logprint (LOG_ERROR, "checker error, no appropriate function for `%s'"
878 : 0 : " found\n", toString ());
879 : : }
880 : 1008 : return getType ();
881 : : }
882 : :
883 : : /* This function returns zero if the applications differentiation
884 : : function could be found and otherwise non-zero. */
885 : 1008 : int application::findDifferentiator (void)
886 : : {
887 [ + + ]: 10268 : for (int i = 0; differentiations[i].application != NULL; i++)
888 : : {
889 [ + + ][ + + ]: 10138 : if (!strcmp (n, differentiations[i].application) &&
890 : : nargs == differentiations[i].nargs)
891 : : {
892 : 878 : derive = differentiations[i].derive;
893 : 878 : return 0;
894 : : }
895 : : }
896 : 1008 : return -1;
897 : : }
898 : :
899 : : /* This function runs the actual evaluation function and the returns
900 : : the result. */
901 : 816 : constant * application::evaluate (void)
902 : : {
903 : : // Evaluate ddx() function.
904 [ + + ][ - + ]: 816 : if (isDDX ())
[ # # ][ - + ]
905 : : {
906 [ # # ][ # # ]: 0 : if (getResult ()) delete getResult ();
907 : 0 : setResult (C (ddx->evaluate()->recreate ()));
908 : 0 : return getResult ();
909 : : }
910 : :
911 : 816 : int errors = 0;
912 [ + - ]: 816 : strlist * apreps = new strlist ();
913 : :
914 : : // first evaluate each argument
915 [ + + ]: 2152 : for (node * arg = args; arg != NULL; arg = arg->getNext ())
916 : : {
917 : : // FIXME: Can save evaluation of already evaluated equations?
918 : : if (arg->evaluated == 0 || 1)
919 : : {
920 : 1336 : arg->solvee = solvee;
921 : 1336 : arg->evaluate ();
922 [ - + ]: 1336 : if (arg->getResult () == NULL)
923 : : {
924 [ # # ]: 0 : if (arg->getTag () == REFERENCE)
925 : : {
926 : : logprint (LOG_ERROR, "evaluate error, no such generated variable "
927 : 0 : "`%s'\n", arg->toString ());
928 : : }
929 : : else
930 : : {
931 : : logprint (LOG_ERROR, "evaluate error, unable to evaluate "
932 : 0 : "`%s'\n", arg->toString ());
933 : : }
934 : 0 : errors++;
935 : : }
936 : : else
937 : : {
938 : : // inherit drop/prep dependencies
939 [ + + ]: 1336 : if (arg->getResult()->dropdeps)
940 : : {
941 : 6 : strlist * preps = arg->getResult()->getPrepDependencies ();
942 : : // recall longest prep dependencies' list of arguments
943 [ + - ][ + + ]: 6 : if (preps && (preps->length () > apreps->length ()))
[ + + ]
944 : : {
945 [ + - ]: 4 : delete apreps;
946 [ + - ]: 4 : apreps = new strlist (*preps);
947 : : }
948 : : }
949 : 1336 : arg->evaluated++;
950 : : }
951 : : }
952 : : }
953 : :
954 : : // then evaluate application itself
955 [ + - ]: 816 : if (!errors)
956 : : {
957 : : node * res;
958 : : // delete previous result if necessary
959 [ + + ][ + - ]: 816 : if ((res = getResult ()) != NULL) delete res;
960 : : // then evaluate the application
961 : 816 : setResult (eval (C (args)));
962 : : // check the returned type once again
963 [ - + ]: 816 : if (getResult()->getType () != getType ())
964 : : {
965 : : logprint (LOG_ERROR, "evaluate error, function `%s' returned invalid "
966 : 0 : "constant type\n", toString ());
967 : : }
968 : : }
969 : :
970 : : // inherit prep dependencies of arguments if necessary
971 [ + + ][ + + ]: 816 : if (!getResult()->dropdeps && apreps->length () > 0)
[ + + ]
972 : : {
973 : 4 : getResult()->dropdeps = 1;
974 : 4 : getResult()->appendPrepDependencies (apreps);
975 : : }
976 [ + - ]: 816 : delete apreps;
977 : :
978 : 816 : return getResult ();
979 : : }
980 : :
981 : : // Returns the derivative of an application.
982 : 0 : node * application::differentiate (char * derivative)
983 : : {
984 [ # # ][ # # ]: 0 : if (isDDX ())
[ # # ][ # # ]
985 : : {
986 : 0 : return ddx->differentiate (derivative);
987 : : }
988 [ # # ]: 0 : if (derive)
989 : 0 : return derive (this, derivative);
990 : 0 : return recreate ();
991 : : }
992 : :
993 : : // Constructor creates an untyped instance of the equation node class.
994 : 0 : node::node ()
995 : : {
996 : 0 : tag = UNKNOWN;
997 : 0 : dropdeps = output = evaluated = evalPossible = cycle = duplicate = skip = 0;
998 : 0 : next = NULL;
999 : 0 : dependencies = NULL;
1000 : 0 : dataDependencies = NULL;
1001 : 0 : dropDependencies = NULL;
1002 : 0 : prepDependencies = NULL;
1003 : 0 : txt = NULL;
1004 : 0 : res = NULL;
1005 : 0 : instance = NULL;
1006 : 0 : solvee = NULL;
1007 : 0 : checkee = NULL;
1008 : 0 : }
1009 : :
1010 : : // This constructor creates an typed instance of the equation node class.
1011 : 4958 : node::node (int type)
1012 : : {
1013 : 4958 : tag = type;
1014 : 4958 : dropdeps = output = evaluated = evalPossible = cycle = duplicate = skip = 0;
1015 : 4958 : next = NULL;
1016 : 4958 : dependencies = NULL;
1017 : 4958 : dataDependencies = NULL;
1018 : 4958 : dropDependencies = NULL;
1019 : 4958 : prepDependencies = NULL;
1020 : 4958 : txt = NULL;
1021 : 4958 : res = NULL;
1022 : 4958 : instance = NULL;
1023 : 4958 : solvee = NULL;
1024 : 4958 : checkee = NULL;
1025 : 4958 : }
1026 : :
1027 : : /* This copy constructor creates a instance of the node class based on
1028 : : the given node. */
1029 : 81 : node::node (const node & o)
1030 : : {
1031 : 81 : tag = o.tag;
1032 : 81 : dropdeps = output = evaluated = evalPossible = cycle = duplicate = skip = 0;
1033 : 81 : next = NULL;
1034 : 81 : dependencies = NULL;
1035 : 81 : dataDependencies = NULL;
1036 : 81 : dropDependencies = NULL;
1037 : 81 : prepDependencies = NULL;
1038 : 81 : txt = NULL;
1039 : 81 : res = NULL;
1040 : 81 : instance = NULL;
1041 : 81 : solvee = o.solvee;
1042 : 81 : checkee = o.checkee;
1043 : 81 : }
1044 : :
1045 : : // Destructor deletes an instance of the equation node class.
1046 : 5033 : node::~node ()
1047 : : {
1048 [ # # ][ # # ]: 5033 : if (dependencies) delete dependencies;
[ + + ][ + - ]
1049 [ # # ][ # # ]: 5033 : if (dataDependencies) delete dataDependencies;
[ + + ][ + - ]
1050 [ # # ][ # # ]: 5033 : if (dropDependencies) delete dropDependencies;
[ - + ][ # # ]
1051 [ # # ][ # # ]: 5033 : if (prepDependencies) delete prepDependencies;
[ + + ][ + - ]
1052 [ # # ][ - + ]: 5033 : if (txt) free (txt);
1053 [ # # ][ + + ]: 5033 : if (instance) free (instance);
1054 [ # # ][ - + ]: 5033 : }
1055 : :
1056 : : // Sets the instance name where the node occurred.
1057 : 735 : void node::setInstance (const char * n)
1058 : : {
1059 [ - + ]: 735 : if (instance) free (instance);
1060 [ + - ]: 735 : instance = n ? strdup (n) : NULL;
1061 : 735 : }
1062 : :
1063 : : // Returns the instance name where the node occurred.
1064 : 861 : char * node::getInstance (void)
1065 : : {
1066 : 861 : return instance;
1067 : : }
1068 : :
1069 : : /* The function applies the instance name of the current equation node
1070 : : to any following node within the list up to the node with a valid
1071 : : instance name. */
1072 : 68 : void node::applyInstance (void)
1073 : : {
1074 : 68 : char * i = getInstance ();
1075 [ + + ]: 207 : for (node * n = getNext (); n != NULL; n = n->getNext ())
1076 : : {
1077 [ + - ]: 139 : if (n->getInstance () == NULL)
1078 : 139 : n->setInstance (i);
1079 : : else
1080 : 0 : break;
1081 : : }
1082 : 68 : }
1083 : :
1084 : : // Counts the number of equations node attached to the node.
1085 : 141 : int node::count (void)
1086 : : {
1087 : 141 : int c = 0;
1088 [ + + ]: 315 : for (node * n = this; n != NULL; n = n->getNext ()) c++;
1089 : 141 : return c;
1090 : : }
1091 : :
1092 : : // Appends yet another node to the equation node object.
1093 : 137 : void node::append (node * last)
1094 : : {
1095 [ - + ]: 274 : if (!last) return;
1096 : : node * n;
1097 [ + + ]: 140 : for (n = this; n->getNext () != NULL; n = n->getNext ()) ;
1098 : 137 : last->setNext (NULL);
1099 : 137 : n->setNext (last);
1100 : : }
1101 : :
1102 : : // Appends othere nodes to the equation node object.
1103 : 0 : void node::appendNodes (node * last)
1104 : : {
1105 [ # # ]: 0 : if (!last) return;
1106 : : node * n;
1107 [ # # ]: 0 : for (n = this; n->getNext () != NULL; n = n->getNext ()) ;
1108 : 0 : n->setNext (last);
1109 : : }
1110 : :
1111 : : // Returns the equation node at the given argument position.
1112 : 3 : node * node::get (int pos)
1113 : : {
1114 : 3 : node * n = this;
1115 [ - + ][ # # ]: 3 : for (int i = 0; i < pos && n != NULL; n = n->getNext (), i++) ;
[ - + ]
1116 : 3 : return n;
1117 : : }
1118 : :
1119 : : // Sets the constant equation node result.
1120 : 255887 : void node::setResult (constant * r)
1121 : : {
1122 : 255887 : res = r;
1123 : 255887 : }
1124 : :
1125 : : // Returns the constant equation node at the given argument position.
1126 : 1339 : constant * node::getResult (int pos)
1127 : : {
1128 : 1339 : node * n = this;
1129 [ + + ][ + - ]: 1885 : for (int i = 0; i < pos && n != NULL; n = n->getNext (), i++) ;
[ + + ]
1130 [ + - ]: 1339 : return n ? n->getResult () : NULL;
1131 : : }
1132 : :
1133 : : /* Returns a double value depending on the type of the equation nodes
1134 : : result type. */
1135 : 32685 : nr_double_t node::getResultDouble (void)
1136 : : {
1137 : 32685 : constant * c = getResult ();
1138 [ + - ]: 32685 : if (c != NULL)
1139 : : {
1140 [ + + - - ]: 32685 : switch (getType ())
1141 : : {
1142 : : case TAG_DOUBLE:
1143 : 32683 : return c->d;
1144 : : break;
1145 : : case TAG_COMPLEX:
1146 : 2 : return real (*(c->c));
1147 : : break;
1148 : : case TAG_BOOLEAN:
1149 [ # # ]: 0 : return c->b ? 1.0 : 0.0;
1150 : : break;
1151 : : }
1152 : : }
1153 : 32685 : return 0.0;
1154 : : }
1155 : :
1156 : : /* Returns a complex value depending on the type of the equation nodes
1157 : : result type. */
1158 : 0 : nr_complex_t node::getResultComplex (void)
1159 : : {
1160 : 0 : constant * c = getResult ();
1161 [ # # ]: 0 : if (c != NULL)
1162 : : {
1163 [ # # # # ]: 0 : switch (getType ())
1164 : : {
1165 : : case TAG_DOUBLE:
1166 : 0 : return nr_complex_t (c->d, 0.0);
1167 : : break;
1168 : : case TAG_COMPLEX:
1169 : 0 : return *(c->c);
1170 : : break;
1171 : : case TAG_BOOLEAN:
1172 [ # # ]: 0 : return c->b ? 1.0 : 0.0;
1173 : : break;
1174 : : }
1175 : : }
1176 : 0 : return 0.0;
1177 : : }
1178 : :
1179 : : /* Returns an immediate vector depending on the type of the equation
1180 : : nodes result type. */
1181 : 0 : qucs::vector node::getResultVector (void)
1182 : : {
1183 : 0 : constant * c = getResult ();
1184 : 0 : qucs::vector v;
1185 [ # # ]: 0 : if (c != NULL)
1186 : : {
1187 [ # # # # : 0 : switch (getType ())
# # ]
1188 : : {
1189 : : case TAG_MATRIX:
1190 : : {
1191 : 0 : int ro, co, n = 0;
1192 [ # # ][ # # ]: 0 : v = qucs::vector (c->m->getRows () * c->m->getCols ());
[ # # ]
1193 [ # # ]: 0 : for (co = 0; co < c->m->getCols (); co++)
1194 [ # # ]: 0 : for (ro = 0; ro < c->m->getRows (); ro++)
1195 [ # # ]: 0 : v (n++) = c->m->get (ro, co);
1196 : : }
1197 : 0 : break;
1198 : : case TAG_VECTOR:
1199 [ # # ]: 0 : v = *(c->v);
1200 : 0 : break;
1201 : : case TAG_DOUBLE:
1202 [ # # ][ # # ]: 0 : v = qucs::vector (1);
[ # # ]
1203 : 0 : v (0) = c->d;
1204 : 0 : break;
1205 : : case TAG_COMPLEX:
1206 [ # # ][ # # ]: 0 : v = qucs::vector (1);
[ # # ]
1207 : 0 : v (0) = *(c->c);
1208 : 0 : break;
1209 : : case TAG_BOOLEAN:
1210 [ # # ][ # # ]: 0 : v = qucs::vector (1);
[ # # ]
1211 [ # # ]: 0 : v (0) = c->b ? 1.0 : 0.0;
1212 : 0 : break;
1213 : : }
1214 : : }
1215 : 0 : return v;
1216 : : }
1217 : :
1218 : : // Assigns the dependency list to the equation node object.
1219 : 265947 : void node::setDependencies (strlist * depends)
1220 : : {
1221 [ + + ][ + - ]: 265947 : if (dependencies) delete dependencies;
1222 : 265947 : dependencies = depends;
1223 : 265947 : }
1224 : :
1225 : : // Returns the dependency list of the equation node object.
1226 : 528444 : strlist * node::getDependencies (void)
1227 : : {
1228 : 528444 : return dependencies;
1229 : : }
1230 : :
1231 : : /* This function recursively finds the variable dependencies for each
1232 : : equation initially passed to the equation checker and returns the
1233 : : list of variable dependencies regarding this equation instance.
1234 : : The caller is responsible for deleting the returned string list
1235 : : object. */
1236 : 132971 : strlist * node::recurseDependencies (checker * check, strlist * deps)
1237 : : {
1238 : :
1239 : 132971 : strlist * res, * sub = NULL;
1240 : :
1241 : : /* The abort condition for recursion first. */
1242 [ - + ]: 132971 : if (deps->contains (A(this)->result))
1243 : : {
1244 [ # # ]: 0 : res = new strlist (*deps);
1245 : 0 : cycle = 1;
1246 : 0 : return res;
1247 : : }
1248 : :
1249 : : /* Go through the list of passed dependency variables. */
1250 [ + + ]: 142079 : for (int i = 0; i < deps->length (); i++)
1251 : : {
1252 : 9108 : char * var = deps->get (i);
1253 : 9108 : node * child = check->findEquation (check->equations, var);
1254 : : /* Check each child equation. */
1255 [ + + ]: 9108 : if (child != NULL)
1256 : : {
1257 [ + - ]: 2435 : if (child->cycle == 0)
1258 : : {
1259 : 2435 : strlist * cdeps = child->getDependencies ();
1260 : : /* And append the dependencies of the child equation. */
1261 [ + + ]: 2435 : if (cdeps->length () > 0)
1262 : : {
1263 : 1791 : res = strlist::join (sub, cdeps);
1264 [ + + ][ + - ]: 1791 : if (sub) delete sub;
1265 : 1791 : sub = res;
1266 : : }
1267 : : }
1268 : : /* If any child is cyclic, the parent is too. */
1269 : : else
1270 : : {
1271 : 0 : cycle = 1;
1272 : : }
1273 : : }
1274 : : }
1275 : :
1276 : : /* Recurse once again if the child equations revealed any more
1277 : : dependencies. */
1278 [ - + ][ # # ]: 132971 : if (cycle && sub && sub->length () > 0)
[ # # ][ - + ]
1279 : : {
1280 : 0 : res = recurseDependencies (check, sub);
1281 [ # # ]: 0 : delete sub;
1282 : 0 : sub = res;
1283 : : }
1284 : :
1285 : : /* Return the result. */
1286 : 132971 : res = strlist::join (deps, sub);
1287 [ + + ][ + - ]: 132971 : if (sub) delete (sub);
1288 : 132971 : return res;
1289 : : }
1290 : :
1291 : : /* The function adds the given data dependency to the list of
1292 : : dependencies which are going to be dropped during the data
1293 : : export. */
1294 : 0 : void node::addDropDependencies (char * dep)
1295 : : {
1296 [ # # ][ # # ]: 0 : if (dropDependencies == NULL) dropDependencies = new strlist ();
1297 : 0 : dropDependencies->add (dep);
1298 : 0 : }
1299 : :
1300 : : /* The function adds the given data dependency to the list of
1301 : : dependencies which are going to be prepend. */
1302 : 5 : void node::addPrepDependencies (char * dep)
1303 : : {
1304 [ + - ][ + - ]: 5 : if (prepDependencies == NULL) prepDependencies = new strlist ();
1305 : 5 : prepDependencies->add (dep);
1306 : 5 : }
1307 : :
1308 : : /* This function appends the given dependency list to the list of
1309 : : dependencies which are going to be prepend. */
1310 : 4 : void node::appendPrepDependencies (strlist * deps)
1311 : : {
1312 [ + - ][ + - ]: 4 : if (prepDependencies == NULL) prepDependencies = new strlist ();
1313 : 4 : prepDependencies->append (deps);
1314 : 4 : }
1315 : :
1316 : : /* The function sets the data dependency list of the equation node. */
1317 : 128304 : void node::setDataDependencies (strlist * deps)
1318 : : {
1319 [ + + ][ + - ]: 128304 : if (dataDependencies != NULL) delete dataDependencies;
1320 [ + + ][ + - ]: 128304 : dataDependencies = deps ? new strlist (*deps) : NULL;
1321 : 128304 : }
1322 : :
1323 : : /* Evaluates the equation node and applies the data dependencies. */
1324 : 126940 : constant * node::calculate (void)
1325 : : {
1326 : 126940 : constant * res = evaluate ();
1327 [ + - ]: 126940 : if (getResult ())
1328 : : {
1329 : 126940 : strlist * deps = solvee->collectDataDependencies (this);
1330 : 126940 : getResult()->setDataDependencies (deps);
1331 [ + + ][ + - ]: 126940 : if (deps) delete deps;
1332 : : }
1333 : : else
1334 : : {
1335 [ # # ]: 0 : qucs::exception * e = new qucs::exception (EXCEPTION_MATH);
1336 : 0 : e->setText ("evaluator exception");
1337 : 0 : throw_exception (e);
1338 : : }
1339 : 126940 : return res;
1340 : : }
1341 : :
1342 : : /* Collects the equation dependencies for a specific node. */
1343 : 0 : strlist * node::collectDependencies (void)
1344 : : {
1345 [ # # ]: 0 : strlist * depends = new strlist ();
1346 : 0 : addDependencies (depends);
1347 : 0 : setDependencies (checker::foldDependencies (depends));
1348 : 0 : return getDependencies ();
1349 : : }
1350 : :
1351 : : /* Collects the data dependencies for a specific node. */
1352 : 0 : strlist * node::collectDataDependencies (void)
1353 : : {
1354 : 0 : strlist * deps = getResult()->getDataDependencies ();
1355 [ # # ]: 0 : if (deps)
1356 : : {
1357 : : // data dependencies already collected
1358 : 0 : setDataDependencies (deps);
1359 : 0 : return deps;
1360 : : }
1361 : : // collect equation dependencies
1362 [ # # ]: 0 : if (!getDependencies ())
1363 : 0 : collectDependencies ();
1364 [ # # ]: 0 : if (solvee)
1365 : : {
1366 : : // finally collect the appropriate data dependencies
1367 : 0 : deps = solvee->collectDataDependencies (this);
1368 : 0 : setDataDependencies (deps);
1369 [ # # ]: 0 : delete deps;
1370 : : }
1371 : 0 : return getDataDependencies ();
1372 : : }
1373 : :
1374 : : // Constructor creates an instance of the checker class.
1375 : 116 : checker::checker ()
1376 : : {
1377 : 116 : defs = NULL;
1378 : 116 : equations = NULL;
1379 : 116 : consts = false;
1380 : 116 : }
1381 : :
1382 : : // Destructor deletes an instance of the checker class.
1383 : 116 : checker::~checker ()
1384 : : {
1385 : : node * next;
1386 [ - + ][ # # ]: 116 : for (node * eqn = equations; eqn != NULL; eqn = next)
1387 : : {
1388 : 0 : next = eqn->getNext ();
1389 [ # # ][ # # ]: 0 : delete eqn;
1390 : : }
1391 : 116 : }
1392 : :
1393 : : // Local macro definition to go through the list of equations.
1394 : : #define foreach_equation(eqn) \
1395 : : for (assignment * (eqn) = A (equations); \
1396 : : (eqn) != NULL; (eqn) = A ((eqn)->getNext ()))
1397 : :
1398 : : /* The function goes through the list of equations assigned to the
1399 : : checker and applies the dependency list. */
1400 : 23303 : void checker::collectDependencies (void)
1401 : : {
1402 [ + + ]: 156274 : foreach_equation (eqn)
1403 : : {
1404 : 132971 : collectDependencies (eqn);
1405 : : }
1406 : 23303 : }
1407 : :
1408 : : // Creates dependency list of given equation node.
1409 : 132971 : void checker::collectDependencies (node * eqn)
1410 : : {
1411 [ + - ]: 132971 : strlist * depends = new strlist ();
1412 : 132971 : eqn->addDependencies (depends);
1413 : 132971 : eqn->setDependencies (depends);
1414 : 132971 : }
1415 : :
1416 : : /* The following function goes through the list of equations and
1417 : : checks whether there is any kind of 'Export="yes|no"' assignment in
1418 : : it. Depending on the value the referred equation results are saved
1419 : : into the dataset or not. */
1420 : 23303 : int checker::checkExport (void)
1421 : : {
1422 : 23303 : int errors = 0;
1423 : : assignment * next;
1424 : : // go through all equations
1425 [ + + ]: 156342 : for (assignment * eqn = A (equations); eqn != NULL; eqn = next)
1426 : : {
1427 : 133039 : next = A (eqn->getNext ());
1428 : : // 'Export' equation found ?
1429 [ + + ]: 133039 : if (!strcmp (eqn->result, "Export"))
1430 : : {
1431 : : // is the type and value correct ?
1432 [ + - ][ - + ]: 68 : if (eqn->body->getTag () != REFERENCE ||
[ # # ][ - + ]
1433 : 68 : (strcmp (R (eqn->body)->n, "yes") &&
1434 : 0 : strcmp (R (eqn->body)->n, "no")))
1435 : : {
1436 : : logprint (LOG_ERROR, "checker error, variable `%s' alternatives "
1437 : 0 : "are `yes' or `no'\n", eqn->result);
1438 : 0 : errors++;
1439 : : }
1440 : : else
1441 : : {
1442 [ + - ]: 68 : int flag = !strcmp (R (eqn->body)->n, "yes") ? 1 : 0;
1443 : 68 : char * i = eqn->getInstance ();
1444 : 68 : int found = 0;
1445 : : // set output flag for each equation with the same instance name
1446 [ + + ]: 580 : foreach_equation (res)
1447 : : {
1448 [ + + ]: 512 : if (!strcmp (res->getInstance (), i))
1449 : 207 : res->output = flag;
1450 [ + + + + ]: 586 : if (!strcmp (res->result, "Export") &&
[ + + ]
1451 : 74 : !strcmp (res->getInstance (), i))
1452 : : {
1453 : 68 : found++;
1454 : : }
1455 : : }
1456 : : // check for duplicate definitions of 'Export'
1457 [ - + ]: 68 : if (found > 1)
1458 : : {
1459 : : logprint (LOG_ERROR, "checker error, variable `%s' "
1460 : 0 : "occurred %dx in `Eqn:%s'\n", eqn->result, found, i);
1461 : 0 : errors++;
1462 : : }
1463 : : // drop the 'Export' equation being useless now
1464 : 68 : dropEquation (eqn);
1465 [ + - ]: 68 : delete eqn;
1466 : : }
1467 : : }
1468 : : }
1469 : 23303 : return errors;
1470 : : }
1471 : :
1472 : : // Logs the textual representation of all equations.
1473 : 0 : void checker::list (void)
1474 : : {
1475 [ # # ]: 0 : for (node * eqn = equations; eqn != NULL; eqn = eqn->getNext ())
1476 : : {
1477 [ # # ]: 0 : logprint (LOG_STATUS, "%s", eqn->evalPossible ? "!" : "?");
1478 : : logprint (LOG_STATUS, "%s", eqn->evalPossible ?
1479 : 0 : (eqn->getType () == TAG_UNKNOWN ? "U!" :
1480 : 0 : eqn->getType () == TAG_DOUBLE ? "D!" :
1481 : 0 : eqn->getType () == TAG_BOOLEAN ? "B!" :
1482 : 0 : eqn->getType () == TAG_COMPLEX ? "C!" :
1483 : 0 : eqn->getType () == TAG_VECTOR ? "V!" :
1484 : 0 : eqn->getType () == TAG_CHAR ? "CHR!" :
1485 : 0 : eqn->getType () == TAG_STRING ? "STR!" :
1486 : 0 : eqn->getType () == TAG_MATVEC ? "MV!" :
1487 : 0 : eqn->getType () == TAG_RANGE ? "R!" :
1488 [ # # # # : 0 : eqn->getType () == TAG_MATRIX ? "M!" : "?!") : "");
# # # # #
# # # # #
# # # # #
# ][ # # ]
1489 : 0 : eqn->print ();
1490 : 0 : logprint (LOG_STATUS, "\n");
1491 : : }
1492 : 0 : }
1493 : :
1494 : : /* Checks whether the variable name is a generated name which is
1495 : : identified by a ".[0-9]{4}" suffix. */
1496 : 12568 : int checker::isGenerated (char * var)
1497 : : {
1498 : 12568 : int len = strlen (var);
1499 [ + + ]: 12568 : if (len > 5)
1500 : : {
1501 [ - + ][ # # : 4713 : if (isdigit (var[len-1]) && isdigit (var[len-2]) &&
# # # # ]
[ # # ][ - + ]
1502 : 0 : isdigit (var[len-3]) && isdigit (var[len-4]) &&
1503 : 0 : var[len-5] == '.')
1504 : : {
1505 : 0 : return 1;
1506 : : }
1507 : : }
1508 : 12568 : return 0;
1509 : : }
1510 : :
1511 : : /* This function checks whether the variable references could be
1512 : : resolved within the equations and returns zero if so. */
1513 : 23303 : int checker::findUndefined (int noundefined)
1514 : : {
1515 : 23303 : int err = 0;
1516 : 23303 : strlist * idents = getVariables ();
1517 : :
1518 [ + + ]: 156274 : foreach_equation (eqn)
1519 : : {
1520 : 132971 : strlist * depends = eqn->getDependencies ();
1521 [ + + ]: 142079 : for (int i = 0; i < depends->length (); i++)
1522 : : {
1523 : 9108 : char * var = depends->get (i);
1524 [ + + ]: 9108 : if (idents->contains (var) <= 0)
1525 : : {
1526 : : // check if this is a circuit property
1527 [ + + ]: 6673 : if (defs)
1528 : : {
1529 : 120 : node * eqn = findProperty (var);
1530 [ - + ]: 120 : if (eqn)
1531 : : {
1532 : 0 : idents->append (var);
1533 : 0 : eqn->collectDependencies ();
1534 : 0 : continue;
1535 : : }
1536 : : }
1537 : : // give an error
1538 [ - + ]: 6673 : if (noundefined)
1539 : : {
1540 [ # # ]: 0 : if (isGenerated (var)) // skip probably generated variables
1541 : 0 : continue;
1542 : : logprint (LOG_ERROR, "checker error, undefined variable `%s' in "
1543 : 0 : "equation `%s'\n", var, eqn->result);
1544 : 0 : err++;
1545 : : }
1546 : : // give a notice only
1547 : : else
1548 : : {
1549 : : logprint (LOG_STATUS, "checker notice, variable `%s' in "
1550 : 6673 : "equation `%s' not yet defined\n", var, eqn->result);
1551 : : }
1552 : : }
1553 : : }
1554 : : }
1555 [ + - ]: 23303 : delete idents;
1556 : 23303 : return err;
1557 : : }
1558 : :
1559 : : /* This function tries to find the given variable name which occurred
1560 : : in an equation dependency in the netlist. If there is such a
1561 : : circuit property it returns a new assignment equation. */
1562 : 120 : node * checker::findProperty (char * var)
1563 : : {
1564 : :
1565 : 120 : node * eqn = NULL;
1566 : 120 : int found = 0;
1567 : :
1568 : : // split into instance and property name
1569 : : char * ret, * inst, * prop;
1570 [ + + ]: 120 : if ((ret = strchr (var, '.')) != NULL)
1571 : : {
1572 : 72 : int len = ret - var;
1573 : 72 : inst = (char *) calloc (1, len + 1);
1574 : 72 : memcpy (inst, var, len);
1575 : 72 : prop = &var[len + 1];
1576 : : }
1577 : 48 : else return NULL;
1578 : :
1579 : : // go through list of circuit elements
1580 [ + + ]: 832 : for (struct definition_t * def = defs; def; def = def->next)
1581 : : {
1582 [ + + ]: 760 : if (!strcmp (def->instance, inst))
1583 : : {
1584 [ + + ]: 52 : for (struct pair_t * pair = def->pairs; pair; pair = pair->next)
1585 : : {
1586 [ - + ]: 18 : if (!strcmp (pair->key, prop))
1587 : : {
1588 [ # # ]: 0 : if (++found == 1)
1589 : : {
1590 [ # # ]: 0 : if (pair->value->ident != NULL)
1591 : : {
1592 : : // reference
1593 : 0 : eqn = createReference ("#property", var, pair->value->ident);
1594 : : }
1595 : : else
1596 : : {
1597 : : // value
1598 : 0 : eqn = createDouble ("#property", var, pair->value->value);
1599 : : }
1600 : : }
1601 : : }
1602 : : }
1603 : : }
1604 : : }
1605 [ - + ]: 72 : if (found > 1)
1606 : : {
1607 : : logprint (LOG_ERROR, "checker error, desired property variable `%s' found "
1608 : 0 : "%dx, is not unique'\n", var, found);
1609 [ # # ]: 0 : delete eqn;
1610 : 0 : eqn = NULL;
1611 : : }
1612 [ - + ]: 72 : else if (found == 1)
1613 : 0 : appendEquation (eqn);
1614 : 72 : free (inst);
1615 : 120 : return eqn;
1616 : : }
1617 : :
1618 : : /* Go through the list of equations and store the left hand side in
1619 : : a string list. */
1620 : 46606 : strlist * checker::getVariables (void)
1621 : : {
1622 [ + - ]: 46606 : strlist * idents = new strlist ();
1623 [ + + ]: 312548 : foreach_equation (eqn)
1624 : : {
1625 : 265942 : idents->add (eqn->result);
1626 : : }
1627 : 46606 : return idents;
1628 : : }
1629 : :
1630 : : /* Finds duplicate equation definitions in the list of equations,
1631 : : emits appropriate error messages and returns zero if everything is
1632 : : ok. */
1633 : 23303 : int checker::findDuplicate (void)
1634 : : {
1635 : 23303 : int err = 0;
1636 : 23303 : strlist * idents = getVariables ();
1637 [ + - ]: 23303 : strlist * dups = new strlist ();
1638 : :
1639 : : // Collect duplicate entries.
1640 [ + + ]: 156274 : foreach_equation (eqn)
1641 : : {
1642 [ + + ][ + - ]: 132971 : if (!eqn->duplicate && dups->contains (eqn->result) == 0)
[ + + ]
1643 : : {
1644 : 1714 : eqn->duplicate = idents->contains (eqn->result);
1645 : 1714 : dups->add (eqn->result);
1646 : : }
1647 : : else
1648 : : {
1649 : 131257 : eqn->duplicate = 1;
1650 : : }
1651 : : }
1652 : : // Emit appropriate error messages.
1653 [ + + ]: 156274 : foreach_equation (eqndups)
1654 : : {
1655 [ - + ]: 132971 : if (eqndups->duplicate > 1)
1656 : : {
1657 : : logprint (LOG_ERROR, "checker error, variable `%s' assigned %dx\n",
1658 : 0 : eqndups->result, eqndups->duplicate);
1659 : 0 : err++;
1660 : : }
1661 : : }
1662 [ + - ]: 23303 : delete idents;
1663 [ + - ]: 23303 : delete dups;
1664 : 23303 : return err;
1665 : : }
1666 : :
1667 : : /* The function returns the equation resulting in the passed variable
1668 : : or NULL if there is no such equation. The function looks through
1669 : : the passed equation root. */
1670 : 21674 : node * checker::findEquation (node * root, const char * const n)
1671 : : {
1672 [ + + ]: 150298 : for (node * eqn = root; eqn != NULL; eqn = eqn->getNext ())
1673 : : {
1674 [ + + ]: 134244 : if (!strcmp (A(eqn)->result, n))
1675 : 5620 : return eqn;
1676 : : }
1677 : 21674 : return NULL;
1678 : : }
1679 : :
1680 : : /* The function returns the equation resulting in the passed variable
1681 : : or NULL if there is no such equation. */
1682 : 0 : node * checker::findEquation (const char * const n) const
1683 : : {
1684 [ # # ]: 0 : foreach_equation (eqn)
1685 : : {
1686 [ # # ]: 0 : if (!strcmp (A(eqn)->result, n)) return eqn;
1687 : : }
1688 : 0 : return NULL;
1689 : : }
1690 : :
1691 : : /* This function display the error messages due to equation cycles and
1692 : : returns zero if there are no such cycles. */
1693 : 23303 : int checker::detectCycles (void)
1694 : : {
1695 : 23303 : int err = 0;
1696 : :
1697 [ + + ]: 156274 : foreach_equation (eqn)
1698 : : {
1699 : 132971 : strlist * deps = eqn->recurseDependencies (this, eqn->getDependencies ());
1700 [ + - ][ - + ]: 132971 : if (deps->contains (eqn->result) || eqn->cycle)
[ - + ]
1701 : : {
1702 : : logprint (LOG_ERROR, "checker error, cyclic definition of variable "
1703 : 0 : "`%s' involves: `%s'\n", eqn->result, deps->toString ());
1704 : 0 : err++;
1705 [ # # ]: 0 : delete deps;
1706 : : }
1707 : : else
1708 : : {
1709 : : // Set folded variable dependencies.
1710 : 132971 : deps = foldDependencies (deps);
1711 : 132971 : eqn->setDependencies (deps);
1712 : : }
1713 : : }
1714 : 23303 : return err;
1715 : : }
1716 : :
1717 : : /* The function returns a variable dependency list with unique entries
1718 : : only. The given string list gets deleted and a new one is created
1719 : : and returned. */
1720 : 260055 : strlist * checker::foldDependencies (strlist * deps)
1721 : : {
1722 [ + - ]: 260055 : strlist * res = new strlist ();
1723 [ + - ][ + + ]: 274009 : for (int i = 0; deps && i < deps->length (); i++)
[ + + ]
1724 : : {
1725 : 13954 : char * var = deps->get (i);
1726 [ + + ]: 13954 : if (!res->contains (var)) res->append (var);
1727 : : }
1728 [ + - ][ + - ]: 260055 : if (deps) delete deps;
1729 : 260055 : return res;
1730 : : }
1731 : :
1732 : : // The function appends the given last node to the given equation root.
1733 : 127439 : node * checker::appendEquation (node * root, node * last)
1734 : : {
1735 : 127439 : last->setNext (NULL);
1736 [ + + ]: 127439 : if (root != NULL)
1737 : : {
1738 : 104136 : node * eqn = lastEquation (root);
1739 : 104136 : eqn->setNext (last);
1740 : : }
1741 : 23303 : else root = last;
1742 : 127439 : return root;
1743 : : }
1744 : :
1745 : : // Returns the last node in the given equation root.
1746 : 127507 : node * checker::lastEquation (node * root)
1747 : : {
1748 : : node * eqn;
1749 [ + - ][ + + ]: 424700 : for (eqn = root; eqn && eqn->getNext () != NULL; eqn = eqn->getNext ()) ;
[ + + ]
1750 : 127507 : return eqn;
1751 : : }
1752 : :
1753 : : // Removes the given equation node from the list of known equations.
1754 : 127566 : void checker::dropEquation (node * eqn)
1755 : : {
1756 [ + + ]: 127566 : if (eqn == equations)
1757 : : {
1758 : 127461 : equations = eqn->getNext ();
1759 : : }
1760 : : else
1761 : : {
1762 : : node * prev;
1763 [ + + ]: 475 : for (prev = equations; prev->getNext () != eqn; prev = prev->getNext()) ;
1764 : 105 : prev->setNext (eqn->getNext ());
1765 : : }
1766 : 127566 : }
1767 : :
1768 : : /* This function reorders the list of equations. The new order can be
1769 : : used to evaluate the list step by step. Each equation being
1770 : : evaluable is properly marked, remaining equations are appended. */
1771 : 23303 : void checker::reorderEquations (void)
1772 : : {
1773 : 23303 : node * root = NULL, * next, * last;
1774 : :
1775 : : // Go through the list of equations.
1776 [ + + ]: 156300 : for (node * eqn = equations; eqn != NULL; eqn = next)
1777 : : {
1778 : 132997 : strlist * deps = eqn->getDependencies ();
1779 : : int i, found, gens;
1780 : 132997 : next = eqn->getNext ();
1781 : : /* Check whether the variable dependencies can be found in
1782 : : previous equations. */
1783 [ + + ]: 144768 : for (found = gens = i = 0; i < deps->length (); i++)
1784 : : {
1785 : 11771 : char * var = deps->get (i);
1786 [ + + ]: 11771 : if (findEquation (root, var) != NULL) found++;
1787 [ - + ]: 11771 : if (isGenerated (var)) gens++;
1788 : : }
1789 : : // Yes.
1790 [ + + ]: 132997 : if (found == (deps->length () - gens))
1791 : : {
1792 : : /* Remove the equation from the current list and append it to
1793 : : the new list. */
1794 : 127439 : dropEquation (eqn);
1795 : 127439 : root = appendEquation (root, eqn);
1796 : 127439 : eqn->evalPossible = 1;
1797 : : // Now start over from the beginning.
1798 : 127439 : next = equations;
1799 : : }
1800 : : }
1801 : : // Any remaining equations get appended.
1802 [ + - ]: 23303 : if (root != NULL)
1803 : : {
1804 : 23303 : last = lastEquation (root);
1805 : 23303 : last->setNext (equations);
1806 : 23303 : equations = root;
1807 : : }
1808 : 23303 : }
1809 : :
1810 : :
1811 : : /* The function passes a list of equations to the checker and also
1812 : : passes the checker instance to each equation. */
1813 : 46606 : void checker::setEquations (node * eqns)
1814 : : {
1815 : 46606 : equations = eqns;
1816 [ + + ]: 311554 : foreach_equation (eqn)
1817 : : {
1818 : 264948 : eqn->checkee = this;
1819 : : }
1820 : 46606 : }
1821 : :
1822 : : /* The function evaluates the types for each equation and recursively
1823 : : checks the availability of the appropriate function. */
1824 : 23303 : int checker::applyTypes (void)
1825 : : {
1826 : 23303 : int err = 0;
1827 [ + + ]: 150742 : foreach_equation (eqn)
1828 : : {
1829 [ + + ]: 131405 : if (eqn->evalPossible)
1830 : : {
1831 [ - + ]: 127439 : if (eqn->evalType () == TAG_UNKNOWN)
1832 : : {
1833 : : logprint (LOG_ERROR, "checker error, type of equation `%s' "
1834 : 0 : "undefined\n", eqn->result);
1835 : 0 : err++;
1836 : : }
1837 : : }
1838 : 3966 : else break;
1839 : : }
1840 : 23303 : return err;
1841 : : }
1842 : :
1843 : : /* This function is the checker routine for a parsed equations. It
1844 : : returns zero on success or non-zero if the parsed equations
1845 : : contained errors. */
1846 : 23303 : int checker::check (int noundefined)
1847 : : {
1848 : 23303 : int err = 0;
1849 : 23303 : err += checkExport ();
1850 : 23303 : collectDependencies ();
1851 : 23303 : err += findUndefined (noundefined);
1852 : 23303 : err += findDuplicate ();
1853 : 23303 : err += detectCycles ();
1854 : 23303 : reorderEquations ();
1855 : 23303 : err += applyTypes ();
1856 : : #if DEBUG && 0
1857 : : list ();
1858 : : #endif /* DEBUG */
1859 : 23303 : return err;
1860 : : }
1861 : :
1862 : : // Constructor creates an instance of the solver class.
1863 : 116 : solver::solver (checker * c)
1864 : : {
1865 : 116 : equations = NULL;
1866 : 116 : data = NULL;
1867 : 116 : generated = 0;
1868 : 116 : checkee = c;
1869 : 116 : }
1870 : :
1871 : : // Destructor deletes an instance of the solver class.
1872 : 116 : solver::~solver ()
1873 : : {
1874 : : node * next;
1875 [ + + ][ # # ]: 1776 : for (node * eqn = equations; eqn != NULL; eqn = next)
1876 : : {
1877 : 1660 : next = eqn->getNext ();
1878 [ + - ][ # # ]: 1660 : delete eqn;
1879 : : }
1880 : 116 : }
1881 : :
1882 : : // The function finally evaluates each equation passed to the solver.
1883 : 23187 : void solver::evaluate (void)
1884 : : {
1885 [ + + ]: 155555 : foreach_equation (eqn)
1886 : : {
1887 : : // FIXME: Can save evaluation of already evaluated equations?
1888 [ + + ][ + - ]: 132368 : if (eqn->evalPossible && !eqn->skip /* && eqn->evaluated == 0 */)
1889 : : {
1890 : : // exception handling around evaluation
1891 : : try_running ()
1892 : : {
1893 : 126940 : eqn->solvee = this;
1894 : 126940 : eqn->calculate ();
1895 : : }
1896 : : // handle evaluation exceptions
1897 [ - + ]: 126940 : catch_exception ()
1898 : : {
1899 : : default:
1900 : 0 : estack.print ("evaluation");
1901 : 0 : break;
1902 : : }
1903 : 126940 : eqn->evaluated++;
1904 : : #if DEBUG && 0
1905 : : // print equation results
1906 : : logprint (LOG_STATUS, "%s = %s\n", A(eqn)->result,
1907 : : eqn->getResult () ? eqn->getResult()->toString () : "error");
1908 : : #if TESTING_DERIVATIVE || 0
1909 : : // print equation
1910 : : logprint (LOG_STATUS, "%s\n", eqn->toString ());
1911 : : // print derivations
1912 : : logprint (LOG_STATUS, "%s\n", eqn->differentiate("x")->toString ());
1913 : : #endif
1914 : : #endif
1915 : : }
1916 : : }
1917 : 23187 : }
1918 : :
1919 : : /* This function adds the given dataset vector to the set of equations
1920 : : stored in the equation solver. */
1921 : 1039 : node * solver::addEquationData (qucs::vector * v, bool ref)
1922 : : {
1923 [ + - ]: 1039 : constant * con = new constant (TAG_VECTOR);
1924 : 1039 : con->v = v;
1925 : 1039 : con->dataref = ref;
1926 [ + - ]: 1039 : assignment * assign = new assignment ();
1927 : 1039 : assign->result = strdup (v->getName ());
1928 : 1039 : assign->body = con;
1929 : 1039 : assign->setNext (equations);
1930 : 1039 : equations = assign;
1931 : 1039 : return assign;
1932 : : }
1933 : :
1934 : : /* The function puts the given vector into the equation set. The
1935 : : resulting data vector is going to be copied and exported - given a
1936 : : generated name based upon the second argument. */
1937 : 5 : node * solver::addGeneratedEquation (qucs::vector * v, const char * n)
1938 : : {
1939 : : // create generated name
1940 : 5 : char * str = (char *) malloc (strlen (n) + 6);
1941 : 5 : sprintf (str, "%s.%04d", n, ++generated);
1942 : : // copy data vector
1943 [ + - ]: 5 : qucs::vector * c = new qucs::vector (*v);
1944 : 5 : c->setName (str);
1945 : : // put vector into the equation set and ensure data export as
1946 : : // independent variable
1947 : 5 : node * res = addEquationData (c);
1948 : 5 : res->setInstance ("#generated");
1949 [ + - ]: 5 : res->setDependencies (new strlist ());
1950 : 5 : res->evalType ();
1951 : 5 : res->solvee = this;
1952 : 5 : res->evaluate ();
1953 : 5 : res->output = 1;
1954 : 5 : free (str);
1955 : 5 : return res;
1956 : : }
1957 : :
1958 : : /* Depending on the type of equation result the function converts the
1959 : : given equation node to one or more valid dataset vector(s). */
1960 : 144 : qucs::vector * solver::dataVector (node * eqn)
1961 : : {
1962 : 144 : qucs::vector * v = NULL;
1963 [ - + ]: 144 : if (!eqn->getResult ()) return NULL;
1964 [ + + + + : 144 : switch (eqn->getType ())
- - - ]
1965 : : {
1966 : : case TAG_VECTOR: // simple vector
1967 [ + - ]: 88 : v = new qucs::vector (* (eqn->getResult()->v));
1968 : 88 : v->setNext (NULL);
1969 : 88 : v->setPrev (NULL);
1970 : 88 : break;
1971 : : case TAG_DOUBLE: // double value
1972 [ + - ]: 33 : v = new qucs::vector ();
1973 [ + - ]: 33 : v->add (eqn->getResult()->d);
1974 : 33 : break;
1975 : : case TAG_BOOLEAN: // boolean value
1976 [ + - ]: 21 : v = new qucs::vector ();
1977 [ + - ][ + - ]: 21 : v->add (eqn->getResult()->b ? 1 : 0);
1978 : 21 : break;
1979 : : case TAG_COMPLEX: // complex value
1980 [ + - ]: 2 : v = new qucs::vector ();
1981 : 2 : v->add (* (eqn->getResult()->c));
1982 : 2 : break;
1983 : : case TAG_MATVEC: // matrix vector
1984 : : {
1985 : : // convert matrix vector to a list of vectors
1986 : 0 : matvec * mv = eqn->getResult()->mv;
1987 : 0 : mv->setName (A(eqn)->result);
1988 [ # # ]: 0 : for (int r = 0; r < mv->getRows (); r++)
1989 : : {
1990 [ # # ]: 0 : for (int c = 0; c < mv->getCols (); c++)
1991 : : {
1992 : : // name gets automatically assigned
1993 [ # # ]: 0 : qucs::vector * t = new qucs::vector (mv->get (r, c));
1994 : : // chain the vectors appropriately
1995 : 0 : t->setNext (v);
1996 : 0 : v = t;
1997 : : }
1998 : : }
1999 : : }
2000 : 0 : return v;
2001 : : case TAG_MATRIX: // single matrix
2002 : : {
2003 : : // convert matrix to a list of vectors
2004 : 0 : matrix * m = eqn->getResult()->m;
2005 [ # # ]: 0 : for (int r = 0; r < m->getRows (); r++)
2006 : : {
2007 [ # # ]: 0 : for (int c = 0; c < m->getCols (); c++)
2008 : : {
2009 [ # # ]: 0 : qucs::vector * t = new qucs::vector ();
2010 : 0 : t->setName (matvec::createMatrixString (A(eqn)->result, r, c));
2011 : 0 : t->add (m->get (r, c));
2012 : : // chain the vectors appropriately
2013 : 0 : t->setNext (v);
2014 : 0 : v = t;
2015 : : }
2016 : : }
2017 : : }
2018 : 0 : return v;
2019 : : default:
2020 : 0 : return NULL;
2021 : : }
2022 : 144 : v->setName (A(eqn)->result);
2023 : 144 : return v;
2024 : : }
2025 : :
2026 : : /* This function collects the data vectors in a dataset and appends
2027 : : these to the list of equation node inside the equation solver. */
2028 : 23187 : void solver::checkinDataset (void)
2029 : : {
2030 [ + + ]: 23290 : if (data == NULL) return;
2031 : : qucs::vector * v;
2032 : 103 : findMatrixVectors (data->getDependencies ());
2033 : 103 : findMatrixVectors (data->getVariables ());
2034 [ + + ]: 237 : for (v = data->getDependencies (); v != NULL; v = (qucs::vector *) v->getNext ())
2035 : : {
2036 [ + - ]: 134 : if (v->getRequested () != -1)
2037 : : {
2038 : 134 : node * eqn = addEquationData (v, true);
2039 [ + - ]: 134 : strlist * deps = new strlist ();
2040 : 134 : deps->add (v->getName ());
2041 : 134 : eqn->setDataDependencies (deps);
2042 [ + - ]: 134 : delete deps;
2043 : : }
2044 : : }
2045 [ + + ]: 1095 : for (v = data->getVariables (); v != NULL; v = (qucs::vector *) v->getNext ())
2046 : : {
2047 [ + + ]: 992 : if (v->getRequested () != -1)
2048 : : {
2049 : 900 : node * eqn = addEquationData (v, true);
2050 : 900 : eqn->setDataDependencies (v->getDependencies ());
2051 : : }
2052 : : }
2053 : : }
2054 : :
2055 : : /* This function searches through the dataset of the equation solver
2056 : : for possible matrix vectors. These are detected by the vectors'
2057 : : names (e.g. S[1,1]). The matrix vectors found in the dataset get
2058 : : converted and saved into the set of equations. */
2059 : 206 : void solver::findMatrixVectors (qucs::vector * v)
2060 : : {
2061 : : qucs::vector * vec;
2062 : : strlist * deps;
2063 : : char * p, * cand;
2064 : 206 : int s, r, c, a, b, n = 1;
2065 : :
2066 : : // initialize the 'found' flag
2067 [ + + ]: 1332 : for (vec = v; vec != NULL; vec = (qucs::vector *) vec->getNext ())
2068 : 1126 : vec->setRequested (0);
2069 : :
2070 : : // loop through the dataset vector until no more matrix vector is found
2071 [ - + ]: 206 : do
2072 : : {
2073 : 206 : r = c = s = -1;
2074 : 206 : cand = NULL;
2075 : 206 : deps = NULL;
2076 : : // go through the dataset
2077 [ + + ]: 1332 : for (vec = v; vec != NULL; vec = (qucs::vector *) vec->getNext ())
2078 : : {
2079 : : // skip detected vectors
2080 [ - + ]: 1126 : if (vec->getRequested ()) continue;
2081 : : // is the vector a possible matrix vector element ?
2082 [ + - ][ + + ]: 1126 : if ((p = matvec::isMatrixVector (vec->getName (), a, b)) != NULL)
2083 : : {
2084 [ + + ]: 92 : if (cand != NULL)
2085 : : {
2086 : : // does this vectors name equals the current one ?
2087 [ + - ][ + - ]: 74 : if (!strcmp (p, cand) && s == vec->getSize ())
[ + - ][ + - ]
2088 : : {
2089 : : // save largest row and column index and set the 'found' flag
2090 [ + + ]: 74 : if (a > r) r = a;
2091 [ + + ]: 74 : if (b > c) c = b;
2092 : 74 : vec->setRequested (n);
2093 : : }
2094 : : }
2095 : : else
2096 : : {
2097 : : /* new possible matrix vector:
2098 : : save its name, row and column index, its size (length of
2099 : : the vector) and data dependencies; then set the 'found' flag */
2100 [ + - ]: 18 : cand = strdup (p);
2101 : 18 : r = a;
2102 : 18 : c = b;
2103 [ + - ]: 18 : s = vec->getSize ();
2104 : 18 : vec->setRequested (n);
2105 [ + - ]: 18 : deps = vec->getDependencies ();
2106 : : }
2107 : 92 : free (p);
2108 : : }
2109 : : }
2110 : :
2111 : : // new matrix vector detected
2112 [ + + ]: 206 : if (cand != NULL)
2113 : : {
2114 : : // create a new matrix vector and set the appropriate name
2115 [ + - ][ + - ]: 18 : matvec * mv = new matvec (s, r + 1, c + 1);
2116 [ + - ]: 18 : mv->setName (cand);
2117 : : // go through the dataset vector once again
2118 [ + + ]: 202 : for (vec = v; vec != NULL; vec = (qucs::vector *) vec->getNext ())
2119 : : {
2120 : : // and collect the vectors with the same 'found' flags
2121 [ + + ]: 184 : if (vec->getRequested () == n)
2122 : : {
2123 [ + - ]: 92 : p = matvec::isMatrixVector (vec->getName (), a, b);
2124 [ + - ][ + - ]: 92 : mv->set (*vec, a, b);
[ + - ]
2125 : 92 : free (p);
2126 : 92 : vec->setRequested (-1);
2127 : : }
2128 : : }
2129 : : // now store this new matrix vector into the set of equations
2130 [ + - ]: 18 : node * eqn = addEquationData (mv);
2131 : 18 : eqn->solvee = this;
2132 [ + - ]: 18 : eqn->evaluate ();
2133 [ - + ]: 18 : if (deps == NULL)
2134 : : {
2135 [ # # ][ # # ]: 0 : strlist * deps = new strlist ();
2136 [ # # ][ # # ]: 0 : deps->add (mv->getName ());
2137 [ # # ]: 0 : eqn->setDataDependencies (deps);
2138 [ # # ][ # # ]: 0 : delete deps;
2139 : : }
2140 : : else
2141 : : {
2142 [ + - ]: 18 : eqn->setDataDependencies (deps);
2143 : : }
2144 : 18 : free (cand);
2145 : 18 : cand = NULL;
2146 : : }
2147 : : // increase the current 'found' flag
2148 : 206 : n++;
2149 : : }
2150 : : while (cand != NULL);
2151 : 206 : }
2152 : :
2153 : : /* The function creates an assignment equation from the given matrix
2154 : : vector and returns it. The new assignment is appended to the list
2155 : : of available equations. */
2156 : 18 : node * solver::addEquationData (matvec * mv)
2157 : : {
2158 [ + - ]: 18 : constant * con = new constant (TAG_MATVEC);
2159 : 18 : con->mv = mv;
2160 [ + - ]: 18 : assignment * assign = new assignment ();
2161 : 18 : assign->result = strdup (mv->getName ());
2162 : 18 : assign->body = con;
2163 : 18 : assign->setNext (equations);
2164 : 18 : equations = assign;
2165 : 18 : return assign;
2166 : : }
2167 : :
2168 : : /* The function returns the dataset entry length of the given equation
2169 : : node (a constant). The constant must already been evaluated when
2170 : : this function is called. */
2171 : 0 : int solver::dataSize (constant * eqn)
2172 : : {
2173 : 0 : int size = 0;
2174 [ # # # ]: 0 : switch (eqn->getType ())
2175 : : {
2176 : : case TAG_VECTOR: // simple vector
2177 : 0 : size = eqn->getResult()->v->getSize ();
2178 : 0 : break;
2179 : : case TAG_MATVEC: // matrix vector
2180 : 0 : size = eqn->getResult()->mv->getSize ();
2181 : : default:
2182 : 0 : size = 1;
2183 : : }
2184 : 0 : return size;
2185 : : }
2186 : :
2187 : : /* This function returns the dataset entry length of the given
2188 : : variable name. It must be ensured that the variable actually
2189 : : exists and is already evaluated. */
2190 : 0 : int solver::getDataSize (char * var)
2191 : : {
2192 : 0 : node * eqn = checker::findEquation (equations, var);
2193 : 0 : return dataSize (C (eqn));
2194 : : }
2195 : :
2196 : : /* Depending on the index the function returns the cumulative product
2197 : : of the dataset entries stored in the given dependency list or one
2198 : : if there are no data dependencies at all. */
2199 : 0 : int solver::getDependencySize (strlist * deps, int idx)
2200 : : {
2201 : 0 : int size = 1;
2202 [ # # ]: 0 : if (deps == NULL) return 1;
2203 [ # # ]: 0 : for (int i = 0; i < deps->length () - idx; i++)
2204 : : {
2205 : 0 : size *= getDataSize (deps->get (i));
2206 : : }
2207 : 0 : return size;
2208 : : }
2209 : :
2210 : : /* This function goes through the given string list and calculates the
2211 : : data entries within these dataset dependencies. It returns at
2212 : : least one no matter whether the data vectors can be found or not. */
2213 : 56 : int solver::dataSize (strlist * deps)
2214 : : {
2215 : 56 : int size = 1;
2216 [ + + ][ + + ]: 80 : for (int i = 0; deps != NULL && i < deps->length (); i++)
[ + + ]
2217 : : {
2218 : 24 : char * str = deps->get (i);
2219 : 24 : qucs::vector * dep = data->findDependency (str);
2220 : 24 : qucs::vector * var = data->findVariable (str);
2221 [ + - ][ # # ]: 24 : size *= dep ? dep->getSize () : var ? var->getSize () : 1;
2222 : : }
2223 : 56 : return size;
2224 : : }
2225 : :
2226 : : /* The function returns the data vector in the dataset according to
2227 : : the given variable name. If there is no such variable, it returns
2228 : : NULL. */
2229 : 0 : qucs::vector * solver::getDataVector (char * str)
2230 : : {
2231 : : qucs::vector * var;
2232 : : /* search for variables in dataset */
2233 [ # # ]: 0 : if (data != NULL)
2234 : : {
2235 [ # # ]: 0 : if ((var = data->findVariable (str)) != NULL)
2236 : 0 : return var;
2237 [ # # ]: 0 : if ((var = data->findDependency (str)) != NULL)
2238 : 0 : return var;
2239 : : }
2240 : : /* search for variables in equation set */
2241 [ # # ]: 0 : if (equations != NULL)
2242 : : {
2243 : 0 : node * eqn = checker::findEquation (equations, str);
2244 : 0 : constant * res = eqn->getResult ();
2245 [ # # ][ # # ]: 0 : if (res->getTag () == CONSTANT && res->getType () == TAG_VECTOR)
[ # # ]
2246 : : {
2247 : 0 : return res->v;
2248 : : }
2249 : : }
2250 : 0 : return NULL;
2251 : : }
2252 : :
2253 : : /* The following function collects the inherited dataset dependencies
2254 : : for the given equation node and returns it as a string list. It
2255 : : returns NULL if there are no such dependencies. */
2256 : 127084 : strlist * solver::collectDataDependencies (node * eqn)
2257 : : {
2258 : 127084 : strlist * sub = NULL, * datadeps = NULL;
2259 : : // should all data dependencies be dropped?
2260 [ + + ]: 127084 : if (!eqn->getResult()->dropdeps)
2261 : : {
2262 : 127070 : strlist * deps = eqn->getDependencies ();
2263 : 127070 : datadeps = eqn->getDataDependencies ();
2264 [ + + ][ + - ]: 127070 : datadeps = datadeps ? new strlist (*datadeps) : NULL;
2265 : : // go through equation dependencies
2266 [ + - ][ + + ]: 127865 : for (int i = 0; deps && i < deps->length (); i++)
[ + + ]
2267 : : {
2268 : 795 : char * var = deps->get (i);
2269 : : // find equation node for the dependency
2270 : 795 : node * n = checker::findEquation (equations, var);
2271 : : // try again in the solver equations
2272 [ - + ][ # # ]: 795 : if (n == NULL && eqn->solvee != NULL)
2273 : 0 : n = checker::findEquation (eqn->solvee->getEquations (), var);
2274 : : // if finally founf the equation node
2275 [ + - ]: 795 : if (n != NULL)
2276 : : {
2277 : : // pass resulting data dependencies up
2278 : : strlist * resdeps;
2279 [ + + ]: 795 : if ((resdeps = n->getResult()->getDataDependencies ()) != NULL)
2280 : 312 : n->setDataDependencies (resdeps);
2281 : : // add data dependencies
2282 : 795 : sub = strlist::join (datadeps, n->getDataDependencies ());
2283 : 795 : sub->del (n->getResult()->getDropDependencies ());
2284 : 795 : sub->add (n->getResult()->getPrepDependencies ());
2285 : : }
2286 [ + + ][ + - ]: 795 : if (datadeps) delete datadeps;
2287 : 795 : datadeps = sub;
2288 : : }
2289 : : }
2290 : : // prepend dependencies if necessary
2291 : 127084 : strlist * preps = eqn->getResult()->getPrepDependencies ();
2292 [ + + ]: 127084 : if (datadeps)
2293 : : {
2294 [ - + ]: 1464 : if (preps) datadeps->add (preps);
2295 : : }
2296 : : else
2297 : : {
2298 [ + - ]: 125620 : datadeps = new strlist ();
2299 [ + + ]: 125620 : if (preps) datadeps->add (preps);
2300 : : }
2301 : : // drop duplicate entries
2302 : 127084 : datadeps = checker::foldDependencies (datadeps);
2303 : : // delete the dependencies to be dropped intentionally
2304 : 127084 : datadeps->del (eqn->getResult()->getDropDependencies ());
2305 : : // finally return the correct data dependencies
2306 [ + + ]: 127084 : if (datadeps->length () == 0)
2307 : : {
2308 [ + - ]: 125978 : delete datadeps;
2309 : 125978 : datadeps = NULL;
2310 : : }
2311 : 127084 : return datadeps;
2312 : : }
2313 : :
2314 : : // The function stores the equation solver results back into a dataset.
2315 : 23187 : void solver::checkoutDataset (void)
2316 : : {
2317 : : // return if nothing todo
2318 [ + + ]: 23290 : if (data == NULL) return;
2319 : : // go through each equation
2320 [ + + ]: 1711 : foreach_equation (eqn)
2321 : : {
2322 : :
2323 : : // skip variables which don't need to be exported
2324 [ + + ]: 1608 : if (!eqn->output) continue;
2325 : :
2326 : : // is the equation result already in the dataset ?
2327 [ + - ]: 144 : if (!findEquationResult (eqn))
2328 : : {
2329 : 144 : qucs::vector * v = dataVector (eqn);
2330 [ - + ]: 144 : if (v == NULL) continue;
2331 : :
2332 : : // collect inherited dataset dependencies
2333 : 144 : strlist * datadeps = collectDataDependencies (eqn);
2334 : :
2335 : : // check whether dataset is smaller than its dependencies
2336 [ + + ][ + + ]: 144 : if (v->getSize () <= 1 && dataSize (datadeps) > v->getSize ())
[ + + ]
2337 : : {
2338 [ + - ]: 18 : delete datadeps;
2339 : 18 : datadeps = NULL;
2340 : : }
2341 : :
2342 : : // store variable vector(s)
2343 [ + + ][ + - ]: 144 : if (datadeps && datadeps->length () > 0)
[ + + ]
2344 : : {
2345 : 83 : v->setDependencies (datadeps);
2346 [ - + ]: 83 : if (v->getNext () != NULL)
2347 : : {
2348 : 0 : data->applyDependencies (v);
2349 : 0 : data->addVariables (v);
2350 : : }
2351 : : else
2352 : : {
2353 : 83 : data->addVariable (v);
2354 : : }
2355 : : }
2356 : : // store independent vector(s)
2357 : : else
2358 : : {
2359 [ - + ]: 61 : if (v->getNext () != NULL)
2360 : 0 : data->addDependencies (v);
2361 : : else
2362 : 61 : data->addDependency (v);
2363 [ - + ]: 61 : delete datadeps;
2364 : : }
2365 : : }
2366 : : }
2367 : : }
2368 : :
2369 : : /* This function checks whether the given equation solver result is
2370 : : already within the dataset. It returns non-zero if so, otherwise
2371 : : the function returns zero. */
2372 : 144 : int solver::findEquationResult (node * eqn)
2373 : : {
2374 : : // check each vector of a given matrix vector
2375 [ - + ]: 144 : if (eqn->getType () == TAG_MATVEC)
2376 : : {
2377 : 0 : matvec * mv = eqn->getResult()->mv;
2378 [ # # ]: 0 : for (int r = 0; r < mv->getRows (); r++)
2379 : : {
2380 [ # # ]: 0 : for (int c = 0; c < mv->getCols (); c++)
2381 : : {
2382 : 0 : char * str = matvec::createMatrixString (A(eqn)->result, r, c);
2383 [ # # ][ # # ]: 0 : if (data->findDependency (str) || data->findVariable (str))
[ # # ]
2384 : 0 : return 1;
2385 : : }
2386 : : }
2387 : : }
2388 : : // check normal data vectors
2389 : : else
2390 : : {
2391 : 144 : char * str = A(eqn)->result;
2392 [ + - ][ - + ]: 144 : if (data->findDependency (str) || data->findVariable (str))
[ - + ]
2393 : 0 : return 1;
2394 : : }
2395 : 144 : return 0;
2396 : : }
2397 : :
2398 : : /* This function is called in order to run the equation checker and
2399 : : the solver. The optional dataset passed to the function receives
2400 : : the results of the calculations. */
2401 : 23187 : int solver::solve (dataset * data)
2402 : : {
2403 : : // load additional dataset equations
2404 : 23187 : setData (data);
2405 : 23187 : checkinDataset ();
2406 : : // put these into the checker
2407 : 23187 : checkee->setEquations (equations);
2408 : : // and check
2409 [ + + ][ - + ]: 23187 : if (checkee->check (data ? 1 : 0) != 0)
2410 : : {
2411 : 0 : return -1;
2412 : : }
2413 : 23187 : equations = checkee->getEquations ();
2414 : : // finally evaluate equations
2415 : 23187 : evaluate ();
2416 : : // put results into the dataset
2417 : 23187 : checkoutDataset ();
2418 : 23187 : return 0;
2419 : : }
2420 : :
2421 : : /* Go through the list of equations and store the left hand side in
2422 : : a string list. */
2423 : 103 : strlist * checker::variables (void)
2424 : : {
2425 [ + - ]: 103 : strlist * idents = new strlist ();
2426 [ + + ]: 654 : foreach_equation (eqn)
2427 : : {
2428 : 551 : idents->add (eqn->result);
2429 : : }
2430 : 103 : return idents;
2431 : : }
2432 : :
2433 : : // Checks if the given variable name is an equation.
2434 : 999 : bool checker::containsVariable (const char * const ident) const
2435 : : {
2436 [ + + ]: 6726 : foreach_equation (eqn)
2437 : : {
2438 [ + + ]: 5753 : if (!strcmp (ident, eqn->result))
2439 : 26 : return true;
2440 : : }
2441 : 999 : return false;
2442 : : }
2443 : :
2444 : : // Structure defining a predefined constant.
2445 : : struct pconstant
2446 : : {
2447 : : const char * ident;
2448 : : nr_double_t value;
2449 : : };
2450 : :
2451 : : // List of global constant variables.
2452 : : static struct pconstant pconstants[] =
2453 : : {
2454 : : { "pi", M_PI },
2455 : : { "e", M_E },
2456 : : { "kB", kB },
2457 : : { "q", Q_e },
2458 : : { NULL, 0 }
2459 : : };
2460 : :
2461 : : /* The function should be called before parsing the netlist. It
2462 : : appends the predefined constants to the list of equations. */
2463 : 116 : void checker::constants (void)
2464 : : {
2465 : :
2466 : : // return if nothing to do
2467 [ - + ]: 232 : if (consts) return;
2468 : :
2469 : : // go through constants and add these to the equations
2470 [ + + ]: 580 : for (int i = 0; pconstants[i].ident != NULL; i++)
2471 : : {
2472 : 464 : addDouble ("#predefined", pconstants[i].ident, pconstants[i].value);
2473 : : }
2474 : :
2475 : : // indicate that constants have been added
2476 : 116 : consts = true;
2477 : : }
2478 : :
2479 : : /* The function adds a new equation to the equation checker consisting
2480 : : of an assignment of a reference. */
2481 : 0 : node * checker::addReference (const char * type, const char * ident,
2482 : : char * value)
2483 : : {
2484 : 0 : node * eqn = createReference (type, ident, value);
2485 : 0 : addEquation (eqn);
2486 : 0 : return eqn;
2487 : : }
2488 : :
2489 : : /* The function adds a new equation to the equation checker consisting
2490 : : of an assignment of a double variable. */
2491 : 523 : node * checker::addDouble (const char * type, const char * ident,
2492 : : nr_double_t value)
2493 : : {
2494 : 523 : node * eqn = createDouble (type, ident, value);
2495 : 523 : addEquation (eqn);
2496 : 523 : return eqn;
2497 : : }
2498 : :
2499 : : /* The function adds a new equation to the equation checker consisting
2500 : : of an assignment of a complex variable. */
2501 : 0 : node * checker::addComplex (const char * type, const char * ident,
2502 : : nr_complex_t value)
2503 : : {
2504 : 0 : node * eqn = createComplex (type, ident, value);
2505 : 0 : addEquation (eqn);
2506 : 0 : return eqn;
2507 : : }
2508 : :
2509 : : // Adds given equation to the equation list.
2510 : 523 : void checker::addEquation (node * eqn)
2511 : : {
2512 : 523 : eqn->setNext (equations);
2513 : 523 : equations = eqn;
2514 : 523 : }
2515 : :
2516 : : // Appends the given equation to the equation list.
2517 : 0 : void checker::appendEquation (node * eqn)
2518 : : {
2519 : 0 : eqn->setNext (NULL);
2520 : 0 : node * last = lastEquation (equations);
2521 [ # # ]: 0 : if (last != NULL)
2522 : 0 : last->setNext (eqn);
2523 : : else
2524 : 0 : equations = eqn;
2525 : 0 : }
2526 : :
2527 : : /* This function creates a equation consisting of an assignment of a
2528 : : double variable. */
2529 : 523 : node * checker::createDouble (const char * type, const char * ident,
2530 : : nr_double_t value)
2531 : : {
2532 : : // create constant double value
2533 [ + - ]: 523 : constant * c = new constant (TAG_DOUBLE);
2534 : 523 : c->checkee = this;
2535 : 523 : c->d = value;
2536 : : // create the appropriate assignment
2537 [ + - ]: 523 : assignment * a = new assignment ();
2538 : 523 : a->checkee = this;
2539 : 523 : a->result = strdup (ident);
2540 : 523 : a->body = c;
2541 : 523 : a->output = 0;
2542 : 523 : a->setInstance (type);
2543 : 523 : return a;
2544 : : }
2545 : :
2546 : : /* This function creates a equation consisting of an assignment of a
2547 : : complex variable. */
2548 : 0 : node * checker::createComplex (const char * type, const char * ident,
2549 : : nr_complex_t value)
2550 : : {
2551 : : // create constant double value
2552 [ # # ]: 0 : constant * c = new constant (TAG_COMPLEX);
2553 : 0 : c->checkee = this;
2554 : 0 : c->c = new nr_complex_t (value);
2555 : : // create the appropriate assignment
2556 [ # # ]: 0 : assignment * a = new assignment ();
2557 : 0 : a->checkee = this;
2558 : 0 : a->result = strdup (ident);
2559 : 0 : a->body = c;
2560 : 0 : a->output = 0;
2561 : 0 : a->setInstance (type);
2562 : 0 : return a;
2563 : : }
2564 : :
2565 : : /* This function creates a equation consisting of an assignment of a
2566 : : reference. */
2567 : 0 : node * checker::createReference (const char * type, const char * ident,
2568 : : char * value)
2569 : : {
2570 : : // create reference value
2571 [ # # ]: 0 : reference * r = new reference ();
2572 : 0 : r->checkee = this;
2573 : 0 : r->n = strdup (value);
2574 : : // create the appropriate assignment
2575 [ # # ]: 0 : assignment * a = new assignment ();
2576 : 0 : a->checkee = this;
2577 : 0 : a->result = strdup (ident);
2578 : 0 : a->body = r;
2579 : 0 : a->output = 0;
2580 : 0 : a->setInstance (type);
2581 : 0 : return a;
2582 : : }
2583 : :
2584 : : /* The functions looks through the set of equations for a real valued
2585 : : result and returns it. If there is no such assignment, zero is
2586 : : returned. */
2587 : 32685 : nr_double_t checker::getDouble (const char * const ident) const
2588 : : {
2589 [ + - ]: 42781 : foreach_equation (eqn)
2590 : : {
2591 [ + + ]: 42781 : if (!strcmp (ident, eqn->result))
2592 : : {
2593 : 32685 : return eqn->getResultDouble ();
2594 : : }
2595 : : }
2596 : 32685 : return 0.0;
2597 : : }
2598 : :
2599 : : /* The function goes through the equation set and looks for the
2600 : : specified assignment. If found the given value is set. */
2601 : 22739 : void checker::setDouble (const char * const ident, nr_double_t val)
2602 : : {
2603 [ + + ]: 152025 : foreach_equation (eqn)
2604 : : {
2605 [ + + ]: 129286 : if (!strcmp (ident, eqn->result))
2606 : : {
2607 [ + - ]: 22739 : if (eqn->body->getTag () == CONSTANT)
2608 : : {
2609 : 22739 : constant * c = C (eqn->body);
2610 [ + - ]: 22739 : if (c->type == TAG_DOUBLE) c->d = val;
2611 : : }
2612 : : }
2613 : : }
2614 : 22739 : }
2615 : :
2616 : : /* The functions looks through the set of equations for a vector
2617 : : result and returns it. If there is no such assignment, an empty
2618 : : vector is returned. */
2619 : 0 : qucs::vector checker::getVector (const char * const ident) const
2620 : : {
2621 [ # # ]: 0 : foreach_equation (eqn)
2622 : : {
2623 [ # # ]: 0 : if (!strcmp (ident, eqn->result))
2624 : : {
2625 : 0 : return eqn->getResultVector ();
2626 : : }
2627 : : }
2628 : 0 : return qucs::vector ();
2629 : : }
2630 : :
2631 : : } // namespace qucs
|