pmm  1.0.0
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
pmm_interval.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_interval.c
22  * @brief Code for working with construction intervals
23  *
24  * Construction intervals describe built/unbuilt regions of a model and
25  * are core to the optimised construction algorithms
26  */
27 #if HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30 
31 #include <stdlib.h> // for malloc/free
32 #include <string.h> // for strcmp
33 
34 #include "pmm_log.h"
35 #include "pmm_interval.h"
36 #include "pmm_model.h" // for param_array_copy, print_params
37 
38 /*!
39  * Allocate and return an interval list structure
40  *
41  * @returns pointer to new interval list
42  */
43 struct pmm_interval_list*
45 {
46  struct pmm_interval_list *l;
47 
48  l = malloc(sizeof *l);
49 
50  l->size = 0;
51  l->top = NULL;
52  l->bottom = NULL;
53 
54  return l;
55 }
56 
57 /*!
58  * frees an interval list structure and members it contains
59  *
60  * @param il pointer to address of the interval list
61  */
62 void
64 {
65 
66  struct pmm_interval *this, *next;
67 
68  this = (*il)->top;
69 
70  while(this != NULL) {
71  next = this->next;
72 
73  free_interval(&this);
74 
75  this = next;
76  }
77 
78  free(*il);
79  *il = NULL;
80 }
81 
82 /*!
83  * determine if interval list is empty
84  *
85  * @param l pointer to interval list
86  * @returns 1 if list is empty, 0 if list is not empty
87  */
88 int
90 {
91  //TODO static
92  if(l->size <= 0) {
93  return 1; // true
94  }
95  else {
96  return 0; // false
97  }
98 }
99 
100 /*!
101  * Allocate and return an interval structure with default, zero parameter values
102  *
103  * @return pointer to the allocated structure or NULL on failure
104  */
106 {
107  struct pmm_interval *i;
108 
109  i = malloc(sizeof *i);
110  if(i == NULL) {
111  ERRPRINTF("Error allocating memory for interval struct\n");
112  return i;
113  }
114 
115  i->plane = -1;
116  i->climb_step = 0;
117 
118  i->n_p = -1;
119  i->start = NULL;
120  i->end = NULL;
121 
122  i->type = IT_NULL;
123 
124  i->next = NULL;
125  i->previous = NULL;
126 
127  return i;
128 }
129 
130 /*!
131  * Initialize an interval with parameters passed.
132  *
133  * Function maybe be used with _INFLECT and _BISECT intervals and with
134  * _POINT intervals if the start parameter is set to the point. May also
135  * be used to on initial IT_GBBP_CLIMB but not once climb_step is non-zero
136  *
137  * @param plane plane that the interval belongs to (defunct)
138  * @param n_p number of parameters of the interval points
139  * @param type interval tyle
140  * @param start pointer to the start parameter array
141  * @param end pointer to the end parameter array
142  *
143  * @return pointer to a newly allocated interval with values initialised as
144  * per the arguments passed
145  *
146  */
148  int n_p,
149  enum pmm_interval_type type,
150  int *start,
151  int *end)
152 {
153  struct pmm_interval *i;
154 
155  i = new_interval();
156 
157  i->plane = plane;
158  i->n_p = n_p;
159  i->type = type;
160 
161  switch(i->type) {
162  case IT_GBBP_CLIMB :
163  case IT_GBBP_BISECT :
164  case IT_GBBP_INFLECT :
165  i->start = init_param_array_copy(start, n_p);
166  i->end = init_param_array_copy(end, n_p);
167  break;
168 
169  case IT_POINT :
170  i->start = init_param_array_copy(start, n_p);
171  break;
172 
173  default :
174  ERRPRINTF("Interval type not supported; %s\n",
176  free_interval(&i);
177  return NULL;
178  }
179 
180  return i;
181 }
182 
183 /*!
184  * frees an interval structure and members it contains
185  *
186  * @param i pointer to address of the interval
187  */
188 void free_interval(struct pmm_interval **i)
189 {
190  if((*i)->start != NULL) {
191  free((*i)->start);
192  (*i)->start = NULL;
193  }
194  if((*i)->end != NULL) {
195  free((*i)->end);
196  (*i)->end = NULL;
197  }
198 
199  free(*i);
200  *i = NULL;
201 }
202 
203 //TODO remove this is not neccessary
204 struct pmm_interval*
206 {
207  if(!isempty_interval_list(l)) {
208  return l->top; // success
209  }
210  else {
211  return NULL; // failure
212  }
213 }
214 
215 /*!
216  * Removes and deletes the top interval on an interval list
217  *
218  * @param l pointer to the interval list
219  *
220  * @return 0 on failure, 1 on success
221  */
222 //TODO fix naming of functions so 'remove'/'delete' indicates deallocation also
223 //TODO fix return to -1 on failure, 0 on success
224 int
226 {
227  // remove top destructively removes the top element of the list, remember
228  // to read it first or it will be gone forever
229 
230  struct pmm_interval *zombie;
231 
232  if(isempty_interval_list(l)) {
233  return 0; // failure
234  }
235  else {
236 
237  if(l->top == l->bottom) { /* only one element in list */
238  zombie = l->top;
239  l->top = NULL;
240  l->bottom = NULL;
241 
242  }
243  else {
244  /* swap old top with new top */
245  zombie = l->top;
246  l->top = zombie->previous;
247 
248  l->top->next=NULL;
249 
250 
251  }
252 
253  free_interval(&zombie);
254 
255  l->size -= 1;
256 
257  return 1; // success
258  }
259 }
260 
261 /*!
262  * Removes and deletes an interval from an interval list
263  *
264  * @param l pointer to interval list
265  * @param i pointer to the interval to remove
266  *
267  * @return 1 on success
268  */
269 //TODO failure? return 0 on success
270 int
272 {
273 
274  LOGPRINTF("removing interval with type: %d\n", i->type);
275 
276  //if interval is at top or bottom, rewire top/bottom pointers
277  if(l->top == i) {
278  l->top = i->previous;
279  }
280  if(l->bottom == i) {
281  l->bottom = i->next;
282  }
283 
284  //rewire intervals that were previous/next intervals of the remove-ee
285  if(i->next != NULL) {
286  i->next->previous = i->previous;
287  }
288  if(i->previous != NULL) {
289  i->previous->next = i->next;
290  }
291 
292 
293  //free interval
294  free_interval(&i);
295  l->size -= 1;
296 
297  LOGPRINTF("size: %d\n", l->size);
298 
299  return 1;
300 }
301 
302 
303 /*!
304  * link the interval into interval list at the top/front
305  *
306  * @param l pointer to interval list
307  * @param i pointer to interval to add to list
308  *
309  * @return success always
310  */
312 {
313 
314  /* if the list was empty, new i will be only member, top & bottom */
315  if(isempty_interval_list(l)) {
316  i->previous = NULL;
317  i->next = NULL;
318 
319  l->bottom = i;
320  l->top = i;
321  } else {
322  i->previous = l->top;
323  l->top->next = i;
324 
325  l->top = i;
326  i->next = NULL;
327  }
328 
329  l->size += 1;
330 
331  return 0; // success TODO void
332 }
333 
334 /*!
335  * Add an interval to the bottom of the interval list
336  *
337  * @param l pointer to the interval list
338  * @param i pointer to the interval
339  *
340  * @return 0 on success
341  */
342 int
344 {
345 
346  // if the list was empty, new i will be only member, top & bottom
347  if(isempty_interval_list(l)) {
348  i->previous = NULL;
349  i->next = NULL;
350 
351  l->bottom = i;
352  l->top = i;
353  } else {
354  i->next = l->bottom;
355  l->bottom->previous = i;
356 
357  l->bottom = i;
358  i->previous = NULL;
359  }
360 
361  l->size += 1;
362 
363  return 0; // success
364 }
365 
366 
367 /*!
368  * print interval list
369  *
370  * @param output output stream to print to
371  * @param l interval list to print
372  */
373 void
374 print_interval_list(const char *output, struct pmm_interval_list *l)
375 {
376  struct pmm_interval *i;
377  int c;
378 
379  i = l->top;
380 
381  c=0;
382  while(i != NULL) {
383  SWITCHPRINTF(output, "%d of %d intervals ...\n", c, l->size);
384 
385  print_interval(output, i);
386 
387  i = i->previous;
388  c++;
389  }
390 }
391 
392 /*!
393  * map interval type to string for printing
394  *
395  * @param type interval type
396  *
397  * @return char string describing interval
398  */
399 char*
401 {
402  switch (type) {
403  case IT_GBBP_EMPTY:
404  return "IT_GBBP_EMPTY";
405  case IT_GBBP_CLIMB:
406  return "IT_GBBP_CLIMB";
407  case IT_GBBP_BISECT:
408  return "IT_GBBP_BISECT";
409  case IT_GBBP_INFLECT:
410  return "IT_GBBP_INFLECT";
412  return "IT_BOUNDARY_COMPLETE";
413  case IT_COMPLETE:
414  return "IT_COMPLETE";
415  case IT_POINT:
416  return "IT_POINT";
417  case IT_NULL:
418  return "IT_NULL";
419  default:
420  return "UNKNOWN";
421  }
422 
423 }
424 
425 /*!
426  * print interval
427  *
428  * @param output output stream to print to
429  * @param i interval to print
430  */
431 void print_interval(const char *output, struct pmm_interval *i) {
432 
433  SWITCHPRINTF(output, "type: %s\n", interval_type_to_string(i->type));
434 
435  switch (i->type) {
436  case IT_GBBP_EMPTY :
437  case IT_GBBP_CLIMB :
438  SWITCHPRINTF(output, "climb_step: %d\n", i->climb_step);
439  case IT_GBBP_BISECT :
440  case IT_GBBP_INFLECT :
441  SWITCHPRINTF(output, "plane: %d\n", i->plane);
442  SWITCHPRINTF(output, "n_p: %d\n", i->n_p);
443  SWITCHPRINTF(output, "start:\n");
444  print_params(output, i->start, i->n_p);
445  SWITCHPRINTF(output, "end:\n");
446  print_params(output, i->end, i->n_p);
447  break;
449  break;
450  case IT_COMPLETE:
451  break;
452  case IT_POINT:
453  SWITCHPRINTF(output, "n_p: %d\n", i->n_p);
454  print_params(output, i->start, i->n_p);
455  break;
456  default:
457  break;
458  }
459 }
460 /*
461  * Test if a benchmark is contained within an interval.
462  *
463  * For intervals of IT_POINT type the test is if the benchmark is at the
464  * interval point, for other interval types the test is if the benchmark
465  * lies inside a line segment going from the start point of the interval to
466  * the end point of the interval.
467  *
468  * @param r pointer to the routine the bench and intervals belong to
469  * @param i pointer to the interval being tested
470  * @param b poitner to the benchmark being tested
471  *
472  * @return 0 if the benchmark is not contained by the interval, 1 if the
473  * benchmark is contained by the interval, -1 on error
474  */
475 /* TODO implement interval_contains_bench with non-boundary intervals
476 int interval_contains_bench(struct pmm_routine *r, struct pmm_interval *i,
477  struct pmm_benchmark *b)
478 {
479  int b_plane;
480 
481  switch(i->type) {
482  case IT_BOUNDARY_COMPLETE :
483  case IT_COMPLETE :
484  return 0; //false
485  break;
486 
487  case IT_POINT :
488  if(params_cmp(b->p, i->point->p, b->n_p) == 0) {
489  return 1; //true
490  }
491  else {
492  return 0; //false
493  }
494  break;
495  case IT_GBBP_EMPTY :
496  case IT_GBBP_CLIMB :
497  case IT_GBBP_BISECT :
498  case IT_GBBP_INFLECT :
499  //
500  // to test if a point c is between two other points a & b,
501  // first, test they are collinear
502  //
503  b_plane = param_on_boundary(r->n_p, r->paramdef_array, b->p);
504  if(b_plane == i->plane || //if b is on this interval's plane
505  b_plane == -1) { //or if b is on all interval planes
506 
507  if(b->p[i->plane] >= i->start && b->p[i->plane] <= i->end)
508 
509  {
510  return 1; //true
511  }
512  else {
513  return 0; //false
514  }
515  }
516  else {
517  ERRPRINTF("benchmark not on expected boundary plane.\n");
518  }
519  break;
520 
521  default:
522  ERRPRINTF("Invalid interval type: %d\n", i->type);
523  break;
524  }
525 
526  return 0;
527 }
528 */