pmm  1.0.0
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
pmm_param.c
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008-2010 Robert Higgins
3  Author: Robert Higgins <robert.higgins@ucd.ie>
4 
5  This file is part of PMM.
6 
7  PMM is free software: you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation, either version 3 of the License, or
10  (at your option) any later version.
11 
12  PMM is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with PMM. If not, see <http://www.gnu.org/licenses/>.
19 */
20 /*!
21  * @file pmm_param.c
22  *
23  * @brief functions operating on benchmark and model parameters
24  *
25  * this file contains the code for working with parameters, parameter
26  * definitions, parameter arrays and so forth.
27  */
28 #if HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31 
32 #include <stdlib.h> // for malloc/free
33 #include <string.h> // for strcmp
34 #include <limits.h> // for INT_MAX
35 
36 #include "pmm_log.h"
37 #include "pmm_model.h"
38 
39 
40 /*!
41  * Create an empty parameter definition set structure. Note pd_array will
42  * not yet be allocated
43  *
44  * @return pointer to newly allocated structure
45  */
47 {
48  struct pmm_paramdef_set *pd_set;
49 
50  pd_set = malloc(sizeof *pd_set);
51 
52  pd_set->n_p = -1;
53 
54  pd_set->pc_formula = (void *)NULL;
55  pd_set->pc_max = -1;
56  pd_set->pc_min = -1;
57 
58  return pd_set;
59 }
60 
61 /*!
62  * Initialise a parameter array to all start values, as descripted by the
63  * parameter definitions
64  *
65  * @param pd_set pointer to parameter definition set
66  *
67  * @return pointer to an array of parameters with all start values of size n
68  */
69 int*
71 {
72  int *p;
73 
74  p = malloc(pd_set->n_p * sizeof *p);
75  if(p == NULL) {
76  ERRPRINTF("Error allocating memory.\n");
77  return NULL;
78  }
79 
80  set_param_array_start(p, pd_set);
81 
82  return p;
83 }
84 
85 /*!
86  * Initialise a parameter array to all end values, as descripted by the
87  * parameter definitions
88  *
89  * @param pd_set pointer to parameter definition set structure
90  *
91  * @return pointer to an array of parameters with all end values of size n
92  */
93 int*
95 {
96  int *p;
97 
98  p = malloc(pd_set->n_p * sizeof *p);
99  if(p == NULL) {
100  ERRPRINTF("Error allocating memory.\n");
101  return NULL;
102  }
103 
104  set_param_array_end(p, pd_set);
105 
106  return p;
107 }
108 
109 /*!
110  * Set a parameter array to all start values, as described by the parameter
111  * definitions
112  *
113  * @param p pointer to an array of parameters
114  * @param pd_set pointer to parameter definitions set structure
115  *
116  * @pre p must be a pointer to allocated memory, the number of elements in the
117  * p array must be identical to the number of parameter definitions
118  */
119 void
121 {
122  int i;
123 
124  for(i=0; i<pd_set->n_p; i++) {
125  p[i] = pd_set->pd_array[i].start;
126  }
127 
128  return;
129 }
130 
131 /*!
132  * Set a parameter array to all end values, as described by the parameter
133  * definitions
134  *
135  * @param p pointer to an array of parameters
136  * @param pd_set pointer to parameter definitions set structure
137  *
138  * @pre p must be a pointer to allocated memory, the number of elements in the
139  * p array must be identical to the number of parameter definitions
140  */
141 void
142 set_param_array_end(int *p, struct pmm_paramdef_set *pd_set)
143 {
144  int i;
145 
146  for(i=0; i<pd_set->n_p; i++) {
147  p[i] = pd_set->pd_array[i].end;
148  }
149 
150  return;
151 }
152 
153 
154 /*!
155  * Copy a parameter array into a newly allocated parameter array
156  *
157  * @param src pointer to the first element of the source parameter array
158  * @param n number of parameters in the source parameter array
159  *
160  * @return pointer to copied parameter array or NULL on failure
161  *
162  */
163 int*
164 init_param_array_copy(int *src, int n)
165 {
166  int *dst;
167 
168  //TODO rename to param_array_copy_to_new or something
169 
170  dst = malloc(n * sizeof *dst);
171  if(dst == NULL) {
172  ERRPRINTF("Error allocating memory.\n");
173  return NULL;
174  }
175 
176  set_param_array_copy(dst, src, n);
177 
178  return dst; //success
179 }
180 
181 /*!
182  * Copy from one parameter array to another
183  *
184  * @param dst pointer to the destination array
185  * @param src pointer tot the source array
186  * @param n number of elements in each array
187  *
188  * @return 0 on success, -1 on failure
189  *
190  * @pre src and dst arrays are of the same size (n)
191  */
192 void
193 set_param_array_copy(int *dst, int *src, int n)
194 {
195  int i;
196 
197  for(i=0; i<n; i++) {
198  dst[i] = src[i];
199  }
200 
201  return;
202 }
203 
204 /*!
205  * Copy a parameter definition structure from src to dst
206  *
207  * @param src pointer to the paramdef to copy
208  * @param dst pointer to the paramdef to copy into
209  *
210  * @return 0 on success, -1 on failure
211  *
212  * @pre src and dst point to allocated structures
213  */
214 int
215 copy_paramdef(struct pmm_paramdef *dst, struct pmm_paramdef *src)
216 {
217  dst->end = src->end;
218  dst->start = src->start;
219  dst->order = src->order;
220  dst->nonzero_end = src->nonzero_end;
221  dst->stride = src->stride;
222  dst->offset = src->offset;
223 
224  if(!set_str(&(dst->name), src->name)) {
225  ERRPRINTF("set_str failed setting name\n");
226  return -1;
227  }
228 
229  return 0;
230 }
231 
232 /*!
233  * Test if a set of parameters lies on one of the parameter axes of the model,
234  * i.e. all but one parameter is at a start or all parameters are start
235  * (i.e. at the origin).
236  *
237  * @param p pointer to the parameter array
238  * @param n number of elements in the parameter array
239  * @param pd_array pointer to the parameter defintions array
240  *
241  *
242  * @return the plane index of the parameter axis the benchmark belongs to or -1
243  * if on all axes (i.e. at origin), or -2 if on no boundaries
244  */
245 int
247  int n,
248  struct pmm_paramdef *pd_array)
249 {
250  int i;
251  int plane = -1;
252 
253  for(i=0; i<n; i++) {
254  // if a parameter is not a start
255  if(p[i] != pd_array[i].start) {
256 
257  //
258  // and if it is the first non-start parameter encountered then set
259  // the possible axis index to the parameter's index
260  //
261  if(plane == -1) {
262  plane = i; // set axis index
263  }
264  //
265  // else if it is the second non-start encounted we can conclude
266  // that the benchmark is not on parameter axis and return negative
267  //
268  else {
269  return -2;
270  }
271  }
272  }
273 
274  return plane;
275 
276 }
277 
278 /*!
279  * Test if a set of parameters is within the limits defined by the parameter
280  * definitions or outside them
281  *
282  * @param p pointer to parameter array
283  * @param n number of parameters
284  * @param pd_array pointer to parameter definition array
285  *
286  * @returns 1 if parameter p is within the parameter space defined by the
287  * parameter definitions, 0 if it is not
288  *
289  */
290 int
292 {
293  int i;
294 
295  for(i=0; i<n; i++) {
296  if(param_within_paramdef(p[i], &pd_array[i]) == 0) {
297  return 0;
298  }
299  }
300 
301  return 1;
302 
303 }
304 
305 /*!
306  * Test if a single parameter is within the limits defined by a parameter
307  * definition
308  *
309  * @param p the parameter
310  * @param pd pointer to the parameter definition
311  *
312  * @return 1 if parameter is within the parameter space defined by the
313  * parameter defintion. I.e. it is between the start and end points
314  */
315 int
317  int dist;
318 
319  dist = abs(pd->end - pd->start);
320 
321  if(abs(p - pd->end) > dist ||
322  abs(p - pd->start) > dist)
323  {
324  return 0;
325  }
326 
327  return 1;
328 }
329 
330 
331 /*!
332  * Align a parameter according to stride and offset defined in corresponding
333  * paramdef.
334  *
335  * @param param the value of the parameter we are aligning
336  * @param pd the corresponding parameter definition
337  *
338  * @return the aligned parameter
339  *
340  * @post the return value is aligned as closely as possible to the passed param.
341  * In cases where the aligned parameter is greater than the end, the parameter
342  * is decremented by the stride until it is within the end bound. If nonzero en
343  * is set, the end point is considered a valid point and the parameter is
344  * aligned to this, regardless if it is within the stride & offset describing
345  * the parameter sequence. If the aligned parameter is less than the start
346  * it is set to the start value, regardless of whether this is within the stride
347  * & offset describing the parameter sequence.
348  *
349  */
350 int
351 align_param(int param, struct pmm_paramdef *pd)
352 {
353  int aligned;
354  //int end_exceeded = 0;
355 
356  // if stride is 1 we can return the parameter as it will always be aligned
357  // while we limit input scalars to int types
358  if(pd->stride == 1) {
359  return param;
360  }
361 
362  //
363  // formula for alignment ...
364  //
365  // S is a sequence of the following form:
366  //
367  // S(x) = ax + b, x=0..
368  //
369  // where a = stride and b = offset
370  //
371  // to align a value p with the sequence, we must find the closet member
372  // of S to p: p_s. This can be achieved with the following steps:
373  //
374  // 1. Solve S(n) = p, for n
375  // 2. round n to get n_s, the position of the aligned value p_s in the
376  // sequence S
377  // 3. calculate S(n_s) to get value of p_s
378  //
379  // i.e.
380  //
381  // S(n) = an + b
382  // S(n) = p
383  //
384  // p = an + b
385  // n = (p-b)/a
386  //
387  // n_s = round(n) = round((p-b)/a)
388  //
389  // p_s = S(n_s) = a * round((p-b)/a) + b
390  //
391  // thus, we have the below code the align the param in terms of the
392  // offset and stride passed to this function
393  //
394  // a = stride, p = param, b = offset
395  //
396  // Note, round of integer division x/y = (x+y/2)/y ...
397  aligned = pd->stride *
398  (((param - pd->offset)+pd->stride/2) /
399  pd->stride) +
400  pd->offset;
401 
402 
403 
404  // if aligned parameter is greater than the end
405  if(aligned >= pd->end) {
406  //DBGPRINTF("greater than end:%d\n", aligned);
407  aligned = pd->end;
408 
409  /*
410  if(pd->nonzero_end == 1) {
411  aligned = pd->end-1; //set to end as this is a valid point, even
412  //if it is not in the sequence
413  }
414  else {
415  aligned = pd->endx;
416  while(aligned >= pd->end) { //decrement until it is less than end
417  aligned -= pd->stride;
418  }
419  }*/
420  }
421 
422  if(aligned < pd->start) { // if aligned parameter is less than start
423  //DBGPRINTF("less than start: %d\n", aligned);
424  aligned = pd->start; //set to start
425  }
426 
427 
428  //DBGPRINTF("param:%d aligned:%d\n", param, aligned);
429 
430  return aligned;
431 }
432 
433 /*!
434  * align an array of parameters
435  *
436  * @param [in,out] params pointer to the array of parameters to align
437  * @param [in] pd_set pointer to the corresponding parameter
438  * definition array
439  */
440 void
441 align_params(int *params, struct pmm_paramdef_set *pd_set)
442 {
443  int i;
444 
445  //DBGPRINTF("n_p:%d\n", n_p);
446 
447  for(i=0; i<pd_set->n_p; i++) {
448  //DBGPRINTF("params[%d]:%d\n", i, params[i]);
449  params[i] = align_param(params[i], &(pd_set->pd_array[i]));
450  }
451 
452  return;
453 }
454 
455 /*!
456  * initialized a set of align a set of parameters based on
457  * a set of unaligned parameters and parameter definitions
458  *
459  * @param p pointer to unaligned parameter array
460  * @param pd_set pointer to corresponding parameter definitions
461  *
462  * @returns allocated array of aligned parameters or NULL on failure
463  */
464 int*
465 init_aligned_params(int *p, struct pmm_paramdef_set *pd_set)
466 {
467  int *aligned_p;
468 
469  aligned_p = init_param_array_copy(p, pd_set->n_p);
470  if(aligned_p == NULL) {
471  ERRPRINTF("Error copying param array.\n");
472  return NULL;
473  }
474 
475  align_params(aligned_p, pd_set);
476 
477  return aligned_p;
478 }
479 
480 /*!
481  * Check if two parameter definition sets are identical
482  *
483  * @param pds_a pointer to first parameter definition set
484  * @param pds_b pointer to second parameter definition set
485  *
486  * @return 0 if not identical, 1 if identical
487  */
488 int
490  struct pmm_paramdef_set *pds_b)
491 {
492  if(pds_a->n_p != pds_b->n_p ||
493  pds_a->pc_max != pds_b->pc_max ||
494  pds_a->pc_min != pds_b->pc_min)
495  {
496  return 0;
497  }
498 
499  if(pds_a->pc_formula != NULL && pds_b->pc_formula != NULL)
500  {
501  if(strcmp(pds_a->pc_formula, pds_b->pc_formula) != 0) {
502  return 0;
503  }
504  }
505  else if((pds_a->pc_formula == NULL && pds_b->pc_formula != NULL) ||
506  (pds_a->pc_formula != NULL && pds_b->pc_formula == NULL))
507  {
508  return 0;
509  }
510 
511  if(!isequal_paramdef_array(pds_a->pd_array, pds_b->pd_array, pds_a->n_p)) {
512  return 0;
513  }
514 
515  return 1;
516 }
517 
518 /*!
519  * Check if two parameter definition arrays are equal.
520  *
521  * @param pd_array_a pointer to first parameter array
522  * @param pd_array_b pointer to second parameter array
523  * @param n_p number of parameters in the array
524  *
525  * @return 0 if arrays contain different parameter definitions, 1 if they
526  * are identical
527  */
528 int
530  struct pmm_paramdef *pd_array_b, int n_p)
531 {
532  int i;
533 
534  for(i=0; i<n_p; i++) {
535  if(!isequal_paramdef(&(pd_array_a[i]), &(pd_array_b[i]))) {
536  return 0;
537  }
538  }
539 
540  return 1;
541 }
542 
543 /*!
544  * Check if two parameter definitions are identical
545  *
546  * @param a pointer to first parameter definition
547  * @param b pointer to second parameter definition
548  *
549  * @return 0 if not identical, 1 if identical
550  */
551 int
553 {
554 
555  if(strcmp(a->name, b->name) != 0 ||
556  //a->type != b->type || TODO implement parameter types
557  a->order != b->order ||
558  a->nonzero_end != b->nonzero_end ||
559  a->end != b->end ||
560  a->start != b->start ||
561  a->stride != b->stride ||
562  a->offset != b->offset)
563  {
564  return 1;
565  }
566 
567  return 0;
568 }
569 
570 /*!
571  * Compare two parameter arrays in terms of their elements. Arrays are equal if
572  * all elements are equal, otherwise the most significant non-equal element
573  * determines which is greater.
574  *
575  * @param p1 pointer to first element of array 1
576  * @param p2 pointer to first element of array 2
577  * @param n number of elements in arrays
578  *
579  * @return >0 if array p1 is 'greater' than p2, <0 if p1 is 'less' than 'p2' or
580  * 0 of p1 is equal to p2.
581  *
582  * @pre arrays must be of the same length and not NULL
583  *
584  */
585 int
586 params_cmp(int *p1, int *p2, int n)
587 {
588  int i;
589 
590  if(p1 == NULL || p2 == NULL) {
591  ERRPRINTF("Parameter arrays should not be null.\n");
592  exit(EXIT_FAILURE);
593  }
594 
595  for(i=0; i<n; i++) {
596  if(p1[i] < p2[i]) {
597  return -1;
598  }
599  else if(p1[i] > p2[i]) {
600  return 1;
601  }
602  }
603 
604  return 0; // at this point, all parameters are identical
605 }
606 
607 /*!
608  * Step between two points, according to a minimum step size defined in
609  * the parameter definitions.
610  *
611  * @param params pointer to an array to store the parameters at the n-th
612  * step between the start and end points
613  * @param start pointer to array describing the start point
614  * @param end pointer to array describing the start point
615  * @param step number of steps to take along the interval (- to step
616  * backwards, + to step forwards)
617  * @param pd_set pointer to the parameter definition set
618  *
619  * @return 0 on success, -1 if the step will exceed the end-point of the
620  * interval or -2 on error
621  */
622 int
623 set_params_step_between_params(int *params, int *start, int *end,
624  int step, struct pmm_paramdef_set *pd_set)
625 {
626  int j;
627  int min_stride; //value of the minimum stride
628  int min_stride_i; //parameter index of the minimum stride
629  int min_stride_i_dist; //distance from start and end minstride parameters
630  int *direction; //direction of stride for each parameter (+1/-1)
631 
632  //
633  // The increment along the line from start->end will be achived by
634  // adding a value to start. If start > end, for a component of that line
635  // then that component should be decremented, not incremented. We control
636  // this by way of a direction factor, +1 for increment, -1 for decriment
637  //
638  direction = malloc(pd_set->n_p * sizeof *direction);
639  if(direction == NULL) {
640  ERRPRINTF("Error allocating memory.\n");
641  return -2;
642  }
643  for(j=0; j<pd_set->n_p; j++) {
644  if(start[j] > end[j]) {
645  DBGPRINTF("parameter:%d will be decremented.\n", j);
646  direction[j] = -1;
647  }
648  else {
649  DBGPRINTF("parameter:%d will be incremented.\n", j);
650  direction[j] = +1;
651  }
652  }
653 
654  //
655  // The increment along a line drawn from start->end is determined
656  // by the smallest stride of all the parameters whose axes in the
657  // model are not perpendicular to the line from start->end.
658  //
659  // E.g. if start = (1,1) and end = (1,5000) then the line joining
660  // start to end is perpendicular to the axis of the 1st parameter,
661  // and its stride should be ignored.
662  //
663  // It obviously follows that if the values of a parameter
664  // are equal in both the start and end points, then that parameter
665  // axis is perpendicular to the interval line.
666  //
667  min_stride = INT_MAX;
668  min_stride_i = -1;
669  for(j=0; j<pd_set->n_p; j++) {
670  if(start[j] != end[j]) {
671  if(pd_set->pd_array[j].stride < min_stride) {
672  min_stride = pd_set->pd_array[j].stride;
673  min_stride_i = j;
674  }
675  }
676  }
677 
678 
679 
680  DBGPRINTF("min_stride:%d, min_stride_i:%d\n", min_stride, min_stride_i);
681  if(min_stride_i == -1) {
682  DBGPRINTF("start and end points identical, cannot stride.\n");
683 
684  free(direction);
685  direction = NULL;
686 
687  return -1;
688  }
689  //
690  // Now that we have identified the parameter and stride we will
691  // increment along we must calculate the position of the incremented
692  // point with the particular stride we apply.
693  //
694  // The parametric representation of a line L between two points, S
695  // = (s_1, s_2, ..., s_n) and E = (e_1, e_2, ..., e_n) is:
696  //
697  // L = L(a) = S^T + a*B, where B = E^T - S^T
698  //
699  // If we take one of the components (the min_stride_i-th) of the
700  // start point S: s_i and increment it by the stride to get i_i
701  // (the value of the component at the incremented point I), then
702  // we can solve for a:
703  //
704  // i_i = s_i+inc = s_i+a(e_i-s_i)
705  // a = inc/(e_i-s_i)
706  //
707  // Then we may calculate all other values x= 0 ... n, for the
708  // incremented point I by calculating L with the solved a.
709  //
710  // I_x = s_x + (inc/(e_i-s_i))*(e_x-s_x)
711  //
712  // In order to maintain some precision when doing integer math we
713  // rearrange this to be
714  //
715  // I_x = s_x + inc*((e_x-s_x)/(e_i-s_i))
716  //
717  // let:
718  //
719  // divisor = e_i-s_i;
720  //
721  // So finally:
722  // I_x = s_x + inc*((e_x-s_x)/divisor)
723  //
724 
725  // to get the 1st/2nd/nth next/previous climb point
726  min_stride = min_stride*step;
727  min_stride_i_dist = end[min_stride_i] - start[min_stride_i];
728 
729  DBGPRINTF("step:%d min_stride:%d min_stride_i_dist:%d\n",
730  step, min_stride, min_stride_i_dist);
731 
732 
733 
734 
735  for(j=0; j<pd_set->n_p; j++) {
736  params[j] = start[j] + direction[j] *
737  (min_stride *
738  ((end[j] - start[j]) /
739  min_stride_i_dist
740  )
741  );
742 
743  // 1 + (5/(300-1))*(1-1) =
744  // 1 + (5/(300-1))*(300-1) = 1+5 ...
745 
746  DBGPRINTF("start[%d]:%d end{%d]:%d direction[%d]:%d\n", j, start[j], j,
747  end[j], j, direction[j]);
748  DBGPRINTF("start[min_stride_i]:%d end[min_stride_i]:%d\n",
749  start[min_stride_i], end[min_stride_i]);
750 
751  DBGPRINTF("params[%d]:%d\n", j, params[j]);
752  }
753 
754 
755  //check that params are within the range of the interval
756  {
757  int start_to_end;
758 
759  for(j=0; j<pd_set->n_p; j++) {
760  start_to_end = abs(end[j] - start[j]);
761  if(abs(end[j]-params[j]) > start_to_end ||
762  abs(start[j]-params[j]) > start_to_end)
763  {
764 
765  DBGPRINTF("stepped params are outside interval limits\n");
766 
767  free(direction);
768  direction = NULL;
769 
770  return -1;
771  }
772  }
773  }
774 
775  align_params(params, pd_set);
776 
777  DBGPRINTF("aligned params:\n");
778  print_params(PMM_DBG, params, pd_set->n_p);
779 
780  free(direction);
781  direction = NULL;
782 
783  return 0; // success
784 
785 }
786 
787 /*!
788  * Print a parameter array
789  *
790  * @param output output stream to print to
791  * @param p pointer to the parameter array
792  * @param n size of the parameter array
793  *
794  */
795 void
796 print_params(const char *output, int *p, int n)
797 {
798  int i;
799 
800  for(i=0; i<n; i++) {
801  SWITCHPRINTF(output, "p[%d]: %d\n", i, p[i]);
802  }
803 }
804 
805 /*!
806  * print a parameter definition array
807  *
808  * @param output output stream to print to
809  * @param pd_array pointer to parameter definition array
810  * @param n number of elements in array
811  */
812 void
813 print_paramdef_array(const char *output, struct pmm_paramdef *pd_array, int n)
814 {
815  int i;
816 
817  SWITCHPRINTF(output, "---paramdef-array---\n");
818  SWITCHPRINTF(output, "n: %d\n", n);
819  for(i=0; i<n; i++) {
820  print_paramdef(output, &(pd_array[i]));
821  }
822 }
823 
824 /*!
825  * print a parameter definition
826  *
827  * @param output output stream to print to
828  * @param pd pointer to parameter definition
829  */
830 void print_paramdef(const char *output, struct pmm_paramdef *pd)
831 {
832  SWITCHPRINTF(output, "name :%s\n", pd->name);
833  SWITCHPRINTF(output, "type :");
834 
835  if(pd->type == -1) {
836  //TODO implement parameter types
837  }
838  SWITCHPRINTF(output,"order: %d\n", pd->order);
839  SWITCHPRINTF(output, "nonzero_end: %d\n", pd->nonzero_end);
840  SWITCHPRINTF(output, "end: %d\n", pd->end);
841  SWITCHPRINTF(output, "start: %d\n", pd->start);
842  SWITCHPRINTF(output, "stride: %d\n", pd->stride);
843  SWITCHPRINTF(output, "offset: %d\n", pd->offset);
844 }
845 
846 /*!
847  * print a parameter definition set
848  *
849  * @param output output stream to print to
850  * @param pd_set pointer to parameter definition set
851  */
852 void print_paramdef_set(const char *output, struct pmm_paramdef_set *pd_set)
853 {
854  SWITCHPRINTF(output, "n_p:%d\n", pd_set->n_p);
855 
856  print_paramdef_array(output, pd_set->pd_array, pd_set->n_p);
857 
858  if(pd_set->pc_formula != NULL) {
859  SWITCHPRINTF(output, "pc_formula:%s\n", pd_set->pc_formula);
860  } else {
861  SWITCHPRINTF(output, "pc_formula:\n");
862  }
863 
864  SWITCHPRINTF(output, "pc_max:%d\n", pd_set->pc_max);
865  SWITCHPRINTF(output, "pc_min:%d\n", pd_set->pc_min);
866 }
867 
868 /*!
869  * frees a parameter definition set structure and members it contains
870  *
871  * @param pd_set pointer to address of parameter definition structure
872  */
873 void free_paramdef_set(struct pmm_paramdef_set **pd_set)
874 {
875 
876  if((*pd_set)->pd_array != NULL)
877  free_paramdef_array(&(*pd_set)->pd_array, (*pd_set)->n_p);
878 
879  free((*pd_set)->pc_formula);
880  (*pd_set)->pc_formula = NULL;
881 
882  free(*pd_set);
883  *pd_set = NULL;
884 
885 }
886 
887 /*!
888  * frees a parameter definition array
889  *
890  * @param pd_array pointer to address of parameter definition array
891  * @param n_p number of parameter definitions in array
892  */
894  int i;
895 
896  for(i=0; i<n_p; i++) {
897  free((*pd_array)[i].name);
898  (*pd_array)[i].name = NULL;
899  }
900 
901  free(*pd_array);
902  *pd_array = NULL;
903 
904 }
905