My Project  0.0.16
QUCS Mapping
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
check_mdl.cpp
Go to the documentation of this file.
1 /*
2  * check_mdl.cpp - iterate an IC-CAP MDL file
3  *
4  * Copyright (C) 2006, 2007 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: check_mdl.cpp 1825 2011-03-11 20:42:14Z ela $
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 <math.h>
33 #include <assert.h>
34 #include <float.h>
35 #include <ctype.h>
36 
37 #include "logging.h"
38 #include "strlist.h"
39 #include "object.h"
40 #include "complex.h"
41 #include "vector.h"
42 #include "dataset.h"
43 #include "sweep.h"
44 #include "valuelist.h"
45 #include "constants.h"
46 #include "check_mdl.h"
47 #include "tokens_mdl.h"
48 
49 // Global variables.
51 struct mdl_link_t * mdl_root = NULL;
52 struct mdl_sync_t * mdl_sync_root = NULL;
53 
54 // Creates an independent data vector.
55 static void mdl_create_depdataset (sweep * data, char * name) {
56  vector v (name);
57  for (int i = 0; i < data->getSize (); i++) v.add (data->get (i));
58  mdl_result->appendDependency (new vector (v));
59 }
60 
61 // Creates an independent data vector with a single element.
62 static void mdl_create_condataset (double val, char * name) {
63  vector v (name);
64  v.add (val);
65  mdl_result->appendDependency (new vector (v));
66 }
67 
68 // The functions creates dependent data vector(s).
69 static void mdl_create_vardataset (struct mdl_point_t * point,
70  struct mdl_datasize_t * dsize,
71  const char * name, const char * type,
72  strlist * deps) {
73  vector * v = new vector[dsize->x * dsize->y] ();
74  // adjust type
75  if (!strcmp (type, "MEAS"))
76  type = ".M";
77  else if (!strcmp (type, "SIMU"))
78  type = ".S";
79  else if (!strcmp (type, "COMMON"))
80  type = "";
81  // create vectors
82  for (struct mdl_point_t * p = point; p != NULL; p = p->next) {
83  int n = (p->y - 1) * 2 + p->x - 1;
84  v[n].add (rect (p->r, p->i));
85  }
86  // go through indices
87  for (int x = 1; x < dsize->x + 1; x++) {
88  for (int y = 1; y < dsize->y + 1; y++) {
89  // create vector description
90  int n = (y - 1) * 2 + x - 1;
91  char * txt = (char *) malloc (strlen (name) + strlen (type) + 4 + 2 * 3);
92  if (dsize->x > 1 || dsize->y > 1)
93  sprintf (txt, "%s%s[%d,%d]", name, type, x, y);
94  else
95  sprintf (txt, "%s%s", name, type);
96  v[n].setName (txt);
97  free (txt);
98  // put vector into dataset
99  if (v[n].getSize () > 1) {
100  v[n].setDependencies (new strlist (*deps));
101  mdl_result->appendVariable (new vector (v[n]));
102  } else {
103  v[n].setDependencies (new strlist ());
104  mdl_result->appendDependency (new vector (v[n]));
105  }
106  }
107  }
108  delete[] v;
109 }
110 
111 // Look through hypertable elements for a name and return value.
112 static char * mdl_find_helement (struct mdl_element_t * root,
113  const char * name) {
114  for (; root != NULL; root = root->next) {
115  if (!strcmp (root->name, name)) return root->value;
116  }
117  return NULL;
118 }
119 
120 // Look through table elements for a name and return value.
121 static char * mdl_find_telement (struct mdl_element_t * root,
122  const char * name) {
123  for (; root != NULL; root = root->next) {
124  if (!strcmp (root->name, "Name") && !strcmp (root->value, name)) {
125  if (root->next && !strcmp (root->next->name, "Value")) {
126  return root->next->value;
127  }
128  }
129  }
130  return NULL;
131 }
132 
133 // Convert number suffix into a multiplication factor.
134 static double mdl_convert_factor (char * end) {
135  double f = 1.0;
136  if (end) {
137  switch (*end) {
138  case 'K': f = 1e+03; break;
139  case 'M': f = 1e+06; break;
140  case 'G': f = 1e+09; break;
141  case 'T': f = 1e+12; break;
142  case 'm': f = 1e-03; break;
143  case 'u': f = 1e-06; break;
144  case 'n': f = 1e-09; break;
145  case 'p': f = 1e-12; break;
146  case 'f': f = 1e-15; break;
147  case 'a': f = 1e-18; break;
148  }
149  }
150  return f;
151 }
152 
153 // Forward declaration.
154 static double mdl_telement_dvalue (struct mdl_link_t *, struct mdl_element_t *,
155  const char *);
156 
157 // The function resolves the given variable trying upscope resolving.
158 static int mdl_resolve_variable (struct mdl_link_t * link, char * name,
159  double &val) {
160  int done = 0;
161  val = 0.0;
162  struct mdl_lcontent_t * root;
163  // try finding variable in current link
164  for (root = link->content; !done && root != NULL; root = root->next) {
165  if (root->type == t_TABLE) {
166  struct mdl_element_t * eroot = root->table->data;
167  if (mdl_find_telement (eroot, name)) {
168  val = mdl_telement_dvalue (link, eroot, name);
169  done++;
170  }
171  }
172  }
173  // resolve variable in upper scope recursively
174  if (!done && link->parent) {
175  done = mdl_resolve_variable (link->parent, name, val);
176  }
177  return done;
178 }
179 
180 // Converts a string into a valid value. Uses variable substitutions.
181 static double mdl_variable_value (struct mdl_link_t * link, char * txt) {
182  double val = 0.0;
183  char * end = NULL;
184  if (txt != NULL) {
185  // remove whitespaces
186  char * t, * p = txt;
187  while (*p) {
188  if (isspace (*p)) {
189  t = p;
190  while (*t) { *t = *(t + 1); t++; }
191  p--;
192  }
193  p++;
194  }
195  // extract value if possible
196  val = strtod (txt, &end);
197  // not a value, a variable
198  if (end == txt) {
199  double f = 1.0;
200  if (*txt == '-') { f = -1.0; txt++; }
201  else if (*txt == '+') { f = +1.0; txt++; }
202  if (!mdl_resolve_variable (link, txt, val)) {
203  // special variables
204  if (!strcmp (txt, "PI")) {
205  val = M_PI;
206  }
207  // no resolvable (probably equation)
208  else {
210  "checker error, unable to resolve `%s' variable in '%s'\n",
211  txt, link->name);
212  val = 0.0;
213  }
214  }
215  val = f * val;
216  }
217  // normal value with probably a suffix
218  else {
219  val *= mdl_convert_factor (end);
220  }
221  }
222  return val;
223 }
224 
225 // Returns a double variable value stored in a hypertable.
226 static double mdl_helement_dvalue (struct mdl_link_t * link,
227  struct mdl_element_t * eroot,
228  const char * name) {
229  char * txt = mdl_find_helement (eroot, name);
230  return mdl_variable_value (link, txt);
231 }
232 
233 // Returns a double variable value stored in a table.
234 static double mdl_telement_dvalue (struct mdl_link_t * link,
235  struct mdl_element_t * eroot,
236  const char * name) {
237  char * txt = mdl_find_telement (eroot, name);
238  return mdl_variable_value (link, txt);
239 }
240 
241 // Returns a integer variable value stored in a hypertable.
242 static int mdl_helement_ivalue (struct mdl_link_t * link,
243  struct mdl_element_t * eroot,
244  const char * name) {
245  return (int) mdl_helement_dvalue (link, eroot, name);
246 }
247 
248 // Looks for dependent data vectors and creates them.
249 static void mdl_find_vardataset (struct mdl_dcontent_t * droot, char * name,
250  strlist * deps) {
251  struct mdl_dcontent_t * root;
252  // go through dataset content
253  for (root = droot; root != NULL; root = root->next) {
254  if (root->type == t_DATASET) {
255  // create possibly both - MEAS and SIMU - data vectors
256  struct mdl_dataset_t * dset = root->data;
257  if (dset->data1)
258  mdl_create_vardataset (dset->data1, dset->dsize, name, dset->type1,
259  deps);
260  if (dset->data2)
261  mdl_create_vardataset (dset->data2, dset->dsize, name, dset->type2,
262  deps);
263  }
264  }
265 }
266 
267 // Looks for independent data vectors and creates them.
269  struct mdl_dcontent_t * droot,
270  char * name) {
271  char * stype = NULL;
272  double val, start, stop, step;
273  int nof = 0, order = 0;
274  valuelist<int> * deps = new valuelist<int> ();
275  struct mdl_dcontent_t * root;
276 
277  // go through dataset content
278  for (root = droot; root != NULL; root = root->next) {
279  if (root->type == t_HYPTABLE) {
280  struct mdl_hyptable_t * hyptab = root->hyptable;
281  // found a sweep definition?
282  if (!strcmp (hyptab->name, "Edit Sweep Def")) {
283  if (!strcmp (stype, "LIN")) {
284  // linear sweep
285  order = mdl_helement_ivalue (link, hyptab->data, "Sweep Order");
286  start = mdl_helement_dvalue (link, hyptab->data, "Start");
287  stop = mdl_helement_dvalue (link, hyptab->data, "Stop");
288  nof = mdl_helement_ivalue (link, hyptab->data, "# of Points");
289  step = mdl_helement_dvalue (link, hyptab->data, "Step Size");
290  if (nof <= 0) nof = (int) fabs ((stop - start) / step) + 1;
291  deps->append (name, new int (order));
292  linsweep * sw = new linsweep ();
293  sw->create (start, stop, nof);
294  mdl_create_depdataset (sw, name);
295  delete sw;
296  }
297  else if (!strcmp (stype, "CON")) {
298  // constant sweep
299  val = mdl_helement_dvalue (link, hyptab->data, "Value");
300  mdl_create_condataset (val, name);
301  }
302  else if (!strcmp (stype, "LOG")) {
303  // logarithmic sweep
304  order = mdl_helement_ivalue (link, hyptab->data, "Sweep Order");
305  start = mdl_helement_dvalue (link, hyptab->data, "Start");
306  stop = mdl_helement_dvalue (link, hyptab->data, "Stop");
307  nof = mdl_helement_ivalue (link, hyptab->data, "Total Pts");
308  if (nof <= 0)
309  nof = mdl_helement_ivalue (link, hyptab->data, "# of Points");
310  if (start * stop == 0.0) {
311  if (start == 0.0) start = 1.0;
312  if (stop == 0.0) stop = 1.0;
313  }
314  deps->append (name, new int (order));
315  logsweep * sw = new logsweep ();
316  sw->create (start, stop, nof);
317  mdl_create_depdataset (sw, name);
318  delete sw;
319  }
320  else if (!strcmp (stype, "LIST")) {
321  // list sweep
322  order = mdl_helement_ivalue (link, hyptab->data, "Sweep Order");
323  nof = mdl_helement_ivalue (link, hyptab->data, "# of Values");
324  deps->append (name, new int (order));
325  }
326  else if (!strcmp (stype, "SYNC")) {
327  // sync sweep
328  struct mdl_sync_t * sync = (struct mdl_sync_t *)
329  calloc (sizeof (struct mdl_sync_t), 1);
330  sync->ratio = mdl_helement_dvalue (link, hyptab->data, "Ratio");
331  sync->offset = mdl_helement_dvalue (link, hyptab->data, "Offset");
332  sync->master = mdl_find_helement (hyptab->data, "Master Sweep");
333  sync->master = strdup (sync->master);
334  sync->name = strdup (name);
335  sync->next = mdl_sync_root;
336  mdl_sync_root = sync;
337  }
338  }
339  // found a sweep information?
340  else if (!strcmp (hyptab->name, "Edit Sweep Info")) {
341  stype = mdl_find_helement (hyptab->data, "Sweep Type");
342  }
343  // found a list table?
344  else if (!strcmp (hyptab->name, "List Table")) {
345  lstsweep * sw = new lstsweep ();
346  sw->create (nof);
347  char txt[16];
348  for (int i = 0; i < nof; i++) {
349  sprintf (txt, "Value %d", i + 1);
350  val = mdl_helement_dvalue (link, hyptab->data, txt);
351  sw->set (i, val);
352  }
353  mdl_create_depdataset (sw, name);
354  delete sw;
355  }
356  }
357  }
358  return deps;
359 }
360 
361 // Composes a link name.
362 static char * mdl_create_linkname (char * base, char * name) {
363  char * txt = (char *) malloc (strlen (base) + 2 + strlen (name));
364  sprintf (txt, "%s.%s", base, name);
365  return txt;
366 }
367 
368 // Collects dependency links.
369 static void mdl_find_deplink (struct mdl_link_t * link, char * name,
370  valuelist<int> * deps) {
371  struct mdl_lcontent_t * root;
372  valuelist<int> * d;
373  // go through link content
374  for (root = link->content; root != NULL; root = root->next) {
375  // independent data vector
376  if (root->type == t_DATA) {
377  d = mdl_find_depdataset (link, root->data->content, name);
378  if (d != NULL) {
379  deps->append (d);
380  delete d;
381  }
382  }
383  // link to independent data vector
384  else if (root->type == t_LINK && !strcmp (root->link->type, "SWEEP")) {
385  char * txt = mdl_create_linkname (name, root->link->name);
386  root->link->parent = link;
387  mdl_find_deplink (root->link, txt, deps);
388  free (txt);
389  }
390  }
391 }
392 
393 // Collects variable links.
394 static void mdl_find_varlink (struct mdl_link_t * link, char * name,
395  strlist * deps) {
396  struct mdl_lcontent_t * root;
397  // go through link content
398  for (root = link->content; root != NULL; root = root->next) {
399  // dependent data vector
400  if (root->type == t_DATA) {
401  mdl_find_vardataset (root->data->content, name, deps);
402  }
403  // link to dependent data vector
404  else if (root->type == t_LINK && (!strcmp (root->link->type, "OUT") ||
405  !strcmp (root->link->type, "XFORM"))) {
406  char * txt = mdl_create_linkname (name, root->link->name);
407  root->link->parent = link;
408  mdl_find_varlink (root->link, txt, deps);
409  free (txt);
410  }
411  }
412 }
413 
414 // Sorts a dependency list according to their sweep order.
415 static strlist * mdl_sort_deps (valuelist<int> * d) {
416  strlist * deps = new strlist ();
417  for (int i = 0; i < d->length (); i++) {
418  for (valuelistiterator<int> it (*d); *it; ++it) {
419  if (*(it.currentVal ()) == i + 1) {
420  deps->append (it.currentKey ());
421  }
422  }
423  }
424  return deps;
425 }
426 
427 // Iterates the MDL file recursively.
428 static void mdl_find_link (struct mdl_link_t * link, char * name) {
429  struct mdl_lcontent_t * root;
430 
431  // collect independent data
432  valuelist<int> * vdeps = new valuelist<int> ();
433  mdl_find_deplink (link, name, vdeps);
434  strlist * deps = mdl_sort_deps (vdeps);
435  delete vdeps;
436 
437  // collect dependent data
438  mdl_find_varlink (link, name, deps);
439  delete deps;
440 
441  // go through link content
442  for (root = link->content; root != NULL; root = root->next) {
443  if (root->type == t_LINK &&
444  strcmp (root->link->type, "OUT") &&
445  strcmp (root->link->type, "SWEEP") &&
446  strcmp (root->link->type, "XFORM")) {
447  char * txt = mdl_create_linkname (name, root->link->name);
448  root->link->parent = link;
449  mdl_find_link (root->link, txt);
450  free (txt);
451  }
452  }
453 }
454 
455 // Creates an synchronized independent data vector.
456 static void mdl_create_syndataset (vector * v, char * name) {
457  v->setName (name);
458  mdl_result->appendDependency (v);
459 }
460 
461 // Goes through list of sync sweeps and creates them if possible.
462 void mdl_find_syncdatasets (struct mdl_sync_t * root) {
463  struct mdl_sync_t * sync;
464  for (sync = root; sync != NULL; sync = sync->next) {
465  // determine master sweep link
466  char * link = sync->name;
467  int i = strlen (link) - 1;
468  while (i > 0 && link[i] != '.') i--;
469  if (link[i] == '.') {
470  link[i] = '\0';
471  char * txt = (char *) malloc (i + 2 + strlen (sync->master));
472  sprintf (txt, "%s.%s", link, sync->master);
473  link[i] = '.';
474  free (sync->master);
475  sync->master = txt;
476  }
477  // create synchronize independent data vector
478  vector * v = mdl_result->findDependency (sync->master);
479  if (v != NULL) {
480  vector * s = new vector ((*v) * sync->ratio + sync->offset);
481  mdl_create_syndataset (s, sync->name);
482  }
483  }
484 }
485 
486 // Destroys an element structure.
487 static void mdl_free_element (struct mdl_element_t * e) {
488  if (e->name) free (e->name);
489  if (e->value) free (e->value);
490  if (e->attr) free (e->attr);
491  free (e);
492 }
493 
494 // Destroys a datasize structure.
495 static void mdl_free_datasize (struct mdl_datasize_t * d) {
496  if (d->type) free (d->type);
497  free (d);
498 }
499 
500 // Destroys a hypertable structure.
501 static void mdl_free_hyptable (struct mdl_hyptable_t * h) {
502  if (h->name) free (h->name);
503  struct mdl_element_t * e, * next;
504  for (e = h->data; e != NULL; e = next) {
505  next = e->next;
506  mdl_free_element (e);
507  }
508  free (h);
509 }
510 
511 // Destroys a table structure.
512 static void mdl_free_table (struct mdl_table_t * t) {
513  if (t->name) free (t->name);
514  struct mdl_element_t * e, * next;
515  for (e = t->data; e != NULL; e = next) {
516  next = e->next;
517  mdl_free_element (e);
518  }
519  free (t);
520 }
521 
522 // Destroys a dataset structure.
523 static void mdl_free_dataset (struct mdl_dataset_t * d) {
524  if (d->type1) free (d->type1);
525  struct mdl_point_t * p, * next;
526  for (p = d->data1; p != NULL; p = next) {
527  next = p->next;
528  free (p);
529  }
530  if (d->type2) free (d->type2);
531  for (p = d->data2; p != NULL; p = next) {
532  next = p->next;
533  free (p);
534  }
535  if (d->dsize) mdl_free_datasize (d->dsize);
536 }
537 
538 // Destroys a data content structure.
539 static void mdl_free_dcontent (struct mdl_dcontent_t * c) {
540  switch (c->type) {
541  case t_DATASET: mdl_free_dataset (c->data); break;
542  case t_HYPTABLE: mdl_free_hyptable (c->hyptable); break;
543  }
544 }
545 
546 // Destroys a data structure.
547 static void mdl_free_data (struct mdl_data_t * d) {
548  struct mdl_dcontent_t * c, * next;
549  for (c = d->content; c != NULL; c = next) {
550  next = c->next;
551  mdl_free_dcontent (c);
552  }
553 }
554 
555 // Forward declaration.
556 static void mdl_free_link (struct mdl_link_t *);
557 
558 // Destroys a link content structure.
559 static void mdl_free_lcontent (struct mdl_lcontent_t * c) {
560  switch (c->type) {
561  case t_LINK: mdl_free_link (c->link); break;
562  case t_DATA: mdl_free_data (c->data); break;
563  case t_TABLE: mdl_free_table (c->table); break;
564  }
565  free (c);
566 }
567 
568 // Destroys a link structure.
569 static void mdl_free_link (struct mdl_link_t * l) {
570  if (l->name) free (l->name);
571  if (l->type) free (l->type);
572  struct mdl_lcontent_t * c, * next;
573  for (c = l->content; c != NULL; c = next) {
574  next = c->next;
575  mdl_free_lcontent (c);
576  }
577 }
578 
579 // Destroys a sync structure.
580 static void mdl_free_sync (struct mdl_sync_t * s) {
581  struct mdl_sync_t * next;
582  for (; s != NULL; s = next) {
583  next = s->next;
584  if (s->name) free (s->name);
585  if (s->master) free (s->master);
586  free (s);
587  }
588 }
589 
590 // Computes the dependent vector length for the given dependency list.
591 static int mdl_get_depsize (strlist * deps) {
592  char * n;
593  vector * v;
594  int res = 1;
595  for (int i = 0; i < deps->length (); i++) {
596  if ((n = deps->get (i)) != NULL)
597  if ((v = mdl_result->findDependency (n)) != NULL)
598  res *= v->getSize ();
599  }
600  return res;
601 }
602 
603 // Checks the variable vector dependencies. Makes them independent if
604 // necessary.
605 static void mdl_check_xform_deplen (void) {
606  vector * v, * next;
607  for (v = mdl_result->getVariables (); v; v = next) {
608  next = (vector *) v->getNext ();
609  strlist * deps = v->getDependencies ();
610  if (deps->length () <= 0) {
611  vector * d = new vector (*v);
612  mdl_result->delVariable (v);
613  mdl_result->addDependency (d);
614  }
615  }
616 }
617 
618 // Checks the variable vector dependencies and reduces them if necessary.
619 static void mdl_check_xform_dep (void) {
620  vector * v, * d;
621  strlist * deps;
622  for (v = mdl_result->getVariables (); v; v = (vector *) v->getNext ()) {
623  deps = v->getDependencies ();
624  int s = mdl_get_depsize (deps);
625  // dependencies differ from actual vector length
626  if (v->getSize () != s) {
627  int found = 0;
628  for (int i = 0; i < deps->length (); i++) {
629  // find out a single dependency with the appropriate length
630  char * n = deps->get (i);
631  if (n != NULL) {
632  d = mdl_result->findDependency (n);
633  if (d != NULL && v->getSize () == d->getSize ()) {
634  strlist * dep = new strlist ();
635  dep->add (n);
636  v->setDependencies (dep);
637  found++;
638  break;
639  }
640  }
641  }
642  // if not found, then no dependency vector
643  if (!found) v->setDependencies (new strlist ());
644  }
645  }
646 }
647 
648 // Checks the XFORM's in the model file
649 static void mdl_check_xforms (void) {
650  mdl_check_xform_dep ();
651  mdl_check_xform_deplen ();
652 }
653 
654 /* This function is the overall MDL data checker. It returns zero on
655  success, non-zero otherwise. */
656 int mdl_check (void) {
657  int errors = 0;
658  mdl_result = new dataset ();
659  struct mdl_link_t * root;
660  for (root = mdl_root; root; root = root->next) {
661  char * name = root->name;
662  mdl_find_link (root, name);
663  }
664  mdl_find_syncdatasets (mdl_sync_root);
665  mdl_check_xforms ();
666  return errors ? -1 : 0;
667 }
668 
669 // Destroys data used by the MDL checker.
670 void mdl_destroy (void) {
671  if (mdl_result != NULL) {
672  // delete associated dataset
673  delete mdl_result;
674  mdl_result = NULL;
675  }
676  if (mdl_root != NULL) {
677  // release internal data structures
678  struct mdl_link_t * root, * next;
679  for (root = mdl_root; root; root = next) {
680  next = root->next;
681  mdl_free_link (root);
682  }
683  mdl_root = NULL;
684  }
685  if (mdl_sync_root != NULL) {
686  // release internal sync structures
687  mdl_free_sync (mdl_sync_root);
688  mdl_sync_root = NULL;
689  }
690 }
691 
692 // Initializes the MDL checker.
693 void mdl_init (void) {
694  mdl_root = NULL;
695  mdl_result = NULL;
696  mdl_sync_root = NULL;
697 }