Scippy

SCIP

Solving Constraint Integer Programs

expriter.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2022 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not visit scip.zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file expriter.c
17  * @ingroup OTHER_CFILES
18  * @brief functions for iterating over algebraic expressions
19  * @author Benjamin Mueller
20  * @author Stefan Vigerske
21  */
22 
23 /* enable this to record where active iterators were initialized
24  * (not thread-safe; problematic when using several SCIP instances concurrently)
25  */
26 /* #define SCIP_DEBUG_EXPRITER */
27 
28 #include <assert.h>
29 
30 #include "scip/expr.h"
31 #include "scip/pub_misc.h"
32 #include "scip/struct_expr.h"
33 #include "scip/struct_stat.h"
34 
35 #define MINDFSSIZE 16 /**< minimum stack size for DFS*/
36 #define MINBFSSIZE 16 /**< minimum queue size for BFS */
37 
38 #ifdef SCIP_DEBUG_EXPRITER
39 #include <execinfo.h>
40 #include <string.h>
41 #include <stdlib.h>
42 
43 #define MAXSUBSCIPDEPTH 10 /**< minimal subscip-depth to no longer store backtrace */
44 #define MAXBACKTRACE 20 /**< maximal length of backtrace to store */
45 
46 /** backtrace when iterator was initialized
47  * - store per subscip-depth (easier than storing per SCIP instance)
48  * - store per iterator position that can be active concurrently
49  * - one string for each entry in backtrace
50  * - each entry up to 200 characters
51  */
52 char iterinitbacktrace[MAXSUBSCIPDEPTH][SCIP_EXPRITER_MAXNACTIVE][MAXBACKTRACE][200];
53 #endif
54 
55 /*
56  * local functions
57  */
58 
59 #ifdef SCIP_DEBUG_EXPRITER
60 /** obtain current backtrace and store it in iterinitbacktrace */
61 static
62 void storeBacktrace(
63  int subscipdepth, /**< current subscip depth */
64  int iterpos /**< iterator position where to store backtrace */
65  )
66 {
67  void* array[MAXBACKTRACE];
68  char** strings;
69  int size;
70  int i;
71 
72  assert(subscipdepth >= 0);
73  assert(iterpos >= 0);
74  assert(iterpos < SCIP_EXPRITER_MAXNACTIVE);
75 
76  if( subscipdepth > MAXSUBSCIPDEPTH )
77  return;
78 
79  size = backtrace(array, MAXBACKTRACE);
80  strings = backtrace_symbols(array, size);
81  if( strings == NULL )
82  size = 0;
83 
84  for( i = 0; i < size; i++ )
85  strncpy(iterinitbacktrace[subscipdepth][iterpos][i], strings[i], sizeof(iterinitbacktrace[0][0][0]));
86 
87  /* '\0' for remining backtrace entries */
88  while( size < MAXBACKTRACE )
89  iterinitbacktrace[subscipdepth][iterpos][size++][0] = '\0';
90 
91  free(strings);
92 }
93 
94 static
95 void printBacktraces(
96  int subscipdepth /**< current subscip depth */
97  )
98 {
99  int i, j;
100 
101  assert(subscipdepth >= 0);
102  if( subscipdepth >= MAXSUBSCIPDEPTH )
103  {
104  SCIPerrorMessage("subscip depth %d too high to report active iterators", subscipdepth);
105  return;
106  }
107 
108  for( i = 0; i < SCIP_EXPRITER_MAXNACTIVE-1; ++i )
109  {
110  SCIPerrorMessage("Active iterator %d created at:\n", i);
111  for( j = 0; j < MAXBACKTRACE; ++j )
112  {
113  if( iterinitbacktrace[subscipdepth][i][j][0] == '\0' )
114  break;
115  SCIPerrorMessage(" %s\n", iterinitbacktrace[subscipdepth][i][j]);
116  }
117  }
118 }
119 #else
120 #define storeBacktrace(subscipdepth, iterpos)
121 
122 /*lint -e{715}*/
123 static
125  int subscipdepth /**< current subscip depth */
126  )
127 { /*lint --e{715}*/
128  SCIPerrorMessage("Rebuild with SCIP_DEBUG_EXPRITER defined in src/scip/expriter.c to see where currently "
129  "active iterators were initialized.\n");
130 }
131 #endif
132 
133 static
134 void deinit(
135  SCIP_EXPRITER* iterator /**< expression iterator */
136  )
137 {
138  assert(iterator != NULL );
139 
140  if( !iterator->initialized )
141  return;
142 
143  if( iterator->iterindex >= 0 )
144  {
145  /* the iterindex must be the one of the last initialized iterator */
146  assert(iterator->iterindex == iterator->stat->nactiveexpriter-1);
147 
148  /* tell core that this iterator is no longer active */
149  --iterator->stat->nactiveexpriter;
150 
151  iterator->iterindex = -1;
152  }
153 
154  switch( iterator->itertype )
155  {
156  case SCIP_EXPRITER_BFS :
157  {
158  assert(iterator->queue != NULL);
159 
160  SCIPqueueFree(&iterator->queue);
161 
162  break;
163  }
164 
166  {
167  assert(iterator->dfsnvisited != NULL);
168  assert(iterator->dfsexprs != NULL);
169 
170  /* free dfs arrays */
171  BMSfreeBlockMemoryArray(iterator->blkmem, &iterator->dfsnvisited, iterator->dfssize);
172  BMSfreeBlockMemoryArray(iterator->blkmem, &iterator->dfsexprs, iterator->dfssize);
173  iterator->dfssize = 0;
174 
175  break;
176  }
177 
178  case SCIP_EXPRITER_DFS :
179  default: break;
180  }
181 }
182 
183 /** ensures minimum stack size of iterator's data */
184 static
186  SCIP_EXPRITER* iterator, /**< expression iterator */
187  int size /**< minimum requires size */
188  )
189 {
190  assert(iterator != NULL);
191  assert(iterator->blkmem != NULL);
192  assert(iterator->itertype == SCIP_EXPRITER_RTOPOLOGIC);
193  assert(size >= 0);
194 
195  if( size > iterator->dfssize )
196  {
197  int newsize = size * 2;
198 
199  SCIP_ALLOC( BMSreallocBlockMemoryArray(iterator->blkmem, &iterator->dfsexprs, iterator->dfssize, newsize) );
200  SCIP_ALLOC( BMSreallocBlockMemoryArray(iterator->blkmem, &iterator->dfsnvisited, iterator->dfssize, newsize) );
201  iterator->dfssize = newsize;
202  }
203 
204  return SCIP_OKAY;
205 }
206 
207 /** adds an expression to the DFS stack */
208 static
210  SCIP_EXPRITER* iterator, /**< expression iterator */
211  SCIP_EXPR* expr /**< expression */
212  )
213 {
214  assert(iterator != NULL);
215  assert(expr != NULL);
216 
217  SCIP_CALL_ABORT( ensureStackSize(iterator, iterator->dfsnexprs + 1) );
218  iterator->dfsexprs[iterator->dfsnexprs] = expr;
219  iterator->dfsnvisited[iterator->dfsnexprs] = 0;
220  ++(iterator->dfsnexprs);
221 }
222 
223 /** moves to the next expression according to a reverse topological order */
224 static
226  SCIP_EXPRITER* iterator /**< expression iterator */
227  )
228 {
229  SCIP_EXPR* expr;
230  int childidx;
231 
232  assert(iterator != NULL);
233  assert(iterator->itertype == SCIP_EXPRITER_RTOPOLOGIC);
234 
235  /* no expression left */
236  if( iterator->dfsnexprs == 0 )
237  return NULL;
238 
239  /* get expression on the top of the stack */
240  expr = iterator->dfsexprs[iterator->dfsnexprs - 1];
241  childidx = iterator->dfsnvisited[iterator->dfsnexprs - 1];
242 
243  /* remove the expression if all children have been visited */
244  if( childidx >= SCIPexprGetNChildren(expr) )
245  {
246  --(iterator->dfsnexprs);
247  return expr;
248  }
249  /* go to the next child */
250  else
251  {
252  SCIP_EXPR* child = SCIPexprGetChildren(expr)[childidx];
253  assert(child != NULL);
254 
255  /* mark that the child has been visited */
256  ++(iterator->dfsnvisited[iterator->dfsnexprs-1]);
257 
258  /* do left-most step */
259  while( SCIPexprGetNChildren(child) > 0 )
260  {
261  /* add child to the DFS stack */
262  reverseTopologicalInsert(iterator, child);
263 
264  /* mark that the child has been visited; note that child is on top of the DFS stack */
265  ++(iterator->dfsnvisited[iterator->dfsnexprs-1]);
266 
267  child = SCIPexprGetChildren(child)[0];
268  }
269 
270  /* return last child; NOTE this child is not been added to the stack */
271  return child;
272  }
273 }
274 
275 /** moves to the next expression according to the BFS rule */
276 static
278  SCIP_EXPRITER* iterator /**< expression iterator */
279  )
280 {
281  SCIP_EXPR* expr;
282  int i;
283 
284  assert(iterator != NULL);
285  assert(iterator->itertype == SCIP_EXPRITER_BFS);
286  assert(iterator->queue != NULL);
287 
288  /* no expression left */
289  if( SCIPqueueIsEmpty(iterator->queue) )
290  return NULL;
291 
292  expr = (SCIP_EXPR*) SCIPqueueRemove(iterator->queue);
293  assert(expr != NULL);
294 
295  assert(iterator->visitedtag == 0 || iterator->iterindex >= 0);
296  assert(iterator->visitedtag == 0 || iterator->iterindex < SCIP_EXPRITER_MAXNACTIVE);
297  /* we should have set the visitedtag when adding the expression to the queue */
298  assert(iterator->visitedtag == 0 || expr->iterdata[iterator->iterindex].visitedtag == iterator->visitedtag);
299 
300  /* add all (possibly non-visited) children to the queue */
301  for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
302  {
303  SCIP_EXPR* child = SCIPexprGetChildren(expr)[i];
304  assert(child != NULL);
305 
306  if( iterator->visitedtag != 0 )
307  {
308  assert(iterator->iterindex >= 0);
309  assert(iterator->iterindex < SCIP_EXPRITER_MAXNACTIVE);
310 
311  /* skip children that have already been visited or have already been added to the queue */
312  if( child->iterdata[iterator->iterindex].visitedtag == iterator->visitedtag )
313  continue;
314 
315  /* mark child as being in the queue (will be inserted next) */
316  child->iterdata[iterator->iterindex].visitedtag = iterator->visitedtag;
317  }
318 
319  /* add child to the queue */
320  SCIP_CALL_ABORT( SCIPqueueInsert(iterator->queue, child) );
321  }
322 
323  return expr;
324 }
325 
326 /** moves to the next expression according to the DFS rule */
327 static
329  SCIP_EXPRITER* iterator /**< expression iterator */
330  )
331 {
332  SCIP_EXPRITERDATA* iterdata;
333 
334  assert(iterator != NULL);
335  assert(iterator->itertype == SCIP_EXPRITER_DFS);
336  assert(iterator->iterindex >= 0);
337 
338  if( iterator->curr == NULL )
339  return NULL;
340 
341  iterdata = &iterator->curr->iterdata[iterator->iterindex];
342 
343  switch( iterator->dfsstage )
344  {
346  /* consider next child */
347  ++iterdata->currentchild;
348  /* fall through */ /* no break */ /*lint -fallthrough*/
349 
351  {
352  /* if there is an unvisited child (left), then go into visitingchild stage, otherwise go to leave stage */
353  iterator->dfsstage = SCIP_EXPRITER_LEAVEEXPR; /* expect that we will leave expr, and change mind to visitingchild below */
354  while( iterdata->currentchild < iterator->curr->nchildren )
355  {
356  if( iterator->visitedtag == 0 || iterator->visitedtag != iterator->curr->children[iterdata->currentchild]->iterdata[iterator->iterindex].visitedtag )
357  {
358  /* if visitedtag is not used or child "currentchild" has not been visited yet, then go into visitingchild stage for this child */
360  break;
361  }
362  ++iterdata->currentchild;
363  }
364  /* if leaving expr, then currentchild should be at nchildren */
365  assert(iterator->dfsstage == SCIP_EXPRITER_VISITINGCHILD || iterdata->currentchild == iterator->curr->nchildren);
366  /* if visiting child, then currentchild should be a valid index */
367  assert(iterator->dfsstage == SCIP_EXPRITER_LEAVEEXPR || iterdata->currentchild < iterator->curr->nchildren);
368  /* if visiting child, then either we don't care whether we visited it already or it has not been visited yet */
369  assert(iterator->dfsstage == SCIP_EXPRITER_LEAVEEXPR || iterator->visitedtag == 0
370  || iterator->visitedtag != iterator->curr->children[iterdata->currentchild]->iterdata[iterator->iterindex].visitedtag);
371 
372  return iterator->curr;
373  }
374 
376  {
377  SCIP_EXPR* child;
378 
379  assert(iterdata->currentchild < iterator->curr->nchildren);
380 
381  /* remember the parent and set the first child that should be visited of the new root */
382  child = iterator->curr->children[iterdata->currentchild];
383  child->iterdata[iterator->iterindex].parent = iterator->curr;
384  child->iterdata[iterator->iterindex].currentchild = 0;
385 
386  /* visit child */
387  iterator->dfsstage = SCIP_EXPRITER_ENTEREXPR;
388 
389  return child;
390  }
391 
393  {
394  /* go back to parent expression */
395 
396  /* remember that this expression has been visited */
397  iterdata->visitedtag = iterator->visitedtag;
398 
399  /* be in visitedchild stage for the parent */
401 
402  return iterdata->parent;
403  }
404 
405  default:
406  /* unknown stage */
407  SCIPABORT();
408  return NULL;
409  }
410 }
411 
412 /*
413  * private functions (expr.h)
414  */
415 
416 /** creates an expression iterator */
418  SCIP_STAT* stat, /**< dynamic problem statistics */
419  BMS_BLKMEM* blkmem, /**< block memory */
420  SCIP_EXPRITER** iterator /**< buffer to store expression iterator */
421  )
422 {
423  assert(stat != NULL);
424  assert(blkmem != NULL);
425  assert(iterator != NULL);
426 
427  SCIP_ALLOC( BMSallocClearBlockMemory(blkmem, iterator) );
428 
429  (*iterator)->stat = stat;
430  (*iterator)->blkmem = blkmem;
431 
432  return SCIP_OKAY;
433 }
434 
435 /** frees an expression iterator */
437  SCIP_EXPRITER** iterator /**< pointer to the expression iterator */
438  )
439 {
440  assert(iterator != NULL);
441  assert(*iterator != NULL);
442  assert((*iterator)->blkmem != NULL);
443 
444  deinit(*iterator);
445 
446  assert((*iterator)->queue == NULL);
447  assert((*iterator)->dfsnvisited == NULL);
448  assert((*iterator)->dfsexprs == NULL);
449 
450  /* free iterator */
451  BMSfreeBlockMemory((*iterator)->blkmem, iterator);
452 }
453 
454 /*
455  * public functions (pub_expr.h)
456  */
457 
458 #ifdef NDEBUG
459 #undef SCIPexpriterIsInit
460 #undef SCIPexpriterGetCurrent
461 #undef SCIPexpriterGetStageDFS
462 #undef SCIPexpriterGetChildIdxDFS
463 #undef SCIPexpriterGetChildExprDFS
464 #undef SCIPexpriterGetParentDFS
465 #undef SCIPexpriterGetCurrentUserData
466 #undef SCIPexpriterGetChildUserDataDFS
467 #undef SCIPexpriterGetExprUserData
468 #undef SCIPexpriterSetCurrentUserData
469 #undef SCIPexpriterSetExprUserData
470 #undef SCIPexpriterSetChildUserData
471 #undef SCIPexpriterIsEnd
472 #endif
473 
474 /** returns whether expression iterator is currently initialized */
476  SCIP_EXPRITER* iterator /**< expression iterator */
477  )
478 {
479  assert(iterator != NULL);
480 
481  return iterator->initialized;
482 }
483 
484 /** initializes an expression iterator
485  *
486  * @note If `expr` is NULL, then iterator will be set into ended-state (SCIPexpriterIsEnd() is TRUE). Useful if following with SCIPexpriterRestartDFS().
487  *
488  * If type is DFS, then `stopstages` will be set to \ref SCIP_EXPRITER_ENTEREXPR.
489  * Use `SCIPexpriterSetStagesDFS` to change this.
490  */
492  SCIP_EXPRITER* iterator, /**< expression iterator */
493  SCIP_EXPR* expr, /**< expression of the iterator, can be NULL */
494  SCIP_EXPRITER_TYPE type, /**< type of expression iterator */
495  SCIP_Bool allowrevisit /**< whether expression are allowed to be visited more than once */
496  )
497 {
498  assert(iterator != NULL);
499 
500  deinit(iterator);
501 
502  /* store the new type of the iterator */
503  iterator->itertype = type;
504 
505  /* get iterindex, if necessary */
506  if( !allowrevisit || type == SCIP_EXPRITER_DFS )
507  {
508  if( iterator->stat->nactiveexpriter + 1 >= SCIP_EXPRITER_MAXNACTIVE )
509  {
510  SCIPerrorMessage("Maximal number of active expression iterators reached at subscip-depth %d.\n",
511  iterator->stat->subscipdepth);
512  printBacktraces(iterator->stat->subscipdepth);
513  return SCIP_MAXDEPTHLEVEL;
514  }
515 
516  iterator->iterindex = iterator->stat->nactiveexpriter++;
517 
518  storeBacktrace(iterator->stat->subscipdepth, iterator->iterindex);
519  }
520  else
521  {
522  iterator->iterindex = -1;
523  }
524 
525  /* get new tag to recognize visited expressions */
526  if( !allowrevisit )
527  {
528  iterator->visitedtag = ++iterator->stat->exprlastvisitedtag;
529  }
530  else
531  {
532  iterator->visitedtag = 0L;
533  }
534 
535  switch( iterator->itertype )
536  {
537  case SCIP_EXPRITER_BFS:
538  {
539  SCIP_CALL( SCIPqueueCreate(&iterator->queue, MINBFSSIZE, 2.0) );
540 
541  assert(iterator->queue != NULL);
542  SCIPqueueClear(iterator->queue);
543 
544  if( expr == NULL )
545  {
546  iterator->curr = NULL;
547  break;
548  }
549 
550  SCIP_CALL( SCIPqueueInsert(iterator->queue, expr) );
551 
552  if( iterator->visitedtag != 0 )
553  {
554  assert(iterator->iterindex >= 0);
555  assert(iterator->iterindex < SCIP_EXPRITER_MAXNACTIVE);
556  assert(expr->iterdata[iterator->iterindex].visitedtag != iterator->visitedtag);
557 
558  /* mark expression as being in the queue */
559  expr->iterdata[iterator->iterindex].visitedtag = iterator->visitedtag;
560  }
561 
562  iterator->curr = SCIPexpriterGetNext(iterator);
563  break;
564  }
565 
567  {
568  SCIP_CALL( ensureStackSize(iterator, MINDFSSIZE) );
569 
570  if( expr != NULL )
571  {
572  reverseTopologicalInsert(iterator, expr);
573  iterator->curr = SCIPexpriterGetNext(iterator);
574  }
575  else
576  {
577  iterator->curr = NULL;
578  }
579 
580  break;
581  }
582 
583  case SCIP_EXPRITER_DFS :
584  {
585  assert(iterator->iterindex >= 0);
586 
588  iterator->curr = expr;
589 
590  if( expr == NULL )
591  break;
592 
593  expr->iterdata[iterator->iterindex].currentchild = 0;
594  expr->iterdata[iterator->iterindex].parent = NULL;
595  iterator->dfsstage = SCIP_EXPRITER_ENTEREXPR;
596 
597  break;
598  }
599  }
600 
601  iterator->initialized = TRUE;
602 
603  return SCIP_OKAY;
604 }
605 
606 /** restarts an already initialized expression iterator in DFS mode
607  *
608  * The expression iterator will continue from the given expression, not revisiting expressions that
609  * this iterator has already been visited (if initialized with `allowrevisit=FALSE`) and giving access
610  * to the same iterator specified expression data that may have been set already.
611  * Also the stop-stages are not reset.
612  *
613  * If revisiting is forbidden and given expr has already been visited, then the iterator will behave
614  * as on the end of iteration (SCIPexpriterIsEnd() is TRUE).
615  * If the enterexpr stage is not one of the stop stages, then the iterator will be moved forward
616  * (SCIPexpriterGetNext() is called).
617  *
618  * @return The current expression.
619  */
621  SCIP_EXPRITER* iterator, /**< expression iterator */
622  SCIP_EXPR* expr /**< expression of the iterator */
623  )
624 {
625  assert(iterator != NULL);
626  assert(iterator->initialized);
627  assert(iterator->itertype == SCIP_EXPRITER_DFS);
628 
629  /* if we forbid revisiting and root expr has already been visited, then set curr to NULL, that is, be at end of iterator */
630  if( iterator->visitedtag > 0 && expr->iterdata[iterator->iterindex].visitedtag == iterator->visitedtag )
631  {
632  iterator->curr = NULL;
633  return NULL;
634  }
635 
636  /* set current to given expr, make it the root, and set stage to enterexpr */
637  iterator->curr = expr;
638  expr->iterdata[iterator->iterindex].currentchild = 0;
639  expr->iterdata[iterator->iterindex].parent = NULL;
640  iterator->dfsstage = SCIP_EXPRITER_ENTEREXPR;
641 
642  if( (iterator->stopstages & SCIP_EXPRITER_ENTEREXPR) == 0 )
643  return SCIPexpriterGetNext(iterator);
644 
645  return iterator->curr;
646 }
647 
648 /** specifies in which stages to stop a DFS iterator
649  *
650  * Parameter `stopstages` should be a bitwise OR of different \ref SCIP_EXPRITER_STAGE values
651  *
652  * If the current stage is not one of the `stopstages`, then the iterator will be moved on.
653  */
655  SCIP_EXPRITER* iterator, /**< expression iterator */
656  SCIP_EXPRITER_STAGE stopstages /**< the stages in which to stop when iterating via DFS */
657  )
658 {
659  assert(iterator != NULL);
660 
661  if( (iterator->dfsstage & stopstages) == 0 )
662  {
663  iterator->stopstages = stopstages;
664  (void) SCIPexpriterGetNext(iterator);
665  }
666  else
667  {
668  iterator->stopstages = stopstages;
669  }
670 }
671 
672 /** gets the current expression that the expression iterator points to */
674  SCIP_EXPRITER* iterator /**< expression iterator */
675  )
676 {
677  assert(iterator != NULL);
678 
679  return iterator->curr;
680 }
681 
682 /** gets the current stage that the expression iterator is in when using DFS
683  *
684  * If the iterator has finished (SCIPexpriterIsEnd() is TRUE), then the stage is undefined.
685  */
687  SCIP_EXPRITER* iterator /**< expression iterator */
688  )
689 {
690  assert(iterator != NULL);
691  assert(iterator->itertype == SCIP_EXPRITER_DFS);
692 
693  return iterator->dfsstage;
694 }
695 
696 /** gets the index of the child that the expression iterator considers when in DFS mode and stage \ref SCIP_EXPRITER_VISITINGCHILD or \ref SCIP_EXPRITER_VISITEDCHILD */
698  SCIP_EXPRITER* iterator /**< expression iterator */
699  )
700 {
701  assert(iterator != NULL);
702  assert(iterator->curr != NULL);
703  assert(iterator->iterindex >= 0);
704  assert(iterator->itertype == SCIP_EXPRITER_DFS);
705  assert(iterator->dfsstage == SCIP_EXPRITER_VISITINGCHILD || iterator->dfsstage == SCIP_EXPRITER_VISITEDCHILD);
706 
707  return iterator->curr->iterdata[iterator->iterindex].currentchild;
708 }
709 
710 /** gets the child expression that the expression iterator considers when in DFS mode and stage \ref SCIP_EXPRITER_VISITINGCHILD or \ref SCIP_EXPRITER_VISITEDCHILD */
712  SCIP_EXPRITER* iterator /**< expression iterator */
713  )
714 {
715  assert(iterator != NULL);
716  assert(iterator->curr != NULL);
717  assert(iterator->iterindex >= 0);
718  assert(iterator->itertype == SCIP_EXPRITER_DFS);
719  assert(iterator->dfsstage == SCIP_EXPRITER_VISITINGCHILD || iterator->dfsstage == SCIP_EXPRITER_VISITEDCHILD);
720  assert(iterator->curr->iterdata[iterator->iterindex].currentchild >= 0);
721  assert(iterator->curr->iterdata[iterator->iterindex].currentchild < iterator->curr->nchildren);
722 
723  return iterator->curr->children[iterator->curr->iterdata[iterator->iterindex].currentchild];
724 }
725 
726 /** gives the parent of the current expression of an expression iteration if in DFS mode
727  *
728  * @return the expression from which the current expression has been accessed
729  */
731  SCIP_EXPRITER* iterator /**< expression iterator */
732  )
733 {
734  assert(iterator != NULL);
735  assert(iterator->curr != NULL);
736  assert(iterator->iterindex >= 0);
737  assert(iterator->itertype == SCIP_EXPRITER_DFS);
738 
739  return iterator->curr->iterdata[iterator->iterindex].parent;
740 }
741 
742 /** gives the iterator specific user data of the current expression
743  *
744  * @note The expression iterator mode must be DFS or another mode with allowrevisit=FALSE
745  */
747  SCIP_EXPRITER* iterator /**< expression iterator */
748  )
749 {
750  assert(iterator != NULL);
751  assert(iterator->curr != NULL);
752  assert(iterator->iterindex >= 0);
753 
754  return iterator->curr->iterdata[iterator->iterindex].userdata;
755 }
756 
757 /** gives the iterator specific user data of the current expressions current child
758  *
759  * @note The expression iterator mode must be in DFS mode and stage \ref SCIP_EXPRITER_VISITINGCHILD or \ref SCIP_EXPRITER_VISITEDCHILD
760  */
762  SCIP_EXPRITER* iterator /**< expression iterator */
763  )
764 {
765  assert(iterator != NULL);
766  assert(iterator->curr != NULL);
767  assert(iterator->iterindex >= 0);
768  assert(iterator->itertype == SCIP_EXPRITER_DFS);
769  assert(iterator->dfsstage == SCIP_EXPRITER_VISITINGCHILD || iterator->dfsstage == SCIP_EXPRITER_VISITEDCHILD);
770  assert(iterator->curr->iterdata[iterator->iterindex].currentchild >= 0);
771  assert(iterator->curr->iterdata[iterator->iterindex].currentchild < iterator->curr->nchildren);
772 
773  return iterator->curr->children[iterator->curr->iterdata[iterator->iterindex].currentchild]->iterdata[iterator->iterindex].userdata;
774 }
775 
776 /** gives the iterator specific user data of a given expression
777  *
778  * @note The expression iterator mode must be DFS or another mode with allowrevisit=FALSE
779  */
781  SCIP_EXPRITER* iterator, /**< expression iterator */
782  SCIP_EXPR* expr /**< expression for which to get the userdata of this iterator */
783  )
784 {
785  assert(iterator != NULL);
786  assert(expr != NULL);
787  assert(iterator->iterindex >= 0);
788 
789  return expr->iterdata[iterator->iterindex].userdata;
790 }
791 
792 /** sets the iterator specific user data of the current expression for an expression iteration if in DFS mode
793  *
794  * @note The expression iterator mode must be DFS or another mode with allowrevisit=FALSE
795  */
797  SCIP_EXPRITER* iterator, /**< expression iterator */
798  SCIP_EXPRITER_USERDATA userdata /**< data to be stored */
799  )
800 {
801  assert(iterator != NULL);
802  assert(iterator->curr != NULL);
803  assert(iterator->iterindex >= 0);
804 
805  iterator->curr->iterdata[iterator->iterindex].userdata = userdata;
806 }
807 
808 /** sets the iterator specific user data of a given expression
809  *
810  * @note The expression iterator mode must be DFS or another mode with allowrevisit=FALSE
811  */
813  SCIP_EXPRITER* iterator, /**< expression iterator */
814  SCIP_EXPR* expr, /**< expression where to set iterator data */
815  SCIP_EXPRITER_USERDATA userdata /**< data to be stored in current child */
816  )
817 {
818  assert(iterator != NULL);
819  assert(iterator->iterindex >= 0);
820 
821  expr->iterdata[iterator->iterindex].userdata = userdata;
822 }
823 
824 /** sets the iterator specific user data of the current expressions current child
825  *
826  * @note The expression iterator mode must be in DFS mode and stage \ref SCIP_EXPRITER_VISITINGCHILD or \ref SCIP_EXPRITER_VISITEDCHILD
827  */
829  SCIP_EXPRITER* iterator, /**< expression iterator */
830  SCIP_EXPRITER_USERDATA userdata /**< data to be stored in current child */
831  )
832 {
833  assert(iterator != NULL);
834  assert(iterator->curr != NULL);
835  assert(iterator->iterindex >= 0);
836  assert(iterator->itertype == SCIP_EXPRITER_DFS);
837  assert(iterator->dfsstage == SCIP_EXPRITER_VISITINGCHILD || iterator->dfsstage == SCIP_EXPRITER_VISITEDCHILD);
838  assert(iterator->curr->iterdata[iterator->iterindex].currentchild >= 0);
839  assert(iterator->curr->iterdata[iterator->iterindex].currentchild < iterator->curr->nchildren);
840 
841  iterator->curr->children[iterator->curr->iterdata[iterator->iterindex].currentchild]->iterdata[iterator->iterindex].userdata = userdata;
842 }
843 
844 /** moves the iterator to the next expression according to the mode of the expression iterator
845  *
846  * @return the next expression, if any, and NULL otherwise
847  */
849  SCIP_EXPRITER* iterator /**< expression iterator */
850  )
851 {
852  /* move to the next expression according to iterator type */
853  switch( iterator->itertype )
854  {
855  case SCIP_EXPRITER_BFS:
856  {
857  iterator->curr = doBfsNext(iterator);
858  break;
859  }
860 
862  {
863  iterator->curr = doReverseTopologicalNext(iterator);
864  if( iterator->visitedtag != 0 )
865  {
866  assert(iterator->iterindex >= 0);
867  assert(iterator->iterindex < SCIP_EXPRITER_MAXNACTIVE);
868 
869  /* skip already visited expressions */
870  while( iterator->curr != NULL )
871  {
872  if( iterator->curr->iterdata[iterator->iterindex].visitedtag == iterator->visitedtag )
873  {
874  /* if curr has already been visited, get next one
875  * TODO this isn't really efficient, since we still walk through already visited expressions
876  */
877  iterator->curr = doReverseTopologicalNext(iterator);
878  }
879  else
880  {
881  /* curr has not been visited yet, so mark it as visited and interrupt loop */
882  iterator->curr->iterdata[iterator->iterindex].visitedtag = iterator->visitedtag;
883  break;
884  }
885  }
886  }
887  break;
888  }
889 
890  case SCIP_EXPRITER_DFS :
891  {
892  assert(iterator->iterindex >= 0);
893 
894  /* get next until we are in a stopstage again
895  * this might give expressions more than once, depending on what the stopstages are
896  */
897  do
898  {
899  iterator->curr = doDfsNext(iterator);
900  }
901  while( iterator->curr != NULL && (iterator->dfsstage & iterator->stopstages) == 0 );
902 
903  break;
904  }
905  }
906 
907  return iterator->curr;
908 }
909 
910 /** moves a DFS iterator to one of the next expressions
911  *
912  * - If in \ref SCIP_EXPRITER_ENTEREXPR stage, then all children of that expression will be skipped.
913  * If \ref SCIP_EXPRITER_LEAVEEXPR is one of the `stopstages`, then it will be the next stage. Otherwise, the iterator will move further on (go to the parent, etc).
914  * - If in \ref SCIP_EXPRITER_VISITINGCHILD stage, then the child that was going to be visited next will be skipped and the iterator will be moved on to the next child (if any).
915  * - If in \ref SCIP_EXPRITER_VISITEDCHILD stage, then all remaining children will be skipped and we move on to the \ref SCIP_EXPRITER_LEAVEEXPR stage (if a stop stage, otherwise further on).
916  * - It is not allowed to call this function when in \ref SCIP_EXPRITER_LEAVEEXPR stage.
917  *
918  * @return the next expression, if any, and NULL otherwise
919  */
921  SCIP_EXPRITER* iterator /**< expression iterator */
922  )
923 {
924  assert(iterator != NULL);
925  assert(iterator->curr != NULL);
926  assert(iterator->itertype == SCIP_EXPRITER_DFS);
927  assert(iterator->iterindex >= 0);
928 
929  switch( iterator->dfsstage )
930  {
933  {
934  /* move directly to leaveexpr */
935  iterator->dfsstage = SCIP_EXPRITER_LEAVEEXPR;
936  /* if leaveexpr is not a stopstage, then move on */
937  while( iterator->curr != NULL && (iterator->dfsstage & iterator->stopstages) == 0 )
938  iterator->curr = doDfsNext(iterator);
939  return iterator->curr;
940  }
941 
943  {
944  /* skip the child to be visited */
945  /* pretend we just visited this child and get next */
947  return SCIPexpriterGetNext(iterator);
948  }
949 
951  default :
952  SCIPerrorMessage("SCIPexpriterSkipDFS called in invalid stage %u", iterator->dfsstage);
953  SCIPABORT();
954  return iterator->curr;
955  }
956 }
957 
958 /** returns whether the iterator visited all expressions already */
960  SCIP_EXPRITER* iterator /**< expression iterator */
961  )
962 {
963  assert(iterator != NULL);
964 
965  return iterator->curr == NULL;
966 }
SCIP_RETCODE SCIPexpriterInit(SCIP_EXPRITER *iterator, SCIP_EXPR *expr, SCIP_EXPRITER_TYPE type, SCIP_Bool allowrevisit)
Definition: expriter.c:491
static void deinit(SCIP_EXPRITER *iterator)
Definition: expriter.c:134
SCIP_Bool initialized
Definition: struct_expr.h:198
int SCIPexprGetNChildren(SCIP_EXPR *expr)
Definition: expr.c:3798
SCIP_EXPR * SCIPexpriterGetParentDFS(SCIP_EXPRITER *iterator)
Definition: expriter.c:730
static SCIP_EXPR * doDfsNext(SCIP_EXPRITER *iterator)
Definition: expriter.c:328
static void reverseTopologicalInsert(SCIP_EXPRITER *iterator, SCIP_EXPR *expr)
Definition: expriter.c:209
int nactiveexpriter
Definition: struct_stat.h:267
SCIP_EXPR * SCIPexpriterSkipDFS(SCIP_EXPRITER *iterator)
Definition: expriter.c:920
SCIP_RETCODE SCIPqueueInsert(SCIP_QUEUE *queue, void *elem)
Definition: misc.c:1020
structure definitions related to algebraic expressions
private functions to work with algebraic expressions
BMS_BLKMEM * blkmem
Definition: struct_expr.h:195
#define TRUE
Definition: def.h:86
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:54
SCIP_EXPRITER_TYPE
Definition: type_expr.h:687
void SCIPexpriterSetChildUserData(SCIP_EXPRITER *iterator, SCIP_EXPRITER_USERDATA userdata)
Definition: expriter.c:828
SCIP_Bool SCIPexpriterIsInit(SCIP_EXPRITER *iterator)
Definition: expriter.c:475
static SCIP_EXPR * doBfsNext(SCIP_EXPRITER *iterator)
Definition: expriter.c:277
SCIP_EXPRITER_USERDATA SCIPexpriterGetChildUserDataDFS(SCIP_EXPRITER *iterator)
Definition: expriter.c:761
static SCIP_RETCODE ensureStackSize(SCIP_EXPRITER *iterator, int size)
Definition: expriter.c:185
SCIP_Bool SCIPqueueIsEmpty(SCIP_QUEUE *queue)
Definition: misc.c:1175
SCIP_EXPRITER_USERDATA SCIPexpriterGetCurrentUserData(SCIP_EXPRITER *iterator)
Definition: expriter.c:746
#define SCIP_EXPRITER_ENTEREXPR
Definition: type_expr.h:667
#define SCIP_EXPRITER_VISITEDCHILD
Definition: type_expr.h:669
SCIP_EXPR * SCIPexpriterGetCurrent(SCIP_EXPRITER *iterator)
Definition: expriter.c:673
int nchildren
Definition: struct_expr.h:100
void SCIPqueueClear(SCIP_QUEUE *queue)
Definition: misc.c:969
SCIP_EXPRITER_USERDATA SCIPexpriterGetExprUserData(SCIP_EXPRITER *iterator, SCIP_EXPR *expr)
Definition: expriter.c:780
SCIP_EXPR ** SCIPexprGetChildren(SCIP_EXPR *expr)
Definition: expr.c:3808
void SCIPexpriterFree(SCIP_EXPRITER **iterator)
Definition: expriter.c:436
int * dfsnvisited
Definition: struct_expr.h:206
#define storeBacktrace(subscipdepth, iterpos)
Definition: expriter.c:120
#define SCIPerrorMessage
Definition: pub_message.h:55
SCIP_Longint visitedtag
Definition: struct_expr.h:202
#define NULL
Definition: lpi_spx1.cpp:155
#define SCIP_CALL(x)
Definition: def.h:384
int SCIPexpriterGetChildIdxDFS(SCIP_EXPRITER *iterator)
Definition: expriter.c:697
struct SCIP_ExprIterData SCIP_EXPRITERDATA
Definition: type_expr.h:694
SCIP_EXPRITER_TYPE itertype
Definition: struct_expr.h:199
void SCIPqueueFree(SCIP_QUEUE **queue)
Definition: misc.c:958
SCIP_EXPR ** dfsexprs
Definition: struct_expr.h:205
#define BMSfreeBlockMemory(mem, ptr)
Definition: memory.h:458
public data structures and miscellaneous methods
#define SCIP_Bool
Definition: def.h:84
SCIP_EXPR * SCIPexpriterRestartDFS(SCIP_EXPRITER *iterator, SCIP_EXPR *expr)
Definition: expriter.c:620
SCIP_RETCODE SCIPexpriterCreate(SCIP_STAT *stat, BMS_BLKMEM *blkmem, SCIP_EXPRITER **iterator)
Definition: expriter.c:417
static void printBacktraces(int subscipdepth)
Definition: expriter.c:124
void SCIPexpriterSetExprUserData(SCIP_EXPRITER *iterator, SCIP_EXPR *expr, SCIP_EXPRITER_USERDATA userdata)
Definition: expriter.c:812
SCIP_QUEUE * queue
Definition: struct_expr.h:211
#define BMSfreeBlockMemoryArray(mem, ptr, num)
Definition: memory.h:460
SCIP_EXPRITER_STAGE dfsstage
Definition: struct_expr.h:214
SCIP_EXPR ** children
Definition: struct_expr.h:102
SCIP_EXPR * curr
Definition: struct_expr.h:200
SCIP_EXPR * SCIPexpriterGetNext(SCIP_EXPRITER *iterator)
Definition: expriter.c:848
SCIP_EXPR * SCIPexpriterGetChildExprDFS(SCIP_EXPRITER *iterator)
Definition: expriter.c:711
datastructures for problem statistics
void SCIPexpriterSetStagesDFS(SCIP_EXPRITER *iterator, SCIP_EXPRITER_STAGE stopstages)
Definition: expriter.c:654
#define SCIP_EXPRITER_MAXNACTIVE
Definition: type_expr.h:664
SCIP_RETCODE SCIPqueueCreate(SCIP_QUEUE **queue, int initsize, SCIP_Real sizefac)
Definition: misc.c:934
#define MINDFSSIZE
Definition: expriter.c:35
SCIP_EXPRITER_STAGE SCIPexpriterGetStageDFS(SCIP_EXPRITER *iterator)
Definition: expriter.c:686
void SCIPexpriterSetCurrentUserData(SCIP_EXPRITER *iterator, SCIP_EXPRITER_USERDATA userdata)
Definition: expriter.c:796
static SCIP_EXPR * doReverseTopologicalNext(SCIP_EXPRITER *iterator)
Definition: expriter.c:225
SCIP_STAT * stat
Definition: struct_expr.h:196
SCIP_Longint exprlastvisitedtag
Definition: struct_stat.h:117
void * SCIPqueueRemove(SCIP_QUEUE *queue)
Definition: misc.c:1071
unsigned int stopstages
Definition: struct_expr.h:215
#define SCIP_EXPRITER_LEAVEEXPR
Definition: type_expr.h:670
unsigned int SCIP_EXPRITER_STAGE
Definition: type_expr.h:674
#define SCIP_EXPRITER_VISITINGCHILD
Definition: type_expr.h:668
#define MINBFSSIZE
Definition: expriter.c:36
SCIP_Bool SCIPexpriterIsEnd(SCIP_EXPRITER *iterator)
Definition: expriter.c:959
struct BMS_BlkMem BMS_BLKMEM
Definition: memory.h:430
#define SCIP_CALL_ABORT(x)
Definition: def.h:363
SCIP_EXPRITERDATA iterdata[SCIP_EXPRITER_MAXNACTIVE]
Definition: struct_expr.h:105
#define SCIP_ALLOC(x)
Definition: def.h:395
#define BMSallocClearBlockMemory(mem, ptr)
Definition: memory.h:445
#define SCIPABORT()
Definition: def.h:356
#define BMSreallocBlockMemoryArray(mem, ptr, oldnum, newnum)
Definition: memory.h:451
int subscipdepth
Definition: struct_stat.h:208