Scippy

SCIP

Solving Constraint Integer Programs

dpborder_core.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 dpborder_core.c
17  * @brief Core of dynamic programming solver for Steiner tree (sub-) problems with small border
18  * @author Daniel Rehfeldt
19  *
20  * Contains core methods.
21  *
22  */
23 
24 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
25 
26 //#define SCIP_DEBUG
27 #include "dpborder.h"
28 #include "dpborderinterns.h"
29 #include "stpvector.h"
30 #include "misc_stp.h"
31 
32 #define DPB_ORDERMULT_PREVS 2
33 #define DPB_ORDERMULT_TERM 5
34 #define DPB_ORDERMULT_OUTDEG 1
35 #define DPB_ORDERMULT_OUTDELTA 1
36 
37 #define DPB_ORDER_MAXNROOTS 100
38 
39 
40 /*
41  * Local methods
42  */
43 
44 #ifdef SCIP_DEBUG
45 /** prints border nodes */
46 static
47 void printBorder(
48  const GRAPH* graph, /**< graph */
49  int iteration, /**< iteration number */
50  const DPBORDER* dpborder /**< border */
51 )
52 {
53  const DPBLEVEL* const toplevel = dpborder->borderlevels[iteration];
54  const int nbordernodes = toplevel->nbordernodes;
55 
56  printf("---PRINTING BORDER: \n");
57  printf("extnode=%d, nbordernodes=%d \n", toplevel->extnode, nbordernodes);
58  printf("bordernodes: \n");
59 
60  for( int i = 0; i < StpVecGetSize(dpborder->bordernodes); i++ )
61  {
62  const int node = dpborder->bordernodes[i];
63  assert(dpborder->nodes_isBorder[node]);
64 
65  printf("char=%d node=%d \n", i, node);
66 
67  }
68 
69  printf("prev-bordernodes: \n");
70 
71  for( int i = 0; i < StpVecGetSize(dpborder->prevbordernodes); i++ )
72  {
73  const int node = dpborder->prevbordernodes[i];
74  assert(!dpborder->nodes_isBorder[node] || node == toplevel->extnode);
75 
76  graph_knot_printInfo(graph, node);
77  }
78 
79 }
80 #endif
81 
82 
83 /** does reallocation of global array if necessary */
84 static inline
86  SCIP* scip, /**< SCIP data structure */
87  int newadds, /**< number of additions */
88  DPBORDER* dpborder /**< border */
89  )
90 {
91  const int size = dpborder->global_partstarts[dpborder->global_npartitions];
92  assert(size >= 0);
93  assert(newadds > 0);
94 
95  if( newadds + size > dpborder->global_partcap )
96  {
97  while( newadds + size > dpborder->global_partcap )
99 
100  SCIPdebugMessage("reallocating memory (to %d) \n", dpborder->global_partcap);
101  SCIP_CALL( SCIPreallocMemoryArray(scip, &(dpborder->global_partitions), dpborder->global_partcap) );
102 
103  hashmap_updateKeyarr(dpborder->global_partitions, &dpborder->hashmap);
104  }
105 
106  return SCIP_OKAY;
107 }
108 
109 
110 /** gets partition range */
111 static inline
113  const DPBORDER* dpborder, /**< border */
114  int globalposition, /**< position of partition */
115  int* start, /**< pointer to range start (OUT) */
116  int* end /**< pointer to range end (OUT) */
117  )
118 {
119  const int* const starts = dpborder->global_partstarts;
120  assert(globalposition >= 0);
121  assert(globalposition < dpborder->global_npartitions);
122 
123  *start = starts[globalposition];
124  *end = starts[globalposition + 1];
125 
126  assert(*start < *end);
127 }
128 
129 
130 
131 /** builds map between old and new border char representation */
132 static
134  int iteration, /**< iteration number */
135  DPBORDER* dpborder /**< border */
136 )
137 {
138  const int extnode = dpborder_getTopLevel(dpborder)->extnode;
139  const SCIP_Bool* const nodes_isBorder = dpborder->nodes_isBorder;
140  int* RESTRICT bordercharmap = dpborder->bordercharmap;
141  int nbordernew = 0;
142 
143  for( int i = 0; i < StpVecGetSize(dpborder->bordernodes); i++ )
144  {
145  const int bordernode = dpborder->bordernodes[i];
146 
147  if( nodes_isBorder[bordernode] )
148  bordercharmap[i] = nbordernew++;
149  else
150  bordercharmap[i] = -1;
151  }
152 
153  if( dpborder->nodes_outdeg[extnode] != 0 || (iteration == dpborder->nnodes - 1) )
154  {
155  nbordernew++;
156  }
157 
158  /* now we set the delimiter */
159  bordercharmap[StpVecGetSize(dpborder->bordernodes)] = nbordernew;
160 
161 #ifdef SCIP_DEBUG
162  SCIPdebugMessage("char border map, old to new: \n");
163  for( int i = 0; i < StpVecGetSize(dpborder->bordernodes); i++ )
164  {
165  SCIPdebugMessage("%d->%d \n", i, bordercharmap[i]);
166  }
167  SCIPdebugMessage("delimiter: %d->%d \n", StpVecGetSize(dpborder->bordernodes),
168  bordercharmap[StpVecGetSize(dpborder->bordernodes)]);
169 
170 #endif
171 }
172 
173 /** builds distances to extension node */
174 static
176  const GRAPH* graph, /**< graph */
177  DPBORDER* dpborder /**< border */
178 )
179 {
180  SCIP_Real* RESTRICT borderchardists = dpborder->borderchardists;
181  const SCIP_Bool* const nodes_isBorder = dpborder->nodes_isBorder;
182  const int* const bordernodes = dpborder->bordernodes;
183  const CSR* const csr = graph->csr_storage;
184  const int* const start_csr = csr->start;
185  const int extnode = dpborder_getTopLevel(dpborder)->extnode;
186  const int nbordernodes = StpVecGetSize(bordernodes);
187 
188  SCIPdebugMessage("setting up border distances for extnode=%d \n", extnode);
189 
190  for( int i = 0; i < nbordernodes; i++ )
191  borderchardists[i] = FARAWAY;
192 
193 #ifndef NDEBUG
194  for( int i = nbordernodes; i < BPBORDER_MAXBORDERSIZE; i++ )
195  borderchardists[i] = -BLOCKED;
196 #endif
197 
198  for( int e = start_csr[extnode]; e != start_csr[extnode + 1]; e++ )
199  {
200  const int head = csr->head[e];
201  if( nodes_isBorder[head] )
202  {
203  int i;
204  for( i = 0; i < BPBORDER_MAXBORDERSIZE; i++ )
205  {
206  const int bordernode = bordernodes[i];
207  assert(bordernode != extnode);
208 
209  if( head == bordernode )
210  {
211  SCIPdebugMessage("setting edge distance for border node %d to %f \n", head, csr->cost[e]);
212  assert(EQ(borderchardists[i], FARAWAY));
213  borderchardists[i] = csr->cost[e];
214  break;
215  }
216  }
217  assert(i != BPBORDER_MAXBORDERSIZE);
218  }
219  }
220 }
221 
222 /** adapts border */
223 static
225  SCIP* scip, /**< SCIP data structure */
226  const GRAPH* graph, /**< graph */
227  int iteration, /**< iteration number */
228  DPBORDER* dpborder /**< border */
229 )
230 {
231  DPBLEVEL* const toplevel = dpborder->borderlevels[iteration];
232  SCIP_Bool* const nodes_isBorder = dpborder->nodes_isBorder;
233  int* const nodes_outdegree = dpborder->nodes_outdeg;
234  const CSR* const csr = graph->csr_storage;
235  const int* const head_csr = csr->head;
236  const int* const start_csr = csr->start;
237  const int extnode = toplevel->extnode;
238  int nbordernodes = 0;
239 
240  assert(iteration >= 1);
241  assert(!nodes_isBorder[extnode]);
242  assert(dpborder->borderlevels[iteration - 1]->nbordernodes == StpVecGetSize(dpborder->bordernodes));
243 
244  /* NOTE: needs to be called before border is updated! */
245  borderBuildCharDists(graph, dpborder);
246 
247  if( dpborder->prevbordernodes )
248  StpVecClear(dpborder->prevbordernodes);
249 
250  for( int e = start_csr[extnode]; e != start_csr[extnode + 1]; e++ )
251  {
252  const int head = head_csr[e];
253  if( nodes_isBorder[head] )
254  {
255  nodes_outdegree[extnode]--;
256  nodes_outdegree[head]--;
257  assert(nodes_outdegree[extnode] >= 0);
258  assert(nodes_outdegree[head] >= 0);
259 
260  if( nodes_outdegree[head] == 0 )
261  {
262  StpVecPushBack(scip, dpborder->prevbordernodes, head);
263  nodes_isBorder[head] = FALSE;
264  }
265  }
266  }
267 
268  if( nodes_outdegree[extnode] == 0 )
269  StpVecPushBack(scip, dpborder->prevbordernodes, extnode);
270 
271  for( int i = 0; i < StpVecGetSize(dpborder->bordernodes); i++ )
272  {
273  const int bordernode = dpborder->bordernodes[i];
274  assert(graph_knot_isInRange(graph, bordernode));
275 
276  /* NOTE: might happen for previous border node */
277  if( nodes_isBorder[bordernode] && nodes_outdegree[bordernode] == 0 )
278  nodes_isBorder[bordernode] = FALSE;
279  }
280 
281 #ifdef SCIP_DEBUG
282  printf("iter=%d bordersize=%d\n", iteration, StpVecGetSize(dpborder->bordernodes));
283  printf("global_npartitions=%d \n", dpborder->global_npartitions);
284 #endif
285 
286  borderBuildCharMap(iteration, dpborder);
287  assert(!toplevel->bordernodesMapToOrg);
288 
289  /* remove outdated border nodes */
290  for( int i = 0; i < StpVecGetSize(dpborder->bordernodes); i++ )
291  {
292  const int bordernode = dpborder->bordernodes[i];
293  assert(graph_knot_isInRange(graph, bordernode));
294 
295  if( nodes_isBorder[bordernode] )
296  {
297  dpborder->bordernodes[nbordernodes++] = dpborder->bordernodes[i];
298  StpVecPushBack(scip, toplevel->bordernodesMapToOrg, bordernode);
299  }
300  }
301 
302  for( int i = StpVecGetSize(dpborder->bordernodes) - nbordernodes; i > 0; i-- )
303  StpVecPopBack(dpborder->bordernodes);
304 
305  if( (nodes_outdegree[extnode] != 0) || (iteration == dpborder->nnodes - 1) )
306  {
307  dpborder->extborderchar = nbordernodes;
308  nbordernodes++;
309  StpVecPushBack(scip, dpborder->bordernodes, extnode);
310  StpVecPushBack(scip, toplevel->bordernodesMapToOrg, extnode);
311  nodes_isBorder[extnode] = TRUE;
312  }
313  else
314  {
315  dpborder->extborderchar = -1;
316  }
317 
318  toplevel->nbordernodes = nbordernodes;
319  assert(toplevel->nbordernodes == StpVecGetSize(dpborder->bordernodes));
320 }
321 
322 
323 /** updates partition from given partition */
324 static
326  SCIP* scip, /**< SCIP data structure */
327  int globalposition, /**< position of partition */
328  const GRAPH* graph, /**< graph */
329  DPBORDER* dpborder /**< border */
330 )
331 {
332  DPBPART partition;
333  int* subbuffer;
334  STP_Vectype(int) candstarts;
335  DPBLEVEL* const toplevel = dpborder_getTopLevel(dpborder);
337  int part_start;
338  int part_end;
339  int ncands;
340  uint32_t powsize;
341  const SCIP_Real part_cost = dpborder->global_partcosts[globalposition];
342  const SCIP_Bool allTermsAreVisited = (dpborder->nterms == dpborder->ntermsvisited);
343  const int delimiter_new = dpborder_getTopDelimiter(dpborder);
344 
345  partitionGetRangeGlobal(dpborder, globalposition, &part_start, &part_end);
346  partition.partchars = &(global_partitions[part_start]);
347  partition.partsize = (part_end - part_start);
348  partition.delimiter = dpborder_getDelimiter(dpborder, StpVecGetSize(dpborder->borderlevels) - 2);
349 
350  candstarts = dpborder_partGetCandstarts(scip, &partition, dpborder);
351  ncands = StpVecGetSize(candstarts);
352  assert(ncands >= 0);
353  powsize = (uint32_t) 1 << (uint32_t) ncands;
354  assert(powsize == (uint32_t) pow(2.0, ncands));
355 
357 
358  /* make sure that partition storage is large enough */
359  SCIP_CALL( partitionTryRealloc(scip, (powsize + 2) * BPBORDER_MAXBORDERSIZE * 2, dpborder) );
360  global_partitions = dpborder->global_partitions;
361  partition.partchars = &(global_partitions[part_start]);
362 
363 #ifdef SCIP_DEBUG
364  SCIPdebugMessage("partition ncands=%d, isTerm=%d ...base partition: \n", ncands, toplevel->exnodeIsTerm);
365  dpborder_partPrint(&partition);
366 #endif
367 
368  if( !toplevel->exnodeIsTerm )
369  {
370  /* try to add/update the partition that does not include the extension node */
371  const int globalposition_new = dpborder_partGetIdxNewExclusive(scip, &partition, dpborder);
372  if( globalposition_new != -1 && LT(part_cost, dpborder->global_partcosts[globalposition_new]) )
373  {
374  SCIPdebugMessage("...added partition at %d with cost=%f \n", globalposition_new, part_cost);
375  dpborder->global_partcosts[globalposition_new] = part_cost;
376  dpborder->global_predparts[globalposition_new] = globalposition;
377  dpborder->global_partsUseExt[globalposition_new] = FALSE;
378  }
379  }
380 
381  /* loop over all subsets (also the empty set) */
382  for( uint32_t counter = powsize; counter >= 1; counter-- )
383  {
384  int nsub = 0;
385  int globalposition_new;
386  SCIP_Real cost_new;
387  const uint32_t mask = counter - 1;
388 
389  SCIPdebugMessage("new partition: \n");
390  for( uint32_t j = 0; j < (uint32_t) ncands; j++ )
391  {
392  if( mask & ((uint32_t) 1 << j) )
393  {
394  assert(nsub < BPBORDER_MAXBORDERSIZE);
395  subbuffer[nsub++] = candstarts[j];
396  SCIPdebugMessage("...%d \n", candstarts[j]);
397  }
398  }
399 
400  globalposition_new = dpborder_partGetIdxNew(scip, &partition, subbuffer, nsub, dpborder);
401 
402  /* non-valid partition? */
403  if( globalposition_new == -1 )
404  {
405  SCIPdebugMessage("partition is invalid... \n");
406  continue;
407  }
408 
409  assert(globalposition_new >= 0);
410  cost_new = dpborder_partGetConnectionCost(dpborder, &partition, subbuffer, nsub);
411  SCIPdebugMessage("connection cost: %f \n", cost_new);
412 
413  cost_new += part_cost;
414 
415  if( GT(dpborder->global_partcosts[globalposition_new], cost_new) )
416  {
417  assert(LT(cost_new, FARAWAY));
418  SCIPdebugMessage("...added partition at %d with cost=%f \n", globalposition_new, cost_new);
419  dpborder->global_partcosts[globalposition_new] = cost_new;
420  dpborder->global_partsUseExt[globalposition_new] = TRUE;
421  dpborder->global_predparts[globalposition_new] = globalposition;
422 
423  if( allTermsAreVisited )
424  {
425  if( 1 == dpborder_partglobalGetCard(globalposition_new, delimiter_new, dpborder) )
426  {
427  if( LT(cost_new, dpborder->global_obj) )
428  {
429  dpborder->global_obj = cost_new;
430  dpborder->global_optposition = globalposition_new;
431  SCIPdebugMessage("updated global obj to %f \n", dpborder->global_obj);
432  }
433  }
434  }
435  }
436  }
437 
438  SCIPfreeBufferArray(scip, &subbuffer);
439  StpVecFree(scip, candstarts);
440 
441  return SCIP_OKAY;
442 }
443 
444 
445 /** adds partitions for new border */
446 static
448  SCIP* scip, /**< SCIP data structure */
449  const GRAPH* graph, /**< graph */
450  int iteration, /**< iteration number */
451  DPBORDER* dpborder /**< border */
452 )
453 {
454  DPBLEVEL* const toplevel = dpborder->borderlevels[iteration];
455  DPBLEVEL* const prevlevel = dpborder->borderlevels[iteration - 1];
456  const int global_start = prevlevel->globalstartidx;
457  const int global_end = toplevel->globalstartidx;
458 
459  SCIPdebugMessage("adding partitions: \n");
460 
461  assert(iteration >= 1);
462  assert(global_start < global_end);
463 
464  /* loop over all valid partitions of previous border */
465  for( int i = global_start; i != global_end; i++ )
466  {
467  SCIP_CALL( updateFromPartition(scip, i, graph, dpborder) );
468  }
469 
470  return SCIP_OKAY;
471 }
472 
473 
474 /** adds border level */
475 static
477  SCIP* scip, /**< SCIP data structure */
478  const GRAPH* graph, /**< graph */
479  int iteration, /**< iteration number */
480  DPBORDER* dpborder /**< border */
481 )
482 {
483  DPBLEVEL* level;
484  const DPBSEQUENCE* const dpbsequence = dpborder->dpbsequence;
485  const int* const nodessequence = dpbsequence->nodessquence;
486  const int node = nodessequence[iteration];
487 
488  assert(graph_knot_isInRange(graph, node));
489 
490 #ifdef SCIP_DEBUG
491  printf("\n----- Starting level %d ----- \n", iteration);
492 #endif
493 
494  if( iteration > 1 )
495  {
496  // todo extra method
497  DPBHASHMAP* hashmap = &(dpborder->hashmap);
498  const STP_Vectype(int) global_partstarts = dpborder->global_partstarts;
499  const int levelstart = dpborder_getTopLevel(dpborder)->globalstartidx;
500  const int levelend = dpborder->global_npartitions;
501 
502  assert(levelstart < levelend);
503 
504  for( int i = levelstart; i != levelend; i++ )
505  {
506  const int partstart = global_partstarts[i];
507  const int partend = global_partstarts[i + 1];
508 
509  assert(partstart < partend);
510 
511 #ifdef NDEBUG
512  (void) hashmap_remove(hashmap, partstart, partend - partstart);
513 #else
514  {
515  int ret = hashmap_remove(hashmap, partstart, partend - partstart);
516  assert(ret == 0);
517  }
518 #endif
519  }
520 
521  assert(hashmap_isEmpty(&dpborder->hashmap));
522  }
523 
524  SCIP_CALL( dpborder_dpblevelInit(scip, &level) );
525  StpVecPushBack(scip, dpborder->borderlevels, level);
526 
527  level->extnode = node;
528  level->exnodeIsTerm = Is_term(graph->term[node]);
529  level->globalstartidx = dpborder->global_npartitions;
530 
531  if( level->exnodeIsTerm )
532  dpborder->ntermsvisited++;
533 
534  updateBorder(scip, graph, iteration, dpborder);
535 
536 
537 #ifdef SCIP_DEBUG
538  printBorder(graph, iteration, dpborder);
539 #endif
540 
541  return SCIP_OKAY;
542 }
543 
544 
545 /** adds first border level */
546 static
548  SCIP* scip, /**< SCIP data structure */
549  const GRAPH* graph, /**< graph */
550  DPBORDER* dpborder /**< border */
551 )
552 {
553  DPBLEVEL* level;
554  const DPBSEQUENCE* const dpbsequence = dpborder->dpbsequence;
555  const int* const nodessequence = dpbsequence->nodessquence;
556  const int root = nodessequence[0];
557 
558  assert(Is_term(graph->term[root]));
559  assert(!dpborder->nodes_isBorder[root]);
560 
561  SCIPdebugMessage("adding initial level for DP-root=%d \n", root);
562 
563  dpborder->nodes_isBorder[root] = TRUE;
564  StpVecPushBack(scip, dpborder->bordernodes, root);
565  StpVecPushBack(scip, dpborder->global_partstarts, 0);
566  dpborder->ntermsvisited = 1;
567 
568  SCIP_CALL( dpborder_dpblevelInit(scip, &level) );
569  StpVecPushBack(scip, dpborder->borderlevels, level);
570 
571  level->extnode = root;
572  level->exnodeIsTerm = TRUE;
573  level->nbordernodes = 1;
574  level->globalstartidx = 0;
575  StpVecPushBack(scip, level->bordernodesMapToOrg, root);
576 
577  dpborder->global_partitions[0] = 0;
578  StpVecPushBack(scip, dpborder->global_partstarts, 1);
579  StpVecPushBack(scip, dpborder->global_partcosts, 0.0);
580  StpVecPushBack(scip, dpborder->global_predparts, 0);
581  StpVecPushBack(scip, dpborder->global_partsUseExt, TRUE);
582  dpborder->global_npartitions = 1;
583 
584  assert(StpVecGetSize(dpborder->bordernodes) == 1);
585 
586  return SCIP_OKAY;
587 }
588 
589 
590 /** initializes for solve */
591 static
593  SCIP* scip, /**< SCIP data structure */
594  const GRAPH* graph, /**< graph */
595  DPBORDER* dpborder /**< border */
596 )
597 {
598  const DPBSEQUENCE* const dpbsequence = dpborder->dpbsequence;
599  const uint64_t maxnpartitions = dpbsequence->maxnpartitions;
600 
601  assert(dpborder->nterms == graph->terms && dpborder->ntermsvisited == 0);
602  assert(!dpborder->bordernodes);
603 
604  if( maxnpartitions > BPBORDER_MAXNPARTITIONS || maxnpartitions > INT_MAX )
605  {
606  SCIPerrorMessage("too many partitions! \n");
607  return SCIP_ERROR;
608  }
609 
610  dpborder->global_partcap = MAX(DPBORDER_GROWTH_FACTOR * maxnpartitions, BPBORDER_MAXBORDERSIZE);
611  SCIP_CALL( SCIPallocMemoryArray(scip, &(dpborder->global_partitions), dpborder->global_partcap) );
612 
613  hashmap_updateKeyarr(dpborder->global_partitions, &dpborder->hashmap);
614 
615  SCIP_CALL( addLevelFirst(scip, graph, dpborder) );
616 
617  return SCIP_OKAY;
618 }
619 
620 // #define DPB_ORDERING_BFS
621 #ifdef DPB_ORDERING_BFS
622 /** computes node ordering and updates if better */
623 static
625  SCIP* scip, /**< SCIP data structure */
626  const GRAPH* graph, /**< graph */
627  int root, /**< node to start from */
628  DPBSEQUENCE* dpbsequence /**< sequence */
629 )
630 {
631  SCIP_Bool* RESTRICT nodes_isVisited;
632  int* RESTRICT nodessquence = dpbsequence->nodessquence;
633  const CSR* const csr = graph->csr_storage;
634  const int* const head_csr = csr->head;
635  const int* const start_csr = csr->start;
636  const int nnodes = graph_get_nNodes(graph);
637  int nvisited;
638  int nscanned;
639 
640  assert(graph_knot_isInRange(graph, root));
641  assert(Is_term(graph->term[root]));
642 
643  SCIP_CALL( SCIPallocClearBufferArray(scip, &nodes_isVisited, nnodes) );
644  assert(!nodes_isVisited[root]);
645 
646  nvisited = 1;
647  nscanned = 0;
648  nodessquence[0] = root;
649  nodes_isVisited[root] = TRUE;
650 
651  while( nvisited < nnodes )
652  {
653  const int node = nodessquence[nscanned++];
654  assert(nscanned <= nvisited);
655 
656  for( int e = start_csr[node]; e != start_csr[node + 1]; e++ )
657  {
658  const int head = head_csr[e];
659  if( !nodes_isVisited[head] )
660  {
661  nodes_isVisited[head] = TRUE;
662  nodessquence[nvisited++] = head;
663  }
664  }
665  }
666 
667  SCIPfreeBufferArray(scip, &nodes_isVisited);
668 
669  return SCIP_OKAY;
670 }
671 #else
672 /** computes node ordering and updates if better */
673 static
675  SCIP* scip, /**< SCIP data structure */
676  const GRAPH* graph, /**< graph */
677  int root, /**< node to start from */
678  DPBSEQUENCE* dpbsequence /**< sequence */
679 )
680 {
681  STP_Vectype(int) frontier = NULL;
682  SCIP_Bool* RESTRICT nodes_isVisited;
683  SCIP_Bool* RESTRICT nodes_isFrontier;
684  int* RESTRICT nodessquence = dpbsequence->nodessquence;
685  const CSR* const csr = graph->csr_storage;
686  const int* const head_csr = csr->head;
687  const int* const start_csr = csr->start;
688  int* RESTRICT nodes_outdegree;
689  const int* const nodes_degree = graph->grad;
690  const int nnodes = graph_get_nNodes(graph);
691  int bordersize;
692  int bordertermsize;
693 
694  assert(graph_knot_isInRange(graph, root));
695  assert(Is_term(graph->term[root]));
696 
697  StpVecReserve(scip, frontier, nnodes);
698  SCIP_CALL( SCIPallocClearBufferArray(scip, &nodes_isVisited, nnodes) );
699  SCIP_CALL( SCIPallocClearBufferArray(scip, &nodes_isFrontier, nnodes) );
700  SCIP_CALL( SCIPallocBufferArray(scip, &nodes_outdegree, nnodes) );
701 
702  BMScopyMemoryArray(nodes_outdegree, nodes_degree, nnodes);
703 
704  dpbsequence->maxbordersize = 0;
705  dpbsequence->maxnpartitions = 0;
706  nodessquence[0] = root;
707  nodes_isVisited[root] = TRUE;
708  bordersize = 1;
709  bordertermsize = 1;
710 
711  for( int e = start_csr[root]; e != start_csr[root + 1]; e++ )
712  {
713  const int head = head_csr[e];
714  nodes_outdegree[head]--;
715 
716  StpVecPushBack(scip, frontier, head);
717  nodes_isFrontier[head] = TRUE;
718  }
719 
720  for( int s = 1; s < nnodes; s++ )
721  {
722  int priority_best = -nnodes * DPB_ORDERMULT_OUTDELTA;
723  int node_best = -1;
724  const int frontier_size = StpVecGetSize(frontier);
725 
726  assert(frontier_size > 0);
727 
728  for( int i = 0; i < frontier_size; i++ )
729  {
730  const int fnode = frontier[i];
731  int priority_new = 0;
732  int nprevs = 0;
733  const int outdegree = nodes_outdegree[fnode];
734  assert(!nodes_isVisited[fnode] && nodes_isFrontier[fnode]);
735 
736  /* count vertices that would be removed from border */
737  for( int e = start_csr[fnode]; e != start_csr[fnode + 1]; e++ )
738  {
739  const int head = head_csr[e];
740  assert(nodes_outdegree[head] >= 1);
741 
742  if( !nodes_isVisited[head] )
743  continue;
744 
745  if( nodes_outdegree[head] == 1 )
746  nprevs++;
747  }
748  assert(outdegree >= 0 && nodes_degree[fnode] >= outdegree);
749  SCIPdebugMessage("(old) frontier node %d: outdegree=%d outdelta=%d nprevs=%d \n",
750  fnode, outdegree, outdegree - nprevs, nprevs);
751 
752  priority_new += DPB_ORDERMULT_PREVS * nprevs;
753 
754  if( Is_term(graph->term[fnode]) )
755  priority_new += DPB_ORDERMULT_TERM * 1;
756 
757  /* number of visited nodes in adjacency list of fnode */
758  priority_new += DPB_ORDERMULT_OUTDEG * (nodes_degree[fnode] - outdegree);
759 
760  /* (negative) delta of number of edges going out of visited region */
761  priority_new += DPB_ORDERMULT_OUTDELTA * (nprevs - outdegree);
762 
763  if( priority_new > priority_best )
764  {
765  node_best = fnode;
766  priority_best = priority_new;
767  }
768  }
769  assert(node_best >= 0);
770 
771  /* update frontier */
772  for( int e = start_csr[node_best]; e != start_csr[node_best + 1]; e++ )
773  {
774  const int head = head_csr[e];
775  nodes_outdegree[head]--;
776  assert(nodes_outdegree[head] >= 0);
777 
778  if( nodes_isVisited[head] )
779  {
780  if( nodes_outdegree[head] == 0 )
781  {
782  if( Is_term(graph->term[head]) )
783  bordertermsize--;
784  bordersize--;
785  }
786  }
787  else if( !nodes_isFrontier[head] )
788  {
789  nodes_isFrontier[head] = TRUE;
790  StpVecPushBack(scip, frontier, head);
791  }
792  }
793  nodes_isFrontier[node_best] = FALSE;
794  nodes_isVisited[node_best] = TRUE;
795  nodessquence[s] = node_best;
796 
797  assert(StpVecGetSize(frontier) > 0);
798  {
799  int i;
800  for( i = 0; i < StpVecGetSize(frontier); i++ )
801  {
802  if( frontier[i] == node_best )
803  break;
804  }
805  assert(i < StpVecGetSize(frontier));
806  SWAP_INTS(frontier[i], frontier[StpVecGetSize(frontier) - 1]);
807  StpVecPopBack(frontier);
808  }
809 
810  if( nodes_outdegree[node_best] != 0 )
811  {
812  if( Is_term(graph->term[node_best]) )
813  bordertermsize++;
814  bordersize++;
815  }
816 
817  assert(bordersize >= bordertermsize);
818  dpbsequence->maxnpartitions += bordersize * bordersize * (bordersize - bordertermsize);
819 
820  SCIPdebugMessage("ADDED node %d to border \n", node_best);
821  SCIPdebugMessage("new size of border: %d (termsize=%d) \n", bordersize, bordertermsize);
822  SCIPdebugMessage("new size of frontier: %d \n", StpVecGetSize(frontier));
823  SCIPdebugMessage("new total number of partitions: %ld \n", dpbsequence->maxnpartitions);
824 
825  if( bordersize > dpbsequence->maxbordersize )
826  {
827  dpbsequence->maxbordersize = bordersize;
828  if( bordersize >= BPBORDER_MAXBORDERSIZE )
829  {
830  SCIPdebugMessage("aborting early, border too large! \n");
831  nodessquence[0] = -1;
832  break;
833  }
834  }
835 
836  if( dpbsequence->maxnpartitions >= BPBORDER_MAXNPARTITIONS )
837  {
838  SCIPdebugMessage("aborting early, too many partitions! \n");
839  nodessquence[0] = -1;
840  break;
841  }
842  }
843 
844  StpVecFree(scip, frontier);
845  SCIPfreeBufferArray(scip, &nodes_outdegree);
846  SCIPfreeBufferArray(scip, &nodes_isFrontier);
847  SCIPfreeBufferArray(scip, &nodes_isVisited);
848 
849  return SCIP_OKAY;
850 }
851 #endif
852 
853 
854 /*
855  * Interface methods
856  */
857 
858 
859 // compute ordering
860 
861 
862 /** computes node ordering */
864  SCIP* scip, /**< SCIP data structure */
865  const GRAPH* graph, /**< graph */
866  DPBORDER* dpborder /**< border */
867 )
868 {
869  SCIP_CALL( computeOrderingFromNode(scip, graph, graph->source, dpborder->dpbsequence) );
870 
871  return SCIP_OKAY;
872 }
873 
874 
875 /** updates given ordering */
877  SCIP* scip, /**< SCIP data structure */
878  const GRAPH* graph, /**< graph */
879  DPBORDER* dpborder /**< border */
880 )
881 {
882  DPBSEQUENCE* const sequence_base = dpborder->dpbsequence;
883  DPBSEQUENCE* sequence_tmp;
884  int* terms;
885  const int nterms = graph->terms;
886  const int root_org = sequence_base->nodessquence[0];
887 
888  assert(nterms > 1);
889  assert(graph_knot_isInRange(graph, root_org));
890  assert(Is_term(graph->term[root_org]));
891 
892  SCIP_CALL( dpborder_dpbsequenceInit(scip, graph, &sequence_tmp) );
893  SCIP_CALL( SCIPallocMemoryArray(scip, &terms, nterms) );
894  SCIP_CALL( graph_getTermsRandom(scip, graph, terms) );
895 
896  for( int i = 0; i < MIN(nterms, DPB_ORDER_MAXNROOTS); i++ )
897  {
898  SCIP_Bool isBetter;
899  const int root = terms[i];
900  if( root == root_org )
901  continue;
902 
903  SCIP_CALL( computeOrderingFromNode(scip, graph, root, sequence_tmp) );
904 
905  if( sequence_tmp->maxbordersize >= BPBORDER_MAXBORDERSIZE )
906  continue;
907 
908  if( sequence_tmp->maxnpartitions >= BPBORDER_MAXNPARTITIONS )
909  continue;
910 
911  isBetter = sequence_tmp->maxnpartitions < sequence_base->maxnpartitions
912  && sequence_tmp->maxbordersize <= sequence_base->maxbordersize;
913 
914  // todo use parameter
915  if( !isBetter )
916  isBetter = (1.2 * (SCIP_Real) sequence_tmp->maxnpartitions < (SCIP_Real) sequence_base->maxnpartitions);
917 
918  if( isBetter )
919  {
920  SCIPdebugMessage("updating ordering: \n" );
921  SCIPdebugMessage("---max n. partitions %ld->%ld \n", sequence_base->maxnpartitions, sequence_tmp->maxnpartitions);
922  SCIPdebugMessage("---max bordersize %d->%d \n", sequence_base->maxbordersize, sequence_tmp->maxbordersize);
923 
924  dpborder_dpbsequenceCopy(sequence_tmp, sequence_base);
925  }
926  }
927 
928  /* NOTE: might happen that the partitions are actually 0 if only terminals are all borders */
929  sequence_base->maxnpartitions = MAX(sequence_base->maxnpartitions, 2);
930 
931  SCIPdebugMessage("final ordering: \n" );
932  SCIPdebugMessage("---max n. partitions %ld \n", sequence_base->maxnpartitions);
933  SCIPdebugMessage("---max bordersize %d \n", sequence_base->maxbordersize);
934 
935  SCIPfreeMemory(scip, &terms);
936  dpborder_dpbsequenceFree(scip, &sequence_tmp);
937 
938  return SCIP_OKAY;
939 }
940 
941 
942 /** solves problem */
944  SCIP* scip, /**< SCIP data structure */
945  const GRAPH* graph, /**< graph */
946  DPBORDER* dpborder, /**< border */
947  SCIP_Bool* wasSolved /**< was problem solved to optimality? */
948 )
949 {
950  const int nnodes = graph_get_nNodes(graph);
951 
952  assert(scip && graph && dpborder && wasSolved);
953  assert(dpborder->dpbsequence);
954 
955  *wasSolved = TRUE;
956 
957  SCIP_CALL( initSolve(scip, graph, dpborder) );
958 
959  /* DP loop */
960  for( int s = 1; s < nnodes; s++ )
961  {
962  SCIP_CALL( addLevel(scip, graph, s, dpborder) );
963  SCIP_CALL( addPartitions(scip, graph, s, dpborder) );
964 
965  if( SCIPisStopped(scip) )
966  {
967  *wasSolved = FALSE;
968  break;
969  }
970  }
971 
972  if( *wasSolved )
973  {
974  SCIPdebugMessage("OBJ=%f \n", dpborder->global_obj);
975  assert(graph->terms == dpborder->ntermsvisited);
976  assert(dpborder->global_optposition != -1);
977 
978  printf("solved with partitions=%d, max. bordersize=%d \n", dpborder->global_npartitions, dpborder->dpbsequence->maxbordersize);
979  }
980 
981  return SCIP_OKAY;
982 }
#define STP_Vectype(type)
Definition: stpvector.h:44
static volatile int nterms
Definition: interrupt.c:38
#define StpVecGetSize(vec)
Definition: stpvector.h:139
int dpborder_partGetIdxNew(SCIP *scip, const DPBPART *borderpartition, const int *candstarts_sub, int ncandstarts_sub, DPBORDER *dpborder)
#define StpVecClear(vec)
Definition: stpvector.h:134
int * head
Definition: graphdefs.h:141
int source
Definition: graphdefs.h:195
#define Is_term(a)
Definition: graphdefs.h:102
static SCIP_RETCODE initSolve(SCIP *scip, const GRAPH *graph, DPBORDER *dpborder)
#define SCIPallocClearBufferArray(scip, ptr, num)
Definition: scip_mem.h:117
static void hashmap_updateKeyarr(const char *keyarr, struct hashmap_s *out_hashmap) HASHMAP_USED
int terms
Definition: graphdefs.h:192
void dpborder_dpbsequenceFree(SCIP *scip, DPBSEQUENCE **dpbsequence)
#define SCIPallocMemoryArray(scip, ptr, num)
Definition: scip_mem.h:55
SCIP_RETCODE dpborder_coreSolve(SCIP *scip, const GRAPH *graph, DPBORDER *dpborder, SCIP_Bool *wasSolved)
void graph_knot_printInfo(const GRAPH *, int)
Definition: graph_stats.c:151
static int hashmap_remove(struct hashmap_s *const hashmap, int position, const unsigned len) HASHMAP_USED
Remove an element from the hashmap.
static SCIP_RETCODE computeOrderingFromNode(SCIP *scip, const GRAPH *graph, int root, DPBSEQUENCE *dpbsequence)
#define FALSE
Definition: def.h:87
SCIP_Real * cost
Definition: graphdefs.h:142
#define TRUE
Definition: def.h:86
#define SWAP_INTS(int1, int2)
Definition: misc_stp.h:34
#define DPB_ORDERMULT_PREVS
Definition: dpborder_core.c:32
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:54
static DPBLEVEL * dpborder_getTopLevel(const DPBORDER *dpborder)
#define StpVecPopBack(vec)
Definition: stpvector.h:182
static void borderBuildCharMap(int iteration, DPBORDER *dpborder)
#define StpVecReserve(scip, vec, _size_)
Definition: stpvector.h:186
#define SCIPdebugMessage
Definition: pub_message.h:87
static int dpborder_getTopDelimiter(const DPBORDER *dpborder)
#define FARAWAY
Definition: graphdefs.h:89
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:127
int * start
Definition: graphdefs.h:140
#define BPBORDER_MAXNPARTITIONS
header only, simple implementation of an STL like vector
CSR * csr_storage
Definition: graphdefs.h:270
static SCIP_Bool allTermsAreVisited(const GRAPH *graph, const MST *mst)
Definition: relax_stpenum.c:72
SCIP_RETCODE dpborder_coreUpdateOrdering(SCIP *scip, const GRAPH *graph, DPBORDER *dpborder)
SCIP_Real dpborder_partGetConnectionCost(const DPBORDER *dpborder, const DPBPART *borderpartition, const int *candstarts_sub, int ncandstarts_sub)
#define DPB_ORDER_MAXNROOTS
Definition: dpborder_core.c:37
miscellaneous methods used for solving Steiner problems
#define SCIPerrorMessage
Definition: pub_message.h:55
static void updateBorder(SCIP *scip, const GRAPH *graph, int iteration, DPBORDER *dpborder)
SCIP_RETCODE dpborder_dpblevelInit(SCIP *scip, DPBLEVEL **dpblevel)
SCIP_RETCODE graph_getTermsRandom(SCIP *, const GRAPH *, int *)
Definition: graph_base.c:588
void dpborder_dpbsequenceCopy(const DPBSEQUENCE *dpbsequence_source, DPBSEQUENCE *dpbsequence_target)
static SCIP_RETCODE addLevelFirst(SCIP *scip, const GRAPH *graph, DPBORDER *dpborder)
#define SCIPreallocMemoryArray(scip, ptr, newnum)
Definition: scip_mem.h:61
int *RESTRICT grad
Definition: graphdefs.h:201
#define DPB_ORDERMULT_OUTDELTA
Definition: dpborder_core.c:35
#define NULL
Definition: lpi_spx1.cpp:155
#define EQ(a, b)
Definition: portab.h:79
#define SCIP_CALL(x)
Definition: def.h:384
SCIP_RETCODE dpborder_coreComputeOrderingSimple(SCIP *scip, const GRAPH *graph, DPBORDER *dpborder)
#define LT(a, b)
Definition: portab.h:81
static SCIP_RETCODE updateFromPartition(SCIP *scip, int globalposition, const GRAPH *graph, DPBORDER *dpborder)
void dpborder_partPrint(const DPBPART *borderpartition)
int dpborder_partglobalGetCard(int globalindex, int delimiter, const DPBORDER *dpborder)
#define DPB_ORDERMULT_OUTDEG
Definition: dpborder_core.c:34
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:115
#define GT(a, b)
Definition: portab.h:84
#define SCIP_Bool
Definition: def.h:84
#define DPBORDER_GROWTH_FACTOR
static void borderBuildCharDists(const GRAPH *graph, DPBORDER *dpborder)
#define MAX(x, y)
Definition: tclique_def.h:83
#define BPBORDER_MAXBORDERSIZE
int *RESTRICT term
Definition: graphdefs.h:196
static int dpborder_getDelimiter(const DPBORDER *dpborder, int iteration)
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:127
SCIP_RETCODE dpborder_dpbsequenceInit(SCIP *scip, const GRAPH *graph, DPBSEQUENCE **dpbsequence)
Definition: dpborder_base.c:97
#define DPB_Ptype
#define SCIPfreeMemory(scip, ptr)
Definition: scip_mem.h:69
Dynamic programming solver for Steiner tree (sub-) problems with small border.
static SCIP_Bool hashmap_isEmpty(const struct hashmap_s *const hashmap) HASHMAP_USED
#define SCIP_Real
Definition: def.h:177
static SCIP_RETCODE partitionTryRealloc(SCIP *scip, int newadds, DPBORDER *dpborder)
Definition: dpborder_core.c:85
#define BLOCKED
Definition: graphdefs.h:90
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:694
Dynamic programming internals for Steiner tree (sub-) problems with small number of terminals...
#define StpVecFree(scip, vec)
Definition: stpvector.h:153
int graph_get_nNodes(const GRAPH *)
Definition: graph_stats.c:536
SCIP_Bool graph_knot_isInRange(const GRAPH *, int)
Definition: graph_node.c:52
#define nnodes
Definition: gastrans.c:65
#define StpVecPushBack(scip, vec, value)
Definition: stpvector.h:167
static SCIP_RETCODE addPartitions(SCIP *scip, const GRAPH *graph, int iteration, DPBORDER *dpborder)
static SCIP_RETCODE addLevel(SCIP *scip, const GRAPH *graph, int iteration, DPBORDER *dpborder)
static void partitionGetRangeGlobal(const DPBORDER *dpborder, int globalposition, int *start, int *end)
int dpborder_partGetIdxNewExclusive(SCIP *scip, const DPBPART *borderpartition, DPBORDER *dpborder)
#define DPB_ORDERMULT_TERM
Definition: dpborder_core.c:33