1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2021 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 scipopt.org. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15
16 /**@file misc.c
17 * @ingroup OTHER_CFILES
18 * @brief miscellaneous methods
19 * @author Tobias Achterberg
20 * @author Gerald Gamrath
21 * @author Stefan Heinz
22 * @author Michael Winkler
23 * @author Kati Wolter
24 * @author Gregor Hendel
25 */
26
27 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
28
29 #include <assert.h>
30 #include <string.h>
31 #include <stdarg.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <errno.h>
35 #include <ctype.h>
36
37 #include "scip/def.h"
38 #include "scip/pub_message.h"
39 #include "scip/misc.h"
40 #include "scip/intervalarith.h"
41 #include "scip/pub_misc.h"
42
43 #ifndef NDEBUG
44 #include "scip/struct_misc.h"
45 #endif
46
47 /*
48 * methods for statistical tests
49 */
50
51 #define SQRTOFTWO 1.4142136 /**< the square root of 2 with sufficient precision */
52
53 /**< contains all critical values for a one-sided two sample t-test up to 15 degrees of freedom
54 * a critical value represents a threshold for rejecting the null-hypothesis in hypothesis testing at
55 * a certain confidence level;
56 *
57 * access through method SCIPstudentTGetCriticalValue()
58 *
59 * source: German Wikipedia
60 *
61 * for confidence levels
62 * c =
63 * 0.75 0.875 0.90 0.95 0.975 (one-sided)
64 * 0.50 0.750 0.80 0.90 0.950 (two-sided)
65 *
66 */
67 static const SCIP_Real studentt_quartiles[] = { /* df:*/
68 1.000, 2.414, 3.078, 6.314, 12.706, /* 1 */
69 0.816, 1.604, 1.886, 2.920, 4.303, /* 2 */
70 0.765, 1.423, 1.638, 2.353, 3.182, /* 3 */
71 0.741, 1.344, 1.533, 2.132, 2.776, /* 4 */
72 0.727, 1.301, 1.476, 2.015, 2.571, /* 5 */
73 0.718, 1.273, 1.440, 1.943, 2.447, /* 6 */
74 0.711, 1.254, 1.415, 1.895, 2.365, /* 7 */
75 0.706, 1.240, 1.397, 1.860, 2.306, /* 8 */
76 0.703, 1.230, 1.383, 1.833, 2.262, /* 9 */
77 0.700, 1.221, 1.372, 1.812, 2.228, /* 10 */
78 0.697, 1.214, 1.363, 1.796, 2.201, /* 11 */
79 0.695, 1.209, 1.356, 1.782, 2.179, /* 12 */
80 0.694, 1.204, 1.350, 1.771, 2.160, /* 13 */
81 0.692, 1.200, 1.345, 1.761, 2.145, /* 14 */
82 0.691, 1.197, 1.341, 1.753, 2.131 /* 15 */
83 };
84
85 /**< critical values for higher degrees of freedom of Student-T distribution for the same error probabilities; infact,
86 * these are critical values of the standard normal distribution with mean 0 and variance 1
87 */
88 static const SCIP_Real studentt_quartilesabove[] = {
89 0.674, 1.150, 1.282, 1.645, 1.960
90 };
91
92 /** the maximum degrees of freedom represented before switching to normal approximation */
93 static const int studentt_maxdf = sizeof(studentt_quartiles)/(5 * sizeof(SCIP_Real));
94
95 /** get critical value of a Student-T distribution for a given number of degrees of freedom at a confidence level */
SCIPstudentTGetCriticalValue(SCIP_CONFIDENCELEVEL clevel,int df)96 SCIP_Real SCIPstudentTGetCriticalValue(
97 SCIP_CONFIDENCELEVEL clevel, /**< (one-sided) confidence level */
98 int df /**< degrees of freedom */
99 )
100 {
101 if( df > studentt_maxdf )
102 return studentt_quartilesabove[(int)clevel];
103 else
104 return studentt_quartiles[(int)clevel + 5 * (df - 1)];
105 }
106
107 /** compute a t-value for the hypothesis that x and y are from the same population; Assuming that
108 * x and y represent normally distributed random samples with equal variance, the returned value
109 * comes from a Student-T distribution with countx + county - 2 degrees of freedom; this
110 * value can be compared with a critical value (see also SCIPstudentTGetCriticalValue()) at
111 * a predefined confidence level for checking if x and y significantly differ in location
112 */
SCIPcomputeTwoSampleTTestValue(SCIP_Real meanx,SCIP_Real meany,SCIP_Real variancex,SCIP_Real variancey,SCIP_Real countx,SCIP_Real county)113 SCIP_Real SCIPcomputeTwoSampleTTestValue(
114 SCIP_Real meanx, /**< the mean of the first distribution */
115 SCIP_Real meany, /**< the mean of the second distribution */
116 SCIP_Real variancex, /**< the variance of the x-distribution */
117 SCIP_Real variancey, /**< the variance of the y-distribution */
118 SCIP_Real countx, /**< number of samples of x */
119 SCIP_Real county /**< number of samples of y */
120 )
121 {
122 SCIP_Real pooledvariance;
123 SCIP_Real tresult;
124
125 /* too few samples */
126 if( countx < 1.9 || county < 1.9 )
127 return SCIP_INVALID;
128
129 /* pooled variance is the weighted average of the two variances */
130 pooledvariance = (countx - 1) * variancex + (county - 1) * variancey;
131 pooledvariance /= (countx + county - 2);
132
133 /* a variance close to zero means the distributions are basically constant */
134 pooledvariance = MAX(pooledvariance, 1e-9);
135
136 /* tresult can be understood as realization of a Student-T distributed variable with
137 * countx + county - 2 degrees of freedom
138 */
139 tresult = (meanx - meany) / pooledvariance;
140 tresult *= SQRT(countx * county / (countx + county));
141
142 return tresult;
143 }
144
145 /** returns the value of the Gauss error function evaluated at a given point */
SCIPerf(SCIP_Real x)146 SCIP_Real SCIPerf(
147 SCIP_Real x /**< value to evaluate */
148 )
149 {
150 #if defined(_WIN32) || defined(_WIN64)
151 SCIP_Real a1, a2, a3, a4, a5, p, t, y;
152 int sign;
153
154 a1 = 0.254829592;
155 a2 = -0.284496736;
156 a3 = 1.421413741;
157 a4 = -1.453152027;
158 a5 = 1.061405429;
159 p = 0.3275911;
160
161 sign = (x >= 0) ? 1 : -1;
162 x = REALABS(x);
163
164 t = 1.0/(1.0 + p*x);
165 y = 1.0 - (((((a5*t + a4)*t) + a3)*t + a2)*t + a1)*t*exp(-x*x);
166 return sign * y;
167 #else
168 return erf(x);
169 #endif
170 }
171
172 /** get critical value of a standard normal distribution at a given confidence level */
SCIPnormalGetCriticalValue(SCIP_CONFIDENCELEVEL clevel)173 SCIP_Real SCIPnormalGetCriticalValue(
174 SCIP_CONFIDENCELEVEL clevel /**< (one-sided) confidence level */
175 )
176 {
177 return studentt_quartilesabove[(int)clevel];
178 }
179
180 /** calculates the cumulative distribution P(-infinity <= x <= value) that a normally distributed
181 * random variable x takes a value between -infinity and parameter \p value.
182 *
183 * The distribution is given by the respective mean and deviation. This implementation
184 * uses the error function SCIPerf().
185 */
SCIPnormalCDF(SCIP_Real mean,SCIP_Real variance,SCIP_Real value)186 SCIP_Real SCIPnormalCDF(
187 SCIP_Real mean, /**< the mean value of the distribution */
188 SCIP_Real variance, /**< the square of the deviation of the distribution */
189 SCIP_Real value /**< the upper limit of the calculated distribution integral */
190 )
191 {
192 SCIP_Real normvalue;
193 SCIP_Real std;
194
195 /* we need to calculate the standard deviation from the variance */
196 assert(variance >= -1e-9);
197 if( variance < 1e-9 )
198 std = 0.0;
199 else
200 std = sqrt(variance);
201
202 /* special treatment for zero variance */
203 if( std < 1e-9 )
204 {
205 if( value < mean + 1e-9 )
206 return 1.0;
207 else
208 return 0.0;
209 }
210 assert( std != 0.0 ); /* for lint */
211
212 /* scale and translate to standard normal distribution. Factor sqrt(2) is needed for SCIPerf() function */
213 normvalue = (value - mean)/(std * SQRTOFTWO);
214
215 SCIPdebugMessage(" Normalized value %g = ( %g - %g ) / (%g * 1.4142136)\n", normvalue, value, mean, std);
216
217 /* calculate the cumulative distribution function for normvalue. For negative normvalues, we negate the normvalue and
218 * use the oddness of the SCIPerf()-function; special treatment for values close to zero.
219 */
220 if( normvalue < 1e-9 && normvalue > -1e-9 )
221 return .5;
222 else if( normvalue > 0 )
223 {
224 SCIP_Real erfresult;
225
226 erfresult = SCIPerf(normvalue);
227 return erfresult / 2.0 + 0.5;
228 }
229 else
230 {
231 SCIP_Real erfresult;
232
233 erfresult = SCIPerf(-normvalue);
234
235 return 0.5 - erfresult / 2.0;
236 }
237 }
238
239 /*
240 * SCIP regression methods
241 */
242
243 /** returns the number of observations of this regression */
SCIPregressionGetNObservations(SCIP_REGRESSION * regression)244 int SCIPregressionGetNObservations(
245 SCIP_REGRESSION* regression /**< regression data structure */
246 )
247 {
248 assert(regression != NULL);
249
250 return regression->nobservations;
251 }
252
253 /** return the current slope of the regression */
SCIPregressionGetSlope(SCIP_REGRESSION * regression)254 SCIP_Real SCIPregressionGetSlope(
255 SCIP_REGRESSION* regression /**< regression data structure */
256 )
257 {
258 assert(regression != NULL);
259
260 return regression->slope;
261 }
262
263 /** get the current y-intercept of the regression */
SCIPregressionGetIntercept(SCIP_REGRESSION * regression)264 SCIP_Real SCIPregressionGetIntercept(
265 SCIP_REGRESSION* regression /**< regression data structure */
266 )
267 {
268 assert(regression != NULL);
269
270 return regression->intercept;
271 }
272
273 /** recomputes regression coefficients from available observation data */
274 static
regressionRecompute(SCIP_REGRESSION * regression)275 void regressionRecompute(
276 SCIP_REGRESSION* regression /**< regression data structure */
277 )
278 {
279 /* regression coefficients require two or more observations and variance in x */
280 if( regression->nobservations <= 1 || EPSZ(regression->variancesumx, 1e-9) )
281 {
282 regression->slope = SCIP_INVALID;
283 regression->intercept = SCIP_INVALID;
284 regression->corrcoef = SCIP_INVALID;
285 }
286 else if( EPSZ(regression->variancesumy, 1e-9) )
287 {
288 /* if there is no variance in the y's (but in the x's), the regression line is horizontal with y-intercept through the mean y */
289 regression->slope = 0.0;
290 regression->corrcoef = 0.0;
291 regression->intercept = regression->meany;
292 }
293 else
294 {
295 /* we ruled this case out already, but to please some compilers... */
296 assert(regression->variancesumx > 0.0);
297 assert(regression->variancesumy > 0.0);
298
299 /* compute slope */
300 regression->slope = (regression->sumxy - regression->nobservations * regression->meanx * regression->meany) / regression->variancesumx;
301
302 /* compute y-intercept */
303 regression->intercept = regression->meany - regression->slope * regression->meanx;
304
305 /* compute empirical correlation coefficient */
306 regression->corrcoef = (regression->sumxy - regression->nobservations * regression->meanx * regression->meany) /
307 sqrt(regression->variancesumx * regression->variancesumy);
308 }
309 }
310
311 /* incremental update of statistics describing mean and variance */
312 static
incrementalStatsUpdate(SCIP_Real value,SCIP_Real * meanptr,SCIP_Real * sumvarptr,int nobservations,SCIP_Bool add)313 void incrementalStatsUpdate(
314 SCIP_Real value, /**< current value to be added to incremental statistics */
315 SCIP_Real* meanptr, /**< pointer to value of current mean */
316 SCIP_Real* sumvarptr, /**< pointer to the value of the current variance sum term */
317 int nobservations, /**< total number of observations */
318 SCIP_Bool add /**< TRUE if the value should be added, FALSE for removing it */
319 )
320 {
321 SCIP_Real oldmean;
322 SCIP_Real addfactor;
323 assert(meanptr != NULL);
324 assert(sumvarptr != NULL);
325 assert(nobservations > 0 || add);
326
327 addfactor = add ? 1.0 : -1.0;
328
329 oldmean = *meanptr;
330 *meanptr = oldmean + addfactor * (value - oldmean)/(SCIP_Real)nobservations;
331 *sumvarptr += addfactor * (value - oldmean) * (value - (*meanptr));
332
333 /* it may happen that *sumvarptr is slightly negative, especially after a series of add/removal operations */
334 assert(*sumvarptr >= -1e-4);
335 *sumvarptr = MAX(0.0, *sumvarptr);
336 }
337
338 /** removes an observation (x,y) from the regression */
SCIPregressionRemoveObservation(SCIP_REGRESSION * regression,SCIP_Real x,SCIP_Real y)339 void SCIPregressionRemoveObservation(
340 SCIP_REGRESSION* regression, /**< regression data structure */
341 SCIP_Real x, /**< X of observation */
342 SCIP_Real y /**< Y of the observation */
343 )
344 {
345 assert(regression != NULL);
346 assert(regression->nobservations > 0);
347
348 /* simply call the reset function in the case of a single remaining observation to avoid numerical troubles */
349 if( regression->nobservations == 1 )
350 {
351 SCIPregressionReset(regression);
352 }
353 else
354 {
355 SCIP_Bool add = FALSE;
356 --regression->nobservations;
357
358 /* decrement individual means and variances */
359 incrementalStatsUpdate(x, ®ression->meanx, ®ression->variancesumx, regression->nobservations, add);
360 incrementalStatsUpdate(y, ®ression->meany, ®ression->variancesumy, regression->nobservations, add);
361
362 /* decrement product sum */
363 regression->sumxy -= (x * y);
364 }
365
366 /* recompute regression parameters */
367 regressionRecompute(regression);
368 }
369
370 /** update regression by a new observation (x,y) */
SCIPregressionAddObservation(SCIP_REGRESSION * regression,SCIP_Real x,SCIP_Real y)371 void SCIPregressionAddObservation(
372 SCIP_REGRESSION* regression, /**< regression data structure */
373 SCIP_Real x, /**< X of observation */
374 SCIP_Real y /**< Y of the observation */
375 )
376 {
377 SCIP_Bool add = TRUE;
378 assert(regression != NULL);
379
380 ++(regression->nobservations);
381 incrementalStatsUpdate(x, ®ression->meanx, ®ression->variancesumx, regression->nobservations, add);
382 incrementalStatsUpdate(y, ®ression->meany, ®ression->variancesumy, regression->nobservations, add);
383
384 regression->sumxy += x * y;
385
386 regressionRecompute(regression);
387 }
388
389 /** reset regression data structure */
SCIPregressionReset(SCIP_REGRESSION * regression)390 void SCIPregressionReset(
391 SCIP_REGRESSION* regression /**< regression data structure */
392 )
393 {
394 regression->intercept = SCIP_INVALID;
395 regression->slope = SCIP_INVALID;
396 regression->corrcoef = SCIP_INVALID;
397 regression->meanx = 0;
398 regression->variancesumx = 0;
399 regression->sumxy = 0;
400 regression->meany = 0;
401 regression->variancesumy = 0;
402 regression->nobservations = 0;
403 }
404
405 /** creates and resets a regression */
SCIPregressionCreate(SCIP_REGRESSION ** regression)406 SCIP_RETCODE SCIPregressionCreate(
407 SCIP_REGRESSION** regression /**< regression data structure */
408 )
409 {
410 assert(regression != NULL);
411
412 /* allocate necessary memory */
413 SCIP_ALLOC (BMSallocMemory(regression) );
414
415 /* reset the regression */
416 SCIPregressionReset(*regression);
417
418 return SCIP_OKAY;
419 }
420
421 /** creates and resets a regression */
SCIPregressionFree(SCIP_REGRESSION ** regression)422 void SCIPregressionFree(
423 SCIP_REGRESSION** regression /**< regression data structure */
424 )
425 {
426 BMSfreeMemory(regression);
427 }
428
429 /** calculate memory size for dynamically allocated arrays (copied from scip/set.c) */
430 static
calcGrowSize(int initsize,SCIP_Real growfac,int num)431 int calcGrowSize(
432 int initsize, /**< initial size of array */
433 SCIP_Real growfac, /**< growing factor of array */
434 int num /**< minimum number of entries to store */
435 )
436 {
437 int size;
438
439 assert(initsize >= 0);
440 assert(growfac >= 1.0);
441 assert(num >= 0);
442
443 if( growfac == 1.0 )
444 size = MAX(initsize, num);
445 else
446 {
447 int oldsize;
448
449 /* calculate the size with this loop, such that the resulting numbers are always the same (-> block memory) */
450 initsize = MAX(initsize, 4);
451 size = initsize;
452 oldsize = size - 1;
453
454 /* second condition checks against overflow */
455 while( size < num && size > oldsize )
456 {
457 oldsize = size;
458 size = (int)(growfac * size + initsize);
459 }
460
461 /* if an overflow happened, set the correct value */
462 if( size <= oldsize )
463 size = num;
464 }
465
466 assert(size >= initsize);
467 assert(size >= num);
468
469 return size;
470 }
471
472 /*
473 * GML graphical printing methods
474 * For a detailed format decription see http://docs.yworks.com/yfiles/doc/developers-guide/gml.html
475 */
476
477 #define GMLNODEWIDTH 120.0
478 #define GMLNODEHEIGTH 30.0
479 #define GMLFONTSIZE 13
480 #define GMLNODETYPE "rectangle"
481 #define GMLNODEFILLCOLOR "#ff0000"
482 #define GMLEDGECOLOR "black"
483 #define GMLNODEBORDERCOLOR "#000000"
484
485
486 /** writes a node section to the given graph file */
SCIPgmlWriteNode(FILE * file,unsigned int id,const char * label,const char * nodetype,const char * fillcolor,const char * bordercolor)487 void SCIPgmlWriteNode(
488 FILE* file, /**< file to write to */
489 unsigned int id, /**< id of the node */
490 const char* label, /**< label of the node */
491 const char* nodetype, /**< type of the node, or NULL */
492 const char* fillcolor, /**< color of the node's interior, or NULL */
493 const char* bordercolor /**< color of the node's border, or NULL */
494 )
495 {
496 assert(file != NULL);
497 assert(label != NULL);
498
499 fprintf(file, " node\n");
500 fprintf(file, " [\n");
501 fprintf(file, " id %u\n", id);
502 fprintf(file, " label \"%s\"\n", label);
503 fprintf(file, " graphics\n");
504 fprintf(file, " [\n");
505 fprintf(file, " w %g\n", GMLNODEWIDTH);
506 fprintf(file, " h %g\n", GMLNODEHEIGTH);
507
508 if( nodetype != NULL )
509 fprintf(file, " type \"%s\"\n", nodetype);
510 else
511 fprintf(file, " type \"%s\"\n", GMLNODETYPE);
512
513 if( fillcolor != NULL )
514 fprintf(file, " fill \"%s\"\n", fillcolor);
515 else
516 fprintf(file, " fill \"%s\"\n", GMLNODEFILLCOLOR);
517
518 if( bordercolor != NULL )
519 fprintf(file, " outline \"%s\"\n", bordercolor);
520 else
521 fprintf(file, " outline \"%s\"\n", GMLNODEBORDERCOLOR);
522
523 fprintf(file, " ]\n");
524 fprintf(file, " LabelGraphics\n");
525 fprintf(file, " [\n");
526 fprintf(file, " text \"%s\"\n", label);
527 fprintf(file, " fontSize %d\n", GMLFONTSIZE);
528 fprintf(file, " fontName \"Dialog\"\n");
529 fprintf(file, " anchor \"c\"\n");
530 fprintf(file, " ]\n");
531 fprintf(file, " ]\n");
532 }
533
534 /** writes a node section including weight to the given graph file */
SCIPgmlWriteNodeWeight(FILE * file,unsigned int id,const char * label,const char * nodetype,const char * fillcolor,const char * bordercolor,SCIP_Real weight)535 void SCIPgmlWriteNodeWeight(
536 FILE* file, /**< file to write to */
537 unsigned int id, /**< id of the node */
538 const char* label, /**< label of the node */
539 const char* nodetype, /**< type of the node, or NULL */
540 const char* fillcolor, /**< color of the node's interior, or NULL */
541 const char* bordercolor, /**< color of the node's border, or NULL */
542 SCIP_Real weight /**< weight of node */
543 )
544 {
545 assert(file != NULL);
546 assert(label != NULL);
547
548 fprintf(file, " node\n");
549 fprintf(file, " [\n");
550 fprintf(file, " id %u\n", id);
551 fprintf(file, " label \"%s\"\n", label);
552 fprintf(file, " weight %g\n", weight);
553 fprintf(file, " graphics\n");
554 fprintf(file, " [\n");
555 fprintf(file, " w %g\n", GMLNODEWIDTH);
556 fprintf(file, " h %g\n", GMLNODEHEIGTH);
557
558 if( nodetype != NULL )
559 fprintf(file, " type \"%s\"\n", nodetype);
560 else
561 fprintf(file, " type \"%s\"\n", GMLNODETYPE);
562
563 if( fillcolor != NULL )
564 fprintf(file, " fill \"%s\"\n", fillcolor);
565 else
566 fprintf(file, " fill \"%s\"\n", GMLNODEFILLCOLOR);
567
568 if( bordercolor != NULL )
569 fprintf(file, " outline \"%s\"\n", bordercolor);
570 else
571 fprintf(file, " outline \"%s\"\n", GMLNODEBORDERCOLOR);
572
573 fprintf(file, " ]\n");
574 fprintf(file, " LabelGraphics\n");
575 fprintf(file, " [\n");
576 fprintf(file, " text \"%s\"\n", label);
577 fprintf(file, " fontSize %d\n", GMLFONTSIZE);
578 fprintf(file, " fontName \"Dialog\"\n");
579 fprintf(file, " anchor \"c\"\n");
580 fprintf(file, " ]\n");
581 fprintf(file, " ]\n");
582 }
583
584 /** writes an edge section to the given graph file */
SCIPgmlWriteEdge(FILE * file,unsigned int source,unsigned int target,const char * label,const char * color)585 void SCIPgmlWriteEdge(
586 FILE* file, /**< file to write to */
587 unsigned int source, /**< source node id of the node */
588 unsigned int target, /**< target node id of the edge */
589 const char* label, /**< label of the edge, or NULL */
590 const char* color /**< color of the edge, or NULL */
591 )
592 {
593 assert(file != NULL);
594
595 fprintf(file, " edge\n");
596 fprintf(file, " [\n");
597 fprintf(file, " source %u\n", source);
598 fprintf(file, " target %u\n", target);
599
600 if( label != NULL)
601 fprintf(file, " label \"%s\"\n", label);
602
603 fprintf(file, " graphics\n");
604 fprintf(file, " [\n");
605
606 if( color != NULL )
607 fprintf(file, " fill \"%s\"\n", color);
608 else
609 fprintf(file, " fill \"%s\"\n", GMLEDGECOLOR);
610
611 /* fprintf(file, " arrow \"both\"\n"); */
612 fprintf(file, " ]\n");
613
614 if( label != NULL)
615 {
616 fprintf(file, " LabelGraphics\n");
617 fprintf(file, " [\n");
618 fprintf(file, " text \"%s\"\n", label);
619 fprintf(file, " fontSize %d\n", GMLFONTSIZE);
620 fprintf(file, " fontName \"Dialog\"\n");
621 fprintf(file, " anchor \"c\"\n");
622 fprintf(file, " ]\n");
623 }
624
625 fprintf(file, " ]\n");
626 }
627
628 /** writes an arc section to the given graph file */
SCIPgmlWriteArc(FILE * file,unsigned int source,unsigned int target,const char * label,const char * color)629 void SCIPgmlWriteArc(
630 FILE* file, /**< file to write to */
631 unsigned int source, /**< source node id of the node */
632 unsigned int target, /**< target node id of the edge */
633 const char* label, /**< label of the edge, or NULL */
634 const char* color /**< color of the edge, or NULL */
635 )
636 {
637 assert(file != NULL);
638
639 fprintf(file, " edge\n");
640 fprintf(file, " [\n");
641 fprintf(file, " source %u\n", source);
642 fprintf(file, " target %u\n", target);
643
644 if( label != NULL)
645 fprintf(file, " label \"%s\"\n", label);
646
647 fprintf(file, " graphics\n");
648 fprintf(file, " [\n");
649
650 if( color != NULL )
651 fprintf(file, " fill \"%s\"\n", color);
652 else
653 fprintf(file, " fill \"%s\"\n", GMLEDGECOLOR);
654
655 fprintf(file, " targetArrow \"standard\"\n");
656 fprintf(file, " ]\n");
657
658 if( label != NULL)
659 {
660 fprintf(file, " LabelGraphics\n");
661 fprintf(file, " [\n");
662 fprintf(file, " text \"%s\"\n", label);
663 fprintf(file, " fontSize %d\n", GMLFONTSIZE);
664 fprintf(file, " fontName \"Dialog\"\n");
665 fprintf(file, " anchor \"c\"\n");
666 fprintf(file, " ]\n");
667 }
668
669 fprintf(file, " ]\n");
670 }
671
672 /** writes the starting line to a GML graph file, does not open a file */
SCIPgmlWriteOpening(FILE * file,SCIP_Bool directed)673 void SCIPgmlWriteOpening(
674 FILE* file, /**< file to write to */
675 SCIP_Bool directed /**< is the graph directed */
676 )
677 {
678 assert(file != NULL);
679
680 fprintf(file, "graph\n");
681 fprintf(file, "[\n");
682 fprintf(file, " hierarchic 1\n");
683
684 if( directed )
685 fprintf(file, " directed 1\n");
686 }
687
688 /** writes the ending lines to a GML graph file, does not close a file */
SCIPgmlWriteClosing(FILE * file)689 void SCIPgmlWriteClosing(
690 FILE* file /**< file to close */
691 )
692 {
693 assert(file != NULL);
694
695 fprintf(file, "]\n");
696 }
697
698
699 /*
700 * Sparse solution
701 */
702
703 /** creates a sparse solution */
SCIPsparseSolCreate(SCIP_SPARSESOL ** sparsesol,SCIP_VAR ** vars,int nvars,SCIP_Bool cleared)704 SCIP_RETCODE SCIPsparseSolCreate(
705 SCIP_SPARSESOL** sparsesol, /**< pointer to store the created sparse solution */
706 SCIP_VAR** vars, /**< variables in the sparse solution, must not contain continuous
707 * variables
708 */
709 int nvars, /**< number of variables to store, size of the lower and upper bound
710 * arrays
711 */
712 SCIP_Bool cleared /**< should the lower and upper bound arrays be cleared (entries set to
713 * 0)
714 */
715 )
716 {
717 assert(sparsesol != NULL);
718 assert(vars != NULL);
719 assert(nvars >= 0);
720
721 SCIP_ALLOC( BMSallocMemory(sparsesol) );
722
723 #ifndef NDEBUG
724 {
725 int v;
726
727 for( v = nvars - 1; v >= 0; --v )
728 {
729 assert(vars[v] != NULL);
730 /* assert(SCIPvarGetType(vars[v]) != SCIP_VARTYPE_CONTINUOUS); */
731 }
732 }
733 #endif
734
735 /* copy variables */
736 SCIP_ALLOC( BMSduplicateMemoryArray(&((*sparsesol)->vars), vars, nvars) );
737
738 /* create bound arrays */
739 if( cleared )
740 {
741 SCIP_ALLOC( BMSallocClearMemoryArray(&((*sparsesol)->lbvalues), nvars) );
742 SCIP_ALLOC( BMSallocClearMemoryArray(&((*sparsesol)->ubvalues), nvars) );
743 }
744 else
745 {
746 SCIP_ALLOC( BMSallocMemoryArray(&((*sparsesol)->lbvalues), nvars) );
747 SCIP_ALLOC( BMSallocMemoryArray(&((*sparsesol)->ubvalues), nvars) );
748 }
749
750 (*sparsesol)->nvars = nvars;
751
752 return SCIP_OKAY;
753 }
754
755 /** frees sparse solution */
SCIPsparseSolFree(SCIP_SPARSESOL ** sparsesol)756 void SCIPsparseSolFree(
757 SCIP_SPARSESOL** sparsesol /**< pointer to a sparse solution */
758 )
759 {
760 assert(sparsesol != NULL);
761 assert(*sparsesol != NULL);
762
763 BMSfreeMemoryArray(&((*sparsesol)->vars));
764 BMSfreeMemoryArray(&((*sparsesol)->ubvalues));
765 BMSfreeMemoryArray(&((*sparsesol)->lbvalues));
766 BMSfreeMemory(sparsesol);
767 }
768
769 /** returns the variables stored in the given sparse solution */
SCIPsparseSolGetVars(SCIP_SPARSESOL * sparsesol)770 SCIP_VAR** SCIPsparseSolGetVars(
771 SCIP_SPARSESOL* sparsesol /**< a sparse solution */
772 )
773 {
774 assert(sparsesol != NULL);
775
776 return sparsesol->vars;
777 }
778
779 /** returns the number of variables stored in the given sparse solution */
SCIPsparseSolGetNVars(SCIP_SPARSESOL * sparsesol)780 int SCIPsparseSolGetNVars(
781 SCIP_SPARSESOL* sparsesol /**< a sparse solution */
782 )
783 {
784 assert(sparsesol != NULL);
785
786 return sparsesol->nvars;
787 }
788
789 /** returns the lower bound array for all variables for a given sparse solution */
SCIPsparseSolGetLbs(SCIP_SPARSESOL * sparsesol)790 SCIP_Longint* SCIPsparseSolGetLbs(
791 SCIP_SPARSESOL* sparsesol /**< a sparse solution */
792 )
793 {
794 assert(sparsesol != NULL);
795
796 return sparsesol->lbvalues;
797 }
798
799 /** returns the upper bound array for all variables for a given sparse solution */
SCIPsparseSolGetUbs(SCIP_SPARSESOL * sparsesol)800 SCIP_Longint* SCIPsparseSolGetUbs(
801 SCIP_SPARSESOL* sparsesol /**< a sparse solution */
802 )
803 {
804 assert(sparsesol != NULL);
805
806 return sparsesol->ubvalues;
807 }
808
809 /** constructs the first solution of sparse solution (all variables are set to their lower bound value */
SCIPsparseSolGetFirstSol(SCIP_SPARSESOL * sparsesol,SCIP_Longint * sol,int nvars)810 void SCIPsparseSolGetFirstSol(
811 SCIP_SPARSESOL* sparsesol, /**< sparse solutions */
812 SCIP_Longint* sol, /**< array to store the first solution */
813 int nvars /**< number of variables */
814 )
815 {
816 SCIP_Longint* lbvalues;
817 int v;
818
819 assert(sparsesol != NULL);
820 assert(sol != NULL);
821 assert(nvars == SCIPsparseSolGetNVars(sparsesol));
822
823 lbvalues = SCIPsparseSolGetLbs(sparsesol);
824 assert(lbvalues != NULL);
825
826 /* copy the lower bounds */
827 for( v = 0; v < nvars; ++v )
828 sol[v] = lbvalues[v];
829 }
830
831
832 /** constructs the next solution of the sparse solution and return whether there was one more or not */
SCIPsparseSolGetNextSol(SCIP_SPARSESOL * sparsesol,SCIP_Longint * sol,int nvars)833 SCIP_Bool SCIPsparseSolGetNextSol(
834 SCIP_SPARSESOL* sparsesol, /**< sparse solutions */
835 SCIP_Longint* sol, /**< current solution array which get changed to the next solution */
836 int nvars /**< number of variables */
837 )
838 {
839 SCIP_Longint* lbvalues;
840 SCIP_Longint* ubvalues;
841 SCIP_Longint lbvalue;
842 SCIP_Longint ubvalue;
843 SCIP_Bool singular;
844 SCIP_Bool carryflag;
845 int v;
846
847 assert(sparsesol != NULL);
848 assert(sol != NULL);
849
850 if( nvars == 0 )
851 return FALSE;
852
853 assert(nvars > 0);
854 assert(nvars == SCIPsparseSolGetNVars(sparsesol));
855
856 lbvalues = SCIPsparseSolGetLbs(sparsesol);
857 ubvalues = SCIPsparseSolGetUbs(sparsesol);
858 assert(lbvalues != NULL);
859 assert(ubvalues != NULL);
860
861 singular = TRUE;
862 carryflag = FALSE;
863
864 for( v = 0; v < nvars; ++v )
865 {
866 lbvalue = lbvalues[v];
867 ubvalue = ubvalues[v];
868
869 if( lbvalue < ubvalue )
870 {
871 singular = FALSE;
872
873 if( carryflag == FALSE )
874 {
875 if( sol[v] < ubvalue )
876 {
877 sol[v]++;
878 break;
879 }
880 else
881 {
882 /* in the last solution the variables v was set to its upper bound value */
883 assert(sol[v] == ubvalue);
884 sol[v] = lbvalue;
885 carryflag = TRUE;
886 }
887 }
888 else
889 {
890 if( sol[v] < ubvalue )
891 {
892 sol[v]++;
893 carryflag = FALSE;
894 break;
895 }
896 else
897 {
898 assert(sol[v] == ubvalue);
899 sol[v] = lbvalue;
900 }
901 }
902 }
903 }
904
905 return (!carryflag && !singular);
906 }
907
908
909 /*
910 * Queue
911 */
912
913 /** resizes element memory to hold at least the given number of elements */
914 static
queueResize(SCIP_QUEUE * queue,int minsize)915 SCIP_RETCODE queueResize(
916 SCIP_QUEUE* queue, /**< pointer to a queue */
917 int minsize /**< minimal number of storable elements */
918 )
919 {
920 assert(queue != NULL);
921 assert(minsize > 0);
922
923 if( minsize <= queue->size )
924 return SCIP_OKAY;
925
926 queue->size = MAX(minsize, (int)(queue->size * queue->sizefac));
927 SCIP_ALLOC( BMSreallocMemoryArray(&queue->slots, queue->size) );
928
929 return SCIP_OKAY;
930 }
931
932
933 /** creates a (circular) queue, best used if the size will be fixed or will not be increased that much */
SCIPqueueCreate(SCIP_QUEUE ** queue,int initsize,SCIP_Real sizefac)934 SCIP_RETCODE SCIPqueueCreate(
935 SCIP_QUEUE** queue, /**< pointer to the new queue */
936 int initsize, /**< initial number of available element slots */
937 SCIP_Real sizefac /**< memory growing factor applied, if more element slots are needed */
938 )
939 {
940 assert(queue != NULL);
941
942 initsize = MAX(1, initsize);
943 sizefac = MAX(1.0, sizefac);
944
945 SCIP_ALLOC( BMSallocMemory(queue) );
946 (*queue)->firstfree = 0;
947 (*queue)->firstused = -1;
948 (*queue)->size = 0;
949 (*queue)->sizefac = sizefac;
950 (*queue)->slots = NULL;
951
952 SCIP_CALL( queueResize(*queue, initsize) );
953
954 return SCIP_OKAY;
955 }
956
957 /** frees queue, but not the data elements themselves */
SCIPqueueFree(SCIP_QUEUE ** queue)958 void SCIPqueueFree(
959 SCIP_QUEUE** queue /**< pointer to a queue */
960 )
961 {
962 assert(queue != NULL);
963
964 BMSfreeMemoryArray(&(*queue)->slots);
965 BMSfreeMemory(queue);
966 }
967
968 /** clears the queue, but doesn't free the data elements themselves */
SCIPqueueClear(SCIP_QUEUE * queue)969 void SCIPqueueClear(
970 SCIP_QUEUE* queue /**< queue */
971 )
972 {
973 assert(queue != NULL);
974
975 queue->firstfree = 0;
976 queue->firstused = -1;
977 }
978
979 /** reallocates slots if queue is necessary */
980 static
queueCheckSize(SCIP_QUEUE * queue)981 SCIP_RETCODE queueCheckSize(
982 SCIP_QUEUE* queue /**< queue */
983 )
984 {
985 if( queue->firstfree == queue->firstused )
986 {
987 int sizediff;
988 int oldsize = queue->size;
989
990 SCIP_CALL( queueResize(queue, queue->size+1) );
991 assert(oldsize < queue->size);
992
993 sizediff = queue->size - oldsize;
994
995 /* move the used memory at the slots to the end */
996 BMSmoveMemoryArray(&(queue->slots[queue->firstused + sizediff]), &(queue->slots[queue->firstused]), oldsize - queue->firstused); /*lint !e866*/
997 queue->firstused += sizediff;
998 }
999 assert(queue->firstfree != queue->firstused);
1000
1001 return SCIP_OKAY;
1002 }
1003
1004 /** checks and adjusts marker of first free and first used slot */
1005 static
queueCheckMarker(SCIP_QUEUE * queue)1006 void queueCheckMarker(
1007 SCIP_QUEUE* queue /**< queue */
1008 )
1009 {
1010 /* if we saved the value at the last position we need to reset the firstfree position */
1011 if( queue->firstfree == queue->size )
1012 queue->firstfree = 0;
1013
1014 /* if a first element was added, we need to update the firstused counter */
1015 if( queue->firstused == -1 )
1016 queue->firstused = 0;
1017 }
1018
1019 /** inserts pointer element at the end of the queue */
SCIPqueueInsert(SCIP_QUEUE * queue,void * elem)1020 SCIP_RETCODE SCIPqueueInsert(
1021 SCIP_QUEUE* queue, /**< queue */
1022 void* elem /**< element to be inserted */
1023 )
1024 {
1025 assert(queue != NULL);
1026 assert(queue->slots != NULL);
1027 assert(queue->firstused >= -1 && queue->firstused < queue->size);
1028 assert(queue->firstfree >= 0 && queue->firstused < queue->size);
1029 assert(queue->firstused > -1 || queue->firstfree == 0);
1030 assert(elem != NULL);
1031
1032 /* check allocated memory */
1033 SCIP_CALL( queueCheckSize(queue) );
1034
1035 /* insert element at the first free slot */
1036 queue->slots[queue->firstfree].ptr = elem;
1037 ++(queue->firstfree);
1038
1039 /* check and adjust marker */
1040 queueCheckMarker(queue);
1041
1042 return SCIP_OKAY;
1043 }
1044
1045 /** inserts unsigned integer element at the end of the queue */
SCIPqueueInsertUInt(SCIP_QUEUE * queue,unsigned int elem)1046 SCIP_RETCODE SCIPqueueInsertUInt(
1047 SCIP_QUEUE* queue, /**< queue */
1048 unsigned int elem /**< element to be inserted */
1049 )
1050 {
1051 assert(queue != NULL);
1052 assert(queue->slots != NULL);
1053 assert(queue->firstused >= -1 && queue->firstused < queue->size);
1054 assert(queue->firstfree >= 0 && queue->firstused < queue->size);
1055 assert(queue->firstused > -1 || queue->firstfree == 0);
1056
1057 /* check allocated memory */
1058 SCIP_CALL( queueCheckSize(queue) );
1059
1060 /* insert element at the first free slot */
1061 queue->slots[queue->firstfree].uinteger = elem;
1062 ++(queue->firstfree);
1063
1064 /* check and adjust marker */
1065 queueCheckMarker(queue);
1066
1067 return SCIP_OKAY;
1068 }
1069
1070 /** removes and returns the first pointer element of the queue, or NULL if no element exists */
SCIPqueueRemove(SCIP_QUEUE * queue)1071 void* SCIPqueueRemove(
1072 SCIP_QUEUE* queue /**< queue */
1073 )
1074 {
1075 int pos;
1076
1077 assert(queue != NULL);
1078 assert(queue->firstused >= -1 && queue->firstused < queue->size);
1079 assert(queue->firstfree >= 0 && queue->firstused < queue->size);
1080 assert(queue->firstused > -1 || queue->firstfree == 0);
1081
1082 if( queue->firstused == -1 )
1083 return NULL;
1084
1085 assert(queue->slots != NULL);
1086
1087 pos = queue->firstused;
1088 ++(queue->firstused);
1089
1090 /* if we removed the value at the last position we need to reset the firstused position */
1091 if( queue->firstused == queue->size )
1092 queue->firstused = 0;
1093
1094 /* if we reached the first free position we can reset both, firstused and firstused, positions */
1095 if( queue->firstused == queue->firstfree )
1096 {
1097 queue->firstused = -1;
1098 queue->firstfree = 0; /* this is not necessary but looks better if we have an empty list to reset this value */
1099 }
1100
1101 return (queue->slots[pos].ptr);
1102 }
1103
1104 /** removes and returns the first unsigned integer element of the queue, or UINT_MAX if no element exists */
SCIPqueueRemoveUInt(SCIP_QUEUE * queue)1105 unsigned int SCIPqueueRemoveUInt(
1106 SCIP_QUEUE* queue /**< queue */
1107 )
1108 {
1109 int pos;
1110
1111 assert(queue != NULL);
1112 assert(queue->firstused >= -1 && queue->firstused < queue->size);
1113 assert(queue->firstfree >= 0 && queue->firstused < queue->size);
1114 assert(queue->firstused > -1 || queue->firstfree == 0);
1115
1116 if( queue->firstused == -1 )
1117 return UINT_MAX;
1118
1119 assert(queue->slots != NULL);
1120
1121 pos = queue->firstused;
1122 ++(queue->firstused);
1123
1124 /* if we removed the value at the last position we need to reset the firstused position */
1125 if( queue->firstused == queue->size )
1126 queue->firstused = 0;
1127
1128 /* if we reached the first free position we can reset both, firstused and firstused, positions */
1129 if( queue->firstused == queue->firstfree )
1130 {
1131 queue->firstused = -1;
1132 queue->firstfree = 0; /* this is not necessary but looks better if we have an empty list to reset this value */
1133 }
1134
1135 return (queue->slots[pos].uinteger);
1136 }
1137
1138 /** returns the first element of the queue without removing it, or NULL if no element exists */
SCIPqueueFirst(SCIP_QUEUE * queue)1139 void* SCIPqueueFirst(
1140 SCIP_QUEUE* queue /**< queue */
1141 )
1142 {
1143 assert(queue != NULL);
1144 assert(queue->firstused >= -1 && queue->firstused < queue->size);
1145 assert(queue->firstfree >= 0 && queue->firstused < queue->size);
1146 assert(queue->firstused > -1 || queue->firstfree == 0);
1147
1148 if( queue->firstused == -1 )
1149 return NULL;
1150
1151 assert(queue->slots != NULL);
1152
1153 return queue->slots[queue->firstused].ptr;
1154 }
1155
1156 /** returns the first unsigned integer element of the queue without removing it, or UINT_MAX if no element exists */
SCIPqueueFirstUInt(SCIP_QUEUE * queue)1157 unsigned int SCIPqueueFirstUInt(
1158 SCIP_QUEUE* queue /**< queue */
1159 )
1160 {
1161 assert(queue != NULL);
1162 assert(queue->firstused >= -1 && queue->firstused < queue->size);
1163 assert(queue->firstfree >= 0 && queue->firstused < queue->size);
1164 assert(queue->firstused > -1 || queue->firstfree == 0);
1165
1166 if( queue->firstused == -1 )
1167 return UINT_MAX;
1168
1169 assert(queue->slots != NULL);
1170
1171 return queue->slots[queue->firstused].uinteger;
1172 }
1173
1174 /** returns whether the queue is empty */
SCIPqueueIsEmpty(SCIP_QUEUE * queue)1175 SCIP_Bool SCIPqueueIsEmpty(
1176 SCIP_QUEUE* queue /**< queue */
1177 )
1178 {
1179 assert(queue != NULL);
1180 assert(queue->firstused >= -1 && queue->firstused < queue->size);
1181 assert(queue->firstfree >= 0 && queue->firstused < queue->size);
1182 assert(queue->firstused > -1 || queue->firstfree == 0);
1183
1184 return (queue->firstused == -1);
1185 }
1186
1187 /** returns the number of elements in the queue */
SCIPqueueNElems(SCIP_QUEUE * queue)1188 int SCIPqueueNElems(
1189 SCIP_QUEUE* queue /**< queue */
1190 )
1191 {
1192 assert(queue != NULL);
1193 assert(queue->firstused >= -1 && queue->firstused < queue->size);
1194 assert(queue->firstfree >= 0 && queue->firstused < queue->size);
1195 assert(queue->firstused > -1 || queue->firstfree == 0);
1196
1197 if( queue->firstused == -1 )
1198 return 0;
1199 else if( queue->firstused < queue->firstfree )
1200 return queue->firstfree - queue->firstused;
1201 else if( queue->firstused == queue->firstfree )
1202 return queue->size;
1203 else
1204 return queue->firstfree + (queue->size - queue->firstused);
1205 }
1206
1207
1208 /*
1209 * Priority Queue
1210 */
1211
1212 #define PQ_PARENT(q) (((q)+1)/2-1)
1213 #define PQ_LEFTCHILD(p) (2*(p)+1)
1214 #define PQ_RIGHTCHILD(p) (2*(p)+2)
1215
1216
1217 /** resizes element memory to hold at least the given number of elements */
1218 static
pqueueResize(SCIP_PQUEUE * pqueue,int minsize)1219 SCIP_RETCODE pqueueResize(
1220 SCIP_PQUEUE* pqueue, /**< pointer to a priority queue */
1221 int minsize /**< minimal number of storable elements */
1222 )
1223 {
1224 assert(pqueue != NULL);
1225
1226 if( minsize <= pqueue->size )
1227 return SCIP_OKAY;
1228
1229 pqueue->size = MAX(minsize, (int)(pqueue->size * pqueue->sizefac));
1230 SCIP_ALLOC( BMSreallocMemoryArray(&pqueue->slots, pqueue->size) );
1231
1232 return SCIP_OKAY;
1233 }
1234
1235 /** creates priority queue */
SCIPpqueueCreate(SCIP_PQUEUE ** pqueue,int initsize,SCIP_Real sizefac,SCIP_DECL_SORTPTRCOMP ((* ptrcomp)),SCIP_DECL_PQUEUEELEMCHGPOS ((* elemchgpos)))1236 SCIP_RETCODE SCIPpqueueCreate(
1237 SCIP_PQUEUE** pqueue, /**< pointer to a priority queue */
1238 int initsize, /**< initial number of available element slots */
1239 SCIP_Real sizefac, /**< memory growing factor applied, if more element slots are needed */
1240 SCIP_DECL_SORTPTRCOMP((*ptrcomp)), /**< data element comparator */
1241 SCIP_DECL_PQUEUEELEMCHGPOS((*elemchgpos)) /**< callback to act on position change of elem in priority queue, or NULL */
1242 )
1243 {
1244 assert(pqueue != NULL);
1245 assert(ptrcomp != NULL);
1246
1247 initsize = MAX(1, initsize);
1248 sizefac = MAX(1.0, sizefac);
1249
1250 SCIP_ALLOC( BMSallocMemory(pqueue) );
1251 (*pqueue)->len = 0;
1252 (*pqueue)->size = 0;
1253 (*pqueue)->sizefac = sizefac;
1254 (*pqueue)->slots = NULL;
1255 (*pqueue)->ptrcomp = ptrcomp;
1256 (*pqueue)->elemchgpos = elemchgpos;
1257 SCIP_CALL( pqueueResize(*pqueue, initsize) );
1258
1259 return SCIP_OKAY;
1260 }
1261
1262 /** frees priority queue, but not the data elements themselves */
SCIPpqueueFree(SCIP_PQUEUE ** pqueue)1263 void SCIPpqueueFree(
1264 SCIP_PQUEUE** pqueue /**< pointer to a priority queue */
1265 )
1266 {
1267 assert(pqueue != NULL);
1268
1269 BMSfreeMemoryArray(&(*pqueue)->slots);
1270 BMSfreeMemory(pqueue);
1271 }
1272
1273 /** clears the priority queue, but doesn't free the data elements themselves */
SCIPpqueueClear(SCIP_PQUEUE * pqueue)1274 void SCIPpqueueClear(
1275 SCIP_PQUEUE* pqueue /**< priority queue */
1276 )
1277 {
1278 assert(pqueue != NULL);
1279
1280 pqueue->len = 0;
1281 }
1282
1283 /** assign element to new slot in priority queue */
1284 static
pqueueElemChgPos(SCIP_PQUEUE * pqueue,void * elem,int oldpos,int newpos)1285 void pqueueElemChgPos(
1286 SCIP_PQUEUE* pqueue, /**< priority queue */
1287 void* elem, /**< element whose position changes */
1288 int oldpos, /**< old position or -1 if elem is newly inserted */
1289 int newpos /**< new position */
1290 )
1291 {
1292 pqueue->slots[newpos] = elem;
1293
1294 /* act on position change */
1295 if( pqueue->elemchgpos != NULL )
1296 {
1297 pqueue->elemchgpos(elem, oldpos, newpos);
1298 }
1299 }
1300
1301 #ifdef SCIP_MORE_DEBUG
1302 /** ensure that the priority queue still has the heap property */
1303 static
pqueueHasHeapProperty(SCIP_PQUEUE * pqueue)1304 SCIP_Bool pqueueHasHeapProperty(
1305 SCIP_PQUEUE* pqueue /**< priority queue */
1306 )
1307 {
1308 int i;
1309
1310 if( SCIPpqueueNElems(pqueue) == 0 )
1311 return TRUE;
1312
1313 /* check local heap property between parents and children */
1314 for( i = 0; i < SCIPpqueueNElems(pqueue); ++i )
1315 {
1316 if( i > 0 && pqueue->ptrcomp(pqueue->slots[i], pqueue->slots[PQ_PARENT(i)]) < 0 )
1317 return FALSE;
1318 if( i < PQ_PARENT(SCIPpqueueNElems(pqueue)) )
1319 {
1320 int leftchild = PQ_LEFTCHILD(i);
1321 int rightchild = PQ_RIGHTCHILD(i);
1322 assert(leftchild < SCIPpqueueNElems(pqueue));
1323 assert(rightchild <= SCIPpqueueNElems(pqueue));
1324 if( pqueue->ptrcomp(pqueue->slots[i], pqueue->slots[leftchild]) > 0 )
1325 return FALSE;
1326 if( rightchild < SCIPpqueueNElems(pqueue) && pqueue->ptrcomp(pqueue->slots[i], pqueue->slots[rightchild]) > 0)
1327 return FALSE;
1328 }
1329 }
1330 return TRUE;
1331 }
1332 #endif
1333
1334 /** inserts element into priority queue */
SCIPpqueueInsert(SCIP_PQUEUE * pqueue,void * elem)1335 SCIP_RETCODE SCIPpqueueInsert(
1336 SCIP_PQUEUE* pqueue, /**< priority queue */
1337 void* elem /**< element to be inserted */
1338 )
1339 {
1340 int pos;
1341 int parentpos;
1342
1343 assert(pqueue != NULL);
1344 assert(pqueue->len >= 0);
1345 assert(elem != NULL);
1346
1347 SCIP_CALL( pqueueResize(pqueue, pqueue->len+1) );
1348
1349 /* insert element as leaf in the tree, move it towards the root as long it is better than its parent */
1350 pos = pqueue->len;
1351 pqueue->len++;
1352 parentpos = PQ_PARENT(pos);
1353 while( pos > 0 && (*pqueue->ptrcomp)(elem, pqueue->slots[parentpos]) < 0 )
1354 {
1355 assert((*pqueue->ptrcomp)(pqueue->slots[parentpos], elem) >= 0);
1356 pqueueElemChgPos(pqueue, pqueue->slots[parentpos], parentpos, pos);
1357
1358 pos = parentpos;
1359 parentpos = PQ_PARENT(pos);
1360 }
1361
1362 /* insert element at the found position */
1363 pqueueElemChgPos(pqueue, elem, -1, pos);
1364
1365 #ifdef SCIP_MORE_DEBUG
1366 assert(pqueueHasHeapProperty(pqueue));
1367 #endif
1368
1369 return SCIP_OKAY;
1370 }
1371
1372
1373 /** delete element at specified position, maintaining the heap property */
SCIPpqueueDelPos(SCIP_PQUEUE * pqueue,int pos)1374 void SCIPpqueueDelPos(
1375 SCIP_PQUEUE* pqueue, /**< priority queue */
1376 int pos /**< position of element that should be deleted */
1377 )
1378 {
1379 void* last;
1380
1381 assert(pqueue != NULL);
1382 assert(pos >= 0);
1383 assert(pos < SCIPpqueueNElems(pqueue));
1384
1385 /* remove element at specified position of the tree, move the better child to its parents position until the last element
1386 * of the queue could be placed in the empty slot
1387 */
1388 pqueue->len--;
1389
1390 /* everything in place */
1391 if( pos == pqueue->len )
1392 return;
1393
1394 last = pqueue->slots[pqueue->len];
1395
1396 /* last element is brought to pos. it may now violate the heap property compared to its parent, or to its children.
1397 * In the first case, move it up, otherwise, move it down.
1398 */
1399 while( pos > 0 && (*pqueue->ptrcomp)(last, pqueue->slots[PQ_PARENT(pos)]) < 0 )
1400 {
1401 pqueueElemChgPos(pqueue, pqueue->slots[PQ_PARENT(pos)], PQ_PARENT(pos), pos);
1402 pos = PQ_PARENT(pos);
1403 }
1404
1405 while( pos <= PQ_PARENT(pqueue->len-1) )
1406 {
1407 int childpos = PQ_LEFTCHILD(pos);
1408 int brotherpos = PQ_RIGHTCHILD(pos);
1409
1410 /* determine better of the two children */
1411 if( brotherpos < pqueue->len && (*pqueue->ptrcomp)(pqueue->slots[brotherpos], pqueue->slots[childpos]) < 0 )
1412 childpos = brotherpos;
1413
1414 if( (*pqueue->ptrcomp)(last, pqueue->slots[childpos]) <= 0 )
1415 break;
1416
1417 /* move better element from childpos to pos */
1418 pqueueElemChgPos(pqueue, pqueue->slots[childpos], childpos, pos);
1419
1420 pos = childpos;
1421 }
1422
1423 /* pos must point into a valid position */
1424 assert(pos <= pqueue->len - 1);
1425
1426 pqueueElemChgPos(pqueue, last, pqueue->len, pos);
1427
1428 #ifdef SCIP_MORE_DEBUG
1429 assert(pqueueHasHeapProperty(pqueue));
1430 #endif
1431 }
1432
1433 /** removes and returns best element from the priority queue */
SCIPpqueueRemove(SCIP_PQUEUE * pqueue)1434 void* SCIPpqueueRemove(
1435 SCIP_PQUEUE* pqueue /**< priority queue */
1436 )
1437 {
1438 void* root;
1439
1440 assert(pqueue != NULL);
1441 assert(pqueue->len >= 0);
1442
1443 if( pqueue->len == 0 )
1444 return NULL;
1445
1446 root = pqueue->slots[0];
1447
1448 SCIPpqueueDelPos(pqueue, 0);
1449
1450 return root;
1451 }
1452
1453 /** returns the best element of the queue without removing it */
SCIPpqueueFirst(SCIP_PQUEUE * pqueue)1454 void* SCIPpqueueFirst(
1455 SCIP_PQUEUE* pqueue /**< priority queue */
1456 )
1457 {
1458 assert(pqueue != NULL);
1459 assert(pqueue->len >= 0);
1460
1461 if( pqueue->len == 0 )
1462 return NULL;
1463
1464 return pqueue->slots[0];
1465 }
1466
1467 /** returns the number of elements in the queue */
SCIPpqueueNElems(SCIP_PQUEUE * pqueue)1468 int SCIPpqueueNElems(
1469 SCIP_PQUEUE* pqueue /**< priority queue */
1470 )
1471 {
1472 assert(pqueue != NULL);
1473 assert(pqueue->len >= 0);
1474
1475 return pqueue->len;
1476 }
1477
1478 /** returns the elements of the queue; changing the returned array may destroy the queue's ordering! */
SCIPpqueueElems(SCIP_PQUEUE * pqueue)1479 void** SCIPpqueueElems(
1480 SCIP_PQUEUE* pqueue /**< priority queue */
1481 )
1482 {
1483 assert(pqueue != NULL);
1484 assert(pqueue->len >= 0);
1485
1486 return pqueue->slots;
1487 }
1488
1489 /** return the position of @p elem in the priority queue, or -1 if element is not found */
SCIPpqueueFind(SCIP_PQUEUE * pqueue,void * elem)1490 int SCIPpqueueFind(
1491 SCIP_PQUEUE* pqueue, /**< priority queue */
1492 void* elem /**< element to be inserted */
1493 )
1494 {
1495 int pos = -1;
1496
1497 while( ++pos < SCIPpqueueNElems(pqueue) )
1498 {
1499 if( pqueue->slots[pos] == elem )
1500 return pos;
1501 }
1502
1503 return -1;
1504 }
1505
1506
1507
1508
1509 /*
1510 * Hash Table
1511 */
1512
1513 /** table of some prime numbers */
1514 static int primetable[] = {
1515 2,
1516 7,
1517 19,
1518 31,
1519 59,
1520 227,
1521 617,
1522 1523,
1523 3547,
1524 8011,
1525 17707,
1526 38723,
1527 83833,
1528 180317,
1529 385897,
1530 821411,
1531 1742369,
1532 3680893,
1533 5693959,
1534 7753849,
1535 9849703,
1536 11973277,
1537 14121853,
1538 17643961,
1539 24273817,
1540 32452843,
1541 49979687,
1542 67867967,
1543 86028121,
1544 104395301,
1545 122949823,
1546 141650939,
1547 160481183,
1548 179424673,
1549 198491317,
1550 217645177,
1551 256203161,
1552 314606869,
1553 373587883,
1554 433024223,
1555 492876847,
1556 553105243,
1557 613651349,
1558 694847533,
1559 756065159,
1560 817504243,
1561 879190747,
1562 941083981,
1563 982451653,
1564 INT_MAX
1565 };
1566 static const int primetablesize = sizeof(primetable)/sizeof(int);
1567
1568 /** simple and fast 2-universal hash function using multiply and shift */
1569 static
hashvalue(uint64_t input)1570 uint32_t hashvalue(
1571 uint64_t input /**< key value */
1572 )
1573 {
1574 return ( (uint32_t) ((UINT64_C(0x9e3779b97f4a7c15) * input)>>32) ) | 1u;
1575 }
1576
1577 /** returns a reasonable hash table size (a prime number) that is at least as large as the specified value */
SCIPcalcMultihashSize(int minsize)1578 int SCIPcalcMultihashSize(
1579 int minsize /**< minimal size of the hash table */
1580 )
1581 {
1582 int pos;
1583
1584 (void) SCIPsortedvecFindInt(primetable, minsize, primetablesize, &pos);
1585 assert(0 <= pos && pos < primetablesize);
1586
1587 return primetable[pos];
1588 }
1589
1590 /** appends element to the multihash list */
1591 static
multihashlistAppend(SCIP_MULTIHASHLIST ** multihashlist,BMS_BLKMEM * blkmem,void * element)1592 SCIP_RETCODE multihashlistAppend(
1593 SCIP_MULTIHASHLIST** multihashlist, /**< pointer to hash list */
1594 BMS_BLKMEM* blkmem, /**< block memory */
1595 void* element /**< element to append to the list */
1596 )
1597 {
1598 SCIP_MULTIHASHLIST* newlist;
1599
1600 assert(multihashlist != NULL);
1601 assert(blkmem != NULL);
1602 assert(element != NULL);
1603
1604 SCIP_ALLOC( BMSallocBlockMemory(blkmem, &newlist) );
1605 newlist->element = element;
1606 newlist->next = *multihashlist;
1607 *multihashlist = newlist;
1608
1609 return SCIP_OKAY;
1610 }
1611
1612 /** frees a multihash list entry and all its successors */
1613 static
multihashlistFree(SCIP_MULTIHASHLIST ** multihashlist,BMS_BLKMEM * blkmem)1614 void multihashlistFree(
1615 SCIP_MULTIHASHLIST** multihashlist, /**< pointer to multihash list to free */
1616 BMS_BLKMEM* blkmem /**< block memory */
1617 )
1618 {
1619 SCIP_MULTIHASHLIST* list;
1620 SCIP_MULTIHASHLIST* nextlist;
1621
1622 assert(multihashlist != NULL);
1623 assert(blkmem != NULL);
1624
1625 list = *multihashlist;
1626 while( list != NULL )
1627 {
1628 nextlist = list->next;
1629 BMSfreeBlockMemory(blkmem, &list);
1630 list = nextlist;
1631 }
1632
1633 *multihashlist = NULL;
1634 }
1635
1636 /** finds multihash list entry pointing to element with given key in the multihash list, returns NULL if not found */
1637 static
multihashlistFind(SCIP_MULTIHASHLIST * multihashlist,SCIP_DECL_HASHGETKEY ((* hashgetkey)),SCIP_DECL_HASHKEYEQ ((* hashkeyeq)),SCIP_DECL_HASHKEYVAL ((* hashkeyval)),void * userptr,uint64_t keyval,void * key)1638 SCIP_MULTIHASHLIST* multihashlistFind(
1639 SCIP_MULTIHASHLIST* multihashlist, /**< multihash list */
1640 SCIP_DECL_HASHGETKEY((*hashgetkey)), /**< gets the key of the given element */
1641 SCIP_DECL_HASHKEYEQ ((*hashkeyeq)), /**< returns TRUE iff both keys are equal */
1642 SCIP_DECL_HASHKEYVAL((*hashkeyval)), /**< returns the hash value of the key */
1643 void* userptr, /**< user pointer */
1644 uint64_t keyval, /**< hash value of key */
1645 void* key /**< key to retrieve */
1646 )
1647 {
1648 uint64_t currentkeyval;
1649 void* currentkey;
1650
1651 assert(hashkeyeq != NULL);
1652 assert(key != NULL);
1653
1654 while( multihashlist != NULL )
1655 {
1656 currentkey = hashgetkey(userptr, multihashlist->element);
1657 currentkeyval = hashkeyval(userptr, currentkey);
1658 if( currentkeyval == keyval && hashkeyeq(userptr, currentkey, key) )
1659 return multihashlist;
1660
1661 multihashlist = multihashlist->next;
1662 }
1663
1664 return NULL;
1665 }
1666
1667 /** retrieves element with given key from the multihash list, or NULL */
1668 static
multihashlistRetrieve(SCIP_MULTIHASHLIST * multihashlist,SCIP_DECL_HASHGETKEY ((* hashgetkey)),SCIP_DECL_HASHKEYEQ ((* hashkeyeq)),SCIP_DECL_HASHKEYVAL ((* hashkeyval)),void * userptr,uint64_t keyval,void * key)1669 void* multihashlistRetrieve(
1670 SCIP_MULTIHASHLIST* multihashlist, /**< hash list */
1671 SCIP_DECL_HASHGETKEY((*hashgetkey)), /**< gets the key of the given element */
1672 SCIP_DECL_HASHKEYEQ ((*hashkeyeq)), /**< returns TRUE iff both keys are equal */
1673 SCIP_DECL_HASHKEYVAL((*hashkeyval)), /**< returns the hash value of the key */
1674 void* userptr, /**< user pointer */
1675 uint64_t keyval, /**< hash value of key */
1676 void* key /**< key to retrieve */
1677 )
1678 {
1679 SCIP_MULTIHASHLIST* h;
1680
1681 /* find hash list entry */
1682 h = multihashlistFind(multihashlist, hashgetkey, hashkeyeq, hashkeyval, userptr, keyval, key);
1683
1684 /* return element */
1685 if( h != NULL )
1686 {
1687 #ifndef NDEBUG
1688 SCIP_MULTIHASHLIST* h2;
1689
1690 h2 = multihashlistFind(h->next, hashgetkey, hashkeyeq, hashkeyval, userptr, keyval, key);
1691
1692 if( h2 != NULL )
1693 {
1694 void* key1;
1695 void* key2;
1696
1697 key1 = hashgetkey(userptr, h->element);
1698 key2 = hashgetkey(userptr, h2->element);
1699 assert(hashkeyval(userptr, key1) == hashkeyval(userptr, key2));
1700
1701 if( hashkeyeq(userptr, key1, key2) )
1702 {
1703 SCIPerrorMessage("WARNING: hashkey with same value exists multiple times (e.g. duplicate constraint/variable names), so the return value is maybe not correct\n");
1704 }
1705 }
1706 #endif
1707
1708 return h->element;
1709 }
1710 else
1711 return NULL;
1712 }
1713
1714
1715 /** retrieves element with given key from the multihash list, or NULL
1716 * returns pointer to multihash table list entry
1717 */
1718 static
multihashlistRetrieveNext(SCIP_MULTIHASHLIST ** multihashlist,SCIP_DECL_HASHGETKEY ((* hashgetkey)),SCIP_DECL_HASHKEYEQ ((* hashkeyeq)),SCIP_DECL_HASHKEYVAL ((* hashkeyval)),void * userptr,uint64_t keyval,void * key)1719 void* multihashlistRetrieveNext(
1720 SCIP_MULTIHASHLIST** multihashlist, /**< on input: hash list to search; on exit: hash list entry corresponding
1721 * to element after retrieved one, or NULL */
1722 SCIP_DECL_HASHGETKEY((*hashgetkey)), /**< gets the key of the given element */
1723 SCIP_DECL_HASHKEYEQ ((*hashkeyeq)), /**< returns TRUE iff both keys are equal */
1724 SCIP_DECL_HASHKEYVAL((*hashkeyval)), /**< returns the hash value of the key */
1725 void* userptr, /**< user pointer */
1726 uint64_t keyval, /**< hash value of key */
1727 void* key /**< key to retrieve */
1728 )
1729 {
1730 SCIP_MULTIHASHLIST* h;
1731
1732 assert(multihashlist != NULL);
1733
1734 /* find hash list entry */
1735 h = multihashlistFind(*multihashlist, hashgetkey, hashkeyeq, hashkeyval, userptr, keyval, key);
1736
1737 /* return element */
1738 if( h != NULL )
1739 {
1740 *multihashlist = h->next;
1741
1742 return h->element;
1743 }
1744
1745 *multihashlist = NULL;
1746
1747 return NULL;
1748 }
1749
1750 /** removes element from the multihash list */
1751 static
multihashlistRemove(SCIP_MULTIHASHLIST ** multihashlist,BMS_BLKMEM * blkmem,void * element)1752 SCIP_Bool multihashlistRemove(
1753 SCIP_MULTIHASHLIST** multihashlist, /**< pointer to hash list */
1754 BMS_BLKMEM* blkmem, /**< block memory */
1755 void* element /**< element to remove from the list */
1756 )
1757 {
1758 SCIP_MULTIHASHLIST* nextlist;
1759
1760 assert(multihashlist != NULL);
1761 assert(blkmem != NULL);
1762 assert(element != NULL);
1763
1764 while( *multihashlist != NULL && (*multihashlist)->element != element )
1765 multihashlist = &(*multihashlist)->next;
1766
1767 if( *multihashlist != NULL )
1768 {
1769 nextlist = (*multihashlist)->next;
1770 BMSfreeBlockMemory(blkmem, multihashlist);
1771 *multihashlist = nextlist;
1772
1773 return TRUE;
1774 }
1775
1776 return FALSE;
1777 }
1778
1779 #define SCIP_MULTIHASH_MAXSIZE 33554431 /* 2^25 - 1*/
1780 #define SCIP_MULTIHASH_RESIZE_PERCENTAGE 65
1781 #define SCIP_MULTIHASH_GROW_FACTOR 1.31
1782
1783 /** resizing(increasing) the given multihash */
1784 static
multihashResize(SCIP_MULTIHASH * multihash)1785 SCIP_RETCODE multihashResize(
1786 SCIP_MULTIHASH* multihash /**< hash table */
1787 )
1788 {
1789 SCIP_MULTIHASHLIST** newlists;
1790 SCIP_MULTIHASHLIST* multihashlist;
1791 SCIP_Longint nelements;
1792 int nnewlists;
1793 int l;
1794
1795 assert(multihash != NULL);
1796 assert(multihash->lists != NULL);
1797 assert(multihash->nlists > 0);
1798 assert(multihash->hashgetkey != NULL);
1799 assert(multihash->hashkeyeq != NULL);
1800 assert(multihash->hashkeyval != NULL);
1801
1802 /* get new memeory for hash table lists */
1803 nnewlists = (int) MIN((unsigned int)(multihash->nlists * SCIP_MULTIHASH_GROW_FACTOR), SCIP_MULTIHASH_MAXSIZE);
1804 nnewlists = MAX(nnewlists, multihash->nlists);
1805
1806 SCIPdebugMessage("load = %g, nelements = %" SCIP_LONGINT_FORMAT ", nlists = %d, nnewlist = %d\n", SCIPmultihashGetLoad(multihash), multihash->nelements, multihash->nlists, nnewlists);
1807
1808 if( nnewlists > multihash->nlists )
1809 {
1810 SCIP_Bool onlyone;
1811 void* key;
1812 uint64_t keyval;
1813 unsigned int hashval;
1814
1815 SCIP_ALLOC( BMSallocClearBlockMemoryArray(multihash->blkmem, &newlists, nnewlists) );
1816
1817 /* move all lists */
1818 for( l = multihash->nlists - 1; l >= 0; --l )
1819 {
1820 multihashlist = multihash->lists[l];
1821 onlyone = TRUE;
1822
1823 /* move all elements frmm the old lists into the new lists */
1824 while( multihashlist != NULL )
1825 {
1826 /* get the hash key and its hash value */
1827 key = multihash->hashgetkey(multihash->userptr, multihashlist->element);
1828 keyval = multihash->hashkeyval(multihash->userptr, key);
1829 hashval = (unsigned int) (keyval % (unsigned) nnewlists); /*lint !e573*/
1830
1831 /* if the old hash table list consists of only one entry, we still can use this old memory block instead
1832 * of creating a new one
1833 */
1834 if( multihashlist->next == NULL && onlyone )
1835 {
1836 /* the new list is also empty, we can directly copy the entry */
1837 if( newlists[hashval] == NULL )
1838 newlists[hashval] = multihashlist;
1839 /* the new list is not empty, so we need to find the first empty spot */
1840 else
1841 {
1842 SCIP_MULTIHASHLIST* lastnext = newlists[hashval];
1843 SCIP_MULTIHASHLIST* next = lastnext->next;
1844
1845 while( next != NULL )
1846 {
1847 lastnext = next;
1848 next = next->next;
1849 }
1850
1851 lastnext->next = multihashlist;
1852 }
1853
1854 multihash->lists[l] = NULL;
1855 }
1856 else
1857 {
1858 /* append old element to the list at the hash position */
1859 SCIP_CALL( multihashlistAppend(&(newlists[hashval]), multihash->blkmem, multihashlist->element) );
1860 }
1861
1862 onlyone = FALSE;
1863 multihashlist = multihashlist->next;
1864 }
1865 }
1866
1867 /* remember number of elements */
1868 nelements = multihash->nelements;
1869 /* clear old lists */
1870 SCIPmultihashRemoveAll(multihash);
1871 /* free old lists */
1872 BMSfreeBlockMemoryArray(multihash->blkmem, &(multihash->lists), multihash->nlists);
1873
1874 /* set new data */
1875 multihash->lists = newlists;
1876 multihash->nlists = nnewlists;
1877 multihash->nelements = nelements;
1878
1879 #ifdef SCIP_MORE_DEBUG
1880 {
1881 SCIP_Longint sumslotsize = 0;
1882
1883 for( l = 0; l < multihash->nlists; ++l )
1884 {
1885 multihashlist = multihash->lists[l];
1886 while( multihashlist != NULL )
1887 {
1888 sumslotsize++;
1889 multihashlist = multihashlist->next;
1890 }
1891 }
1892 assert(sumslotsize == multihash->nelements);
1893 }
1894 #endif
1895 }
1896
1897 return SCIP_OKAY;
1898 }
1899
1900 /** creates a multihash table */
SCIPmultihashCreate(SCIP_MULTIHASH ** multihash,BMS_BLKMEM * blkmem,int tablesize,SCIP_DECL_HASHGETKEY ((* hashgetkey)),SCIP_DECL_HASHKEYEQ ((* hashkeyeq)),SCIP_DECL_HASHKEYVAL ((* hashkeyval)),void * userptr)1901 SCIP_RETCODE SCIPmultihashCreate(
1902 SCIP_MULTIHASH** multihash, /**< pointer to store the created multihash table */
1903 BMS_BLKMEM* blkmem, /**< block memory used to store multihash table entries */
1904 int tablesize, /**< size of the hash table */
1905 SCIP_DECL_HASHGETKEY((*hashgetkey)), /**< gets the key of the given element */
1906 SCIP_DECL_HASHKEYEQ ((*hashkeyeq)), /**< returns TRUE iff both keys are equal */
1907 SCIP_DECL_HASHKEYVAL((*hashkeyval)), /**< returns the hash value of the key */
1908 void* userptr /**< user pointer */
1909 )
1910 {
1911 /* only assert non negative to catch overflow errors
1912 * but not zeros due to integer divison
1913 */
1914 assert(tablesize >= 0);
1915 assert(multihash != NULL);
1916 assert(hashgetkey != NULL);
1917 assert(hashkeyeq != NULL);
1918 assert(hashkeyval != NULL);
1919
1920 SCIP_ALLOC( BMSallocBlockMemory(blkmem, multihash) );
1921 SCIP_ALLOC( BMSallocClearBlockMemoryArray(blkmem, &(*multihash)->lists, tablesize) );
1922 (*multihash)->blkmem = blkmem;
1923 (*multihash)->nlists = tablesize;
1924 (*multihash)->hashgetkey = hashgetkey;
1925 (*multihash)->hashkeyeq = hashkeyeq;
1926 (*multihash)->hashkeyval = hashkeyval;
1927 (*multihash)->userptr = userptr;
1928 (*multihash)->nelements = 0;
1929
1930 return SCIP_OKAY;
1931 }
1932
1933 /** frees the multihash table */
SCIPmultihashFree(SCIP_MULTIHASH ** multihash)1934 void SCIPmultihashFree(
1935 SCIP_MULTIHASH** multihash /**< pointer to the multihash table */
1936 )
1937 {
1938 int i;
1939 SCIP_MULTIHASH* table;
1940 BMS_BLKMEM* blkmem;
1941 SCIP_MULTIHASHLIST** lists;
1942
1943 assert(multihash != NULL);
1944 assert(*multihash != NULL);
1945
1946 table = (*multihash);
1947 blkmem = table->blkmem;
1948 lists = table->lists;
1949
1950 /* free hash lists */
1951 for( i = table->nlists - 1; i >= 0; --i )
1952 multihashlistFree(&lists[i], blkmem);
1953
1954 /* free main hash table data structure */
1955 BMSfreeBlockMemoryArray(blkmem, &table->lists, table->nlists);
1956 BMSfreeBlockMemory(blkmem, multihash);
1957 }
1958
1959
1960 /** inserts element in multihash table (multiple inserts of same element possible)
1961 *
1962 * @note A pointer to a multihashlist returned by SCIPmultihashRetrieveNext() might get invalid when adding an element
1963 * to the hash table, due to dynamic resizing.
1964 */
SCIPmultihashInsert(SCIP_MULTIHASH * multihash,void * element)1965 SCIP_RETCODE SCIPmultihashInsert(
1966 SCIP_MULTIHASH* multihash, /**< multihash table */
1967 void* element /**< element to insert into the table */
1968 )
1969 {
1970 void* key;
1971 uint64_t keyval;
1972 unsigned int hashval;
1973
1974 assert(multihash != NULL);
1975 assert(multihash->lists != NULL);
1976 assert(multihash->nlists > 0);
1977 assert(multihash->hashgetkey != NULL);
1978 assert(multihash->hashkeyeq != NULL);
1979 assert(multihash->hashkeyval != NULL);
1980 assert(element != NULL);
1981
1982 /* dynamically resizing the hashtables */
1983 if( SCIPmultihashGetLoad(multihash) > SCIP_MULTIHASH_RESIZE_PERCENTAGE )
1984 {
1985 SCIP_CALL( multihashResize(multihash) );
1986 }
1987
1988 /* get the hash key and its hash value */
1989 key = multihash->hashgetkey(multihash->userptr, element);
1990 keyval = multihash->hashkeyval(multihash->userptr, key);
1991 hashval = (unsigned int) (keyval % (unsigned) multihash->nlists); /*lint !e573*/
1992
1993 /* append element to the list at the hash position */
1994 SCIP_CALL( multihashlistAppend(&multihash->lists[hashval], multihash->blkmem, element) );
1995
1996 ++(multihash->nelements);
1997
1998 return SCIP_OKAY;
1999 }
2000
2001 /** inserts element in multihash table (multiple insertion of same element is checked and results in an error)
2002 *
2003 * @note A pointer to a multihashlist returned by SCIPmultihashRetrieveNext() might get invalid when adding a new
2004 * element to the multihash table, due to dynamic resizing.
2005 */
SCIPmultihashSafeInsert(SCIP_MULTIHASH * multihash,void * element)2006 SCIP_RETCODE SCIPmultihashSafeInsert(
2007 SCIP_MULTIHASH* multihash, /**< multihash table */
2008 void* element /**< element to insert into the table */
2009 )
2010 {
2011 assert(multihash != NULL);
2012 assert(multihash->hashgetkey != NULL);
2013
2014 /* check, if key is already existing */
2015 if( SCIPmultihashRetrieve(multihash, multihash->hashgetkey(multihash->userptr, element)) != NULL )
2016 return SCIP_KEYALREADYEXISTING;
2017
2018 /* insert element in hash table */
2019 SCIP_CALL( SCIPmultihashInsert(multihash, element) );
2020
2021 return SCIP_OKAY;
2022 }
2023
2024 /** retrieve element with key from multihash table, returns NULL if not existing */
SCIPmultihashRetrieve(SCIP_MULTIHASH * multihash,void * key)2025 void* SCIPmultihashRetrieve(
2026 SCIP_MULTIHASH* multihash, /**< multihash table */
2027 void* key /**< key to retrieve */
2028 )
2029 {
2030 uint64_t keyval;
2031 unsigned int hashval;
2032
2033 assert(multihash != NULL);
2034 assert(multihash->lists != NULL);
2035 assert(multihash->nlists > 0);
2036 assert(multihash->hashgetkey != NULL);
2037 assert(multihash->hashkeyeq != NULL);
2038 assert(multihash->hashkeyval != NULL);
2039 assert(key != NULL);
2040
2041 /* get the hash value of the key */
2042 keyval = multihash->hashkeyval(multihash->userptr, key);
2043 hashval = (unsigned int) (keyval % (unsigned) multihash->nlists); /*lint !e573*/
2044
2045 return multihashlistRetrieve(multihash->lists[hashval], multihash->hashgetkey, multihash->hashkeyeq,
2046 multihash->hashkeyval, multihash->userptr, keyval, key);
2047 }
2048
2049 /** retrieve element with key from multihash table, returns NULL if not existing
2050 * can be used to retrieve all entries with the same key (one-by-one)
2051 *
2052 * @note The returned multimultihashlist pointer might get invalid when adding a new element to the multihash table.
2053 */
SCIPmultihashRetrieveNext(SCIP_MULTIHASH * multihash,SCIP_MULTIHASHLIST ** multihashlist,void * key)2054 void* SCIPmultihashRetrieveNext(
2055 SCIP_MULTIHASH* multihash, /**< multihash table */
2056 SCIP_MULTIHASHLIST** multihashlist, /**< input: entry in hash table list from which to start searching, or NULL
2057 * output: entry in hash table list corresponding to element after
2058 * retrieved one, or NULL */
2059 void* key /**< key to retrieve */
2060 )
2061 {
2062 uint64_t keyval;
2063
2064 assert(multihash != NULL);
2065 assert(multihash->lists != NULL);
2066 assert(multihash->nlists > 0);
2067 assert(multihash->hashgetkey != NULL);
2068 assert(multihash->hashkeyeq != NULL);
2069 assert(multihash->hashkeyval != NULL);
2070 assert(multihashlist != NULL);
2071 assert(key != NULL);
2072
2073 keyval = multihash->hashkeyval(multihash->userptr, key);
2074
2075 if( *multihashlist == NULL )
2076 {
2077 unsigned int hashval;
2078
2079 /* get the hash value of the key */
2080 hashval = (unsigned int) (keyval % (unsigned) multihash->nlists); /*lint !e573*/
2081
2082 *multihashlist = multihash->lists[hashval];
2083 }
2084
2085 return multihashlistRetrieveNext(multihashlist, multihash->hashgetkey, multihash->hashkeyeq,
2086 multihash->hashkeyval, multihash->userptr, keyval, key);
2087 }
2088
2089 /** returns whether the given element exists in the multihash table */
SCIPmultihashExists(SCIP_MULTIHASH * multihash,void * element)2090 SCIP_Bool SCIPmultihashExists(
2091 SCIP_MULTIHASH* multihash, /**< multihash table */
2092 void* element /**< element to search in the table */
2093 )
2094 {
2095 void* key;
2096 uint64_t keyval;
2097 unsigned int hashval;
2098
2099 assert(multihash != NULL);
2100 assert(multihash->lists != NULL);
2101 assert(multihash->nlists > 0);
2102 assert(multihash->hashgetkey != NULL);
2103 assert(multihash->hashkeyeq != NULL);
2104 assert(multihash->hashkeyval != NULL);
2105 assert(element != NULL);
2106
2107 /* get the hash key and its hash value */
2108 key = multihash->hashgetkey(multihash->userptr, element);
2109 keyval = multihash->hashkeyval(multihash->userptr, key);
2110 hashval = (unsigned int) (keyval % (unsigned) multihash->nlists); /*lint !e573*/
2111
2112 return (multihashlistFind(multihash->lists[hashval], multihash->hashgetkey, multihash->hashkeyeq,
2113 multihash->hashkeyval, multihash->userptr, keyval, key) != NULL);
2114 }
2115
2116 /** removes element from the multihash table, if it exists */
SCIPmultihashRemove(SCIP_MULTIHASH * multihash,void * element)2117 SCIP_RETCODE SCIPmultihashRemove(
2118 SCIP_MULTIHASH* multihash, /**< multihash table */
2119 void* element /**< element to remove from the table */
2120 )
2121 {
2122 void* key;
2123 uint64_t keyval;
2124 unsigned int hashval;
2125
2126 assert(multihash != NULL);
2127 assert(multihash->lists != NULL);
2128 assert(multihash->nlists > 0);
2129 assert(multihash->hashgetkey != NULL);
2130 assert(multihash->hashkeyeq != NULL);
2131 assert(multihash->hashkeyval != NULL);
2132 assert(element != NULL);
2133
2134 /* get the hash key and its hash value */
2135 key = multihash->hashgetkey(multihash->userptr, element);
2136 keyval = multihash->hashkeyval(multihash->userptr, key);
2137 hashval = (unsigned int) (keyval % (unsigned) multihash->nlists); /*lint !e573*/
2138
2139 /* remove element from the list at the hash position */
2140 if( multihashlistRemove(&multihash->lists[hashval], multihash->blkmem, element) )
2141 --(multihash->nelements);
2142
2143 return SCIP_OKAY;
2144 }
2145
2146 /** removes all elements of the multihash table
2147 *
2148 * @note From a performance point of view you should not fill and clear a hash table too often since the clearing can
2149 * be expensive. Clearing is done by looping over all buckets and removing the hash table lists one-by-one.
2150 */
SCIPmultihashRemoveAll(SCIP_MULTIHASH * multihash)2151 void SCIPmultihashRemoveAll(
2152 SCIP_MULTIHASH* multihash /**< multihash table */
2153 )
2154 {
2155 BMS_BLKMEM* blkmem;
2156 SCIP_MULTIHASHLIST** lists;
2157 int i;
2158
2159 assert(multihash != NULL);
2160
2161 blkmem = multihash->blkmem;
2162 lists = multihash->lists;
2163
2164 /* free hash lists */
2165 for( i = multihash->nlists - 1; i >= 0; --i )
2166 multihashlistFree(&lists[i], blkmem);
2167
2168 multihash->nelements = 0;
2169 }
2170
2171 /** returns number of multihash table elements */
SCIPmultihashGetNElements(SCIP_MULTIHASH * multihash)2172 SCIP_Longint SCIPmultihashGetNElements(
2173 SCIP_MULTIHASH* multihash /**< multihash table */
2174 )
2175 {
2176 assert(multihash != NULL);
2177
2178 return multihash->nelements;
2179 }
2180
2181 /** returns the load of the given multihash table in percentage */
SCIPmultihashGetLoad(SCIP_MULTIHASH * multihash)2182 SCIP_Real SCIPmultihashGetLoad(
2183 SCIP_MULTIHASH* multihash /**< multihash table */
2184 )
2185 {
2186 assert(multihash != NULL);
2187
2188 return ((SCIP_Real)(multihash->nelements) / (multihash->nlists) * 100.0);
2189 }
2190
2191 /** prints statistics about multihash table usage */
SCIPmultihashPrintStatistics(SCIP_MULTIHASH * multihash,SCIP_MESSAGEHDLR * messagehdlr)2192 void SCIPmultihashPrintStatistics(
2193 SCIP_MULTIHASH* multihash, /**< multihash table */
2194 SCIP_MESSAGEHDLR* messagehdlr /**< message handler */
2195 )
2196 {
2197 SCIP_MULTIHASHLIST* multihashlist;
2198 int usedslots;
2199 int maxslotsize;
2200 int sumslotsize;
2201 int slotsize;
2202 int i;
2203
2204 assert(multihash != NULL);
2205
2206 usedslots = 0;
2207 maxslotsize = 0;
2208 sumslotsize = 0;
2209 for( i = 0; i < multihash->nlists; ++i )
2210 {
2211 multihashlist = multihash->lists[i];
2212 if( multihashlist != NULL )
2213 {
2214 usedslots++;
2215 slotsize = 0;
2216 while( multihashlist != NULL )
2217 {
2218 slotsize++;
2219 multihashlist = multihashlist->next;
2220 }
2221 maxslotsize = MAX(maxslotsize, slotsize);
2222 sumslotsize += slotsize;
2223 }
2224 }
2225 assert(sumslotsize == multihash->nelements);
2226
2227 SCIPmessagePrintInfo(messagehdlr, "%" SCIP_LONGINT_FORMAT " multihash entries, used %d/%d slots (%.1f%%)",
2228 multihash->nelements, usedslots, multihash->nlists, 100.0*(SCIP_Real)usedslots/(SCIP_Real)(multihash->nlists));
2229 if( usedslots > 0 )
2230 SCIPmessagePrintInfo(messagehdlr, ", avg. %.1f entries/used slot, max. %d entries in slot",
2231 (SCIP_Real)(multihash->nelements)/(SCIP_Real)usedslots, maxslotsize);
2232 SCIPmessagePrintInfo(messagehdlr, "\n");
2233 }
2234
2235 /** creates a hash table */
SCIPhashtableCreate(SCIP_HASHTABLE ** hashtable,BMS_BLKMEM * blkmem,int tablesize,SCIP_DECL_HASHGETKEY ((* hashgetkey)),SCIP_DECL_HASHKEYEQ ((* hashkeyeq)),SCIP_DECL_HASHKEYVAL ((* hashkeyval)),void * userptr)2236 SCIP_RETCODE SCIPhashtableCreate(
2237 SCIP_HASHTABLE** hashtable, /**< pointer to store the created hash table */
2238 BMS_BLKMEM* blkmem, /**< block memory used to store hash table entries */
2239 int tablesize, /**< size of the hash table */
2240 SCIP_DECL_HASHGETKEY((*hashgetkey)), /**< gets the key of the given element */
2241 SCIP_DECL_HASHKEYEQ ((*hashkeyeq)), /**< returns TRUE iff both keys are equal */
2242 SCIP_DECL_HASHKEYVAL((*hashkeyval)), /**< returns the hash value of the key */
2243 void* userptr /**< user pointer */
2244 )
2245 {
2246 unsigned int nslots;
2247
2248 /* only assert non negative to catch overflow errors
2249 * but not zeros due to integer divison
2250 */
2251 assert(tablesize >= 0);
2252 assert(hashtable != NULL);
2253 assert(hashgetkey != NULL);
2254 assert(hashkeyeq != NULL);
2255 assert(hashkeyval != NULL);
2256 assert(blkmem != NULL);
2257
2258 SCIP_ALLOC( BMSallocBlockMemory(blkmem, hashtable) );
2259
2260 /* dont create too small hashtables, i.e. at least size 32, and increase
2261 * the given size by divinding it by 0.9, since then no rebuilding will
2262 * be necessary if the given number of elements are inserted. Finally round
2263 * to the next power of two.
2264 */
2265 (*hashtable)->shift = 32;
2266 (*hashtable)->shift -= (unsigned int)ceil(LOG2(MAX(32.0, tablesize / 0.9)));
2267
2268 /* compute size from shift */
2269 nslots = 1u << (32 - (*hashtable)->shift);
2270
2271 /* compute mask to do a fast modulo by nslots using bitwise and */
2272 (*hashtable)->mask = nslots - 1;
2273 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*hashtable)->slots, nslots) );
2274 SCIP_ALLOC( BMSallocClearBlockMemoryArray(blkmem, &(*hashtable)->hashes, nslots) );
2275 (*hashtable)->blkmem = blkmem;
2276 (*hashtable)->hashgetkey = hashgetkey;
2277 (*hashtable)->hashkeyeq = hashkeyeq;
2278 (*hashtable)->hashkeyval = hashkeyval;
2279 (*hashtable)->userptr = userptr;
2280 (*hashtable)->nelements = 0;
2281
2282 return SCIP_OKAY;
2283 }
2284
2285 /** frees the hash table */
SCIPhashtableFree(SCIP_HASHTABLE ** hashtable)2286 void SCIPhashtableFree(
2287 SCIP_HASHTABLE** hashtable /**< pointer to the hash table */
2288 )
2289 {
2290 uint32_t nslots;
2291 SCIP_HASHTABLE* table;
2292
2293 assert(hashtable != NULL);
2294 assert(*hashtable != NULL);
2295 table = *hashtable;
2296 nslots = (*hashtable)->mask + 1;
2297 #ifdef SCIP_DEBUG
2298 {
2299 uint32_t maxprobelen = 0;
2300 uint64_t probelensum = 0;
2301 uint32_t i;
2302
2303 assert(table != NULL);
2304
2305 for( i = 0; i < nslots; ++i )
2306 {
2307 if( table->hashes[i] != 0 )
2308 {
2309 uint32_t probelen = ((i + table->mask + 1 - (table->hashes[i]>>(table->shift))) & table->mask) + 1;
2310 probelensum += probelen;
2311 maxprobelen = MAX(probelen, maxprobelen);
2312 }
2313 }
2314
2315 SCIPdebugMessage("%u hash table entries, used %u/%u slots (%.1f%%)",
2316 (unsigned int)table->nelements, (unsigned int)table->nelements, (unsigned int)nslots,
2317 100.0*(SCIP_Real)table->nelements/(SCIP_Real)(nslots));
2318 if( table->nelements > 0 )
2319 SCIPdebugMessage(", avg. probe length is %.1f, max. probe length is %u",
2320 (SCIP_Real)(probelensum)/(SCIP_Real)table->nelements, (unsigned int)maxprobelen);
2321 SCIPdebugMessage("\n");
2322 }
2323 #endif
2324
2325 /* free main hash table data structure */
2326 BMSfreeBlockMemoryArray((*hashtable)->blkmem, &table->hashes, nslots);
2327 BMSfreeBlockMemoryArray((*hashtable)->blkmem, &table->slots, nslots);
2328 BMSfreeBlockMemory((*hashtable)->blkmem, hashtable);
2329 }
2330
2331 /** removes all elements of the hash table
2332 *
2333 * @note From a performance point of view you should not fill and clear a hash table too often since the clearing can
2334 * be expensive. Clearing is done by looping over all buckets and removing the hash table lists one-by-one.
2335 *
2336 * @deprecated Please use SCIPhashtableRemoveAll()
2337 */
SCIPhashtableClear(SCIP_HASHTABLE * hashtable)2338 void SCIPhashtableClear(
2339 SCIP_HASHTABLE* hashtable /**< hash table */
2340 )
2341 {
2342 SCIPhashtableRemoveAll(hashtable);
2343 }
2344
2345 /* computes the distance from it's desired position for the element stored at pos */
2346 #define ELEM_DISTANCE(pos) (((pos) + hashtable->mask + 1 - (hashtable->hashes[(pos)]>>(hashtable->shift))) & hashtable->mask)
2347
2348 /** inserts element in hash table (multiple inserts of same element overrides previous one) */
2349 static
hashtableInsert(SCIP_HASHTABLE * hashtable,void * element,void * key,uint32_t hashval,SCIP_Bool override)2350 SCIP_RETCODE hashtableInsert(
2351 SCIP_HASHTABLE* hashtable, /**< hash table */
2352 void* element, /**< element to insert into the table */
2353 void* key, /**< key of element */
2354 uint32_t hashval, /**< hash value of element */
2355 SCIP_Bool override /**< should element be overridden or an error be returned if already existing */
2356 )
2357 {
2358 uint32_t elemdistance;
2359 uint32_t pos;
2360 #ifndef NDEBUG
2361 SCIP_Bool swapped = FALSE;
2362 #endif
2363
2364 assert(hashtable != NULL);
2365 assert(hashtable->slots != NULL);
2366 assert(hashtable->hashes != NULL);
2367 assert(hashtable->mask > 0);
2368 assert(hashtable->hashgetkey != NULL);
2369 assert(hashtable->hashkeyeq != NULL);
2370 assert(hashtable->hashkeyval != NULL);
2371 assert(element != NULL);
2372
2373 pos = hashval>>(hashtable->shift);
2374 elemdistance = 0;
2375 while( TRUE ) /*lint !e716*/
2376 {
2377 uint32_t distance;
2378
2379 /* if position is empty or key equal insert element */
2380 if( hashtable->hashes[pos] == 0 )
2381 {
2382 hashtable->slots[pos] = element;
2383 hashtable->hashes[pos] = hashval;
2384 ++hashtable->nelements;
2385 return SCIP_OKAY;
2386 }
2387
2388 if( hashtable->hashes[pos] == hashval && hashtable->hashkeyeq(hashtable->userptr,
2389 hashtable->hashgetkey(hashtable->userptr, hashtable->slots[pos]), key) )
2390 {
2391 if( override )
2392 {
2393 #ifndef NDEBUG
2394 assert(! swapped);
2395 #endif
2396 hashtable->slots[pos] = element;
2397 hashtable->hashes[pos] = hashval;
2398 return SCIP_OKAY;
2399 }
2400 else
2401 {
2402 return SCIP_KEYALREADYEXISTING;
2403 }
2404 }
2405
2406 /* otherwise check if the current element at this position is closer to its hashvalue */
2407 distance = ELEM_DISTANCE(pos);
2408 if( distance < elemdistance )
2409 {
2410 uint32_t tmp;
2411
2412 /* if this is the case we insert the new element here and find a new position for the old one */
2413 elemdistance = distance;
2414 SCIPswapPointers(&hashtable->slots[pos], &element);
2415 tmp = hashval;
2416 hashval = hashtable->hashes[pos];
2417 hashtable->hashes[pos] = tmp;
2418 key = hashtable->hashgetkey(hashtable->userptr, element);
2419
2420 /* after doing a swap the case that other elements are replaced must not happen anymore */
2421 #ifndef NDEBUG
2422 swapped = TRUE;
2423 #endif
2424 }
2425
2426 /* continue until we have found an empty position */
2427 pos = (pos + 1) & hashtable->mask;
2428 ++elemdistance;
2429 }
2430 }
2431
2432 /** check if the load factor of the hashtable is too high and rebuild if necessary */
2433 static
hashtableCheckLoad(SCIP_HASHTABLE * hashtable)2434 SCIP_RETCODE hashtableCheckLoad(
2435 SCIP_HASHTABLE* hashtable /**< hash table */
2436 )
2437 {
2438 assert(hashtable != NULL);
2439 assert(hashtable->shift < 32);
2440
2441 /* use integer arithmetic to approximately check if load factor is above 90% */
2442 if( ((((uint64_t)hashtable->nelements)<<10)>>(32-hashtable->shift) > 921) )
2443 {
2444 void** slots;
2445 uint32_t* hashes;
2446 uint32_t nslots;
2447 uint32_t newnslots;
2448 uint32_t i;
2449
2450 /* calculate new size (always power of two) */
2451 nslots = hashtable->mask + 1;
2452 newnslots = 2*nslots;
2453 hashtable->mask = newnslots-1;
2454 --hashtable->shift;
2455
2456 /* reallocate array */
2457 SCIP_ALLOC( BMSallocBlockMemoryArray(hashtable->blkmem, &slots, newnslots) );
2458 SCIP_ALLOC( BMSallocClearBlockMemoryArray(hashtable->blkmem, &hashes, newnslots) );
2459
2460 SCIPswapPointers((void**) &slots, (void**) &hashtable->slots);
2461 SCIPswapPointers((void**) &hashes, (void**) &hashtable->hashes);
2462 hashtable->nelements = 0;
2463
2464 /* reinsert all elements */
2465 for( i = 0; i < nslots; ++i )
2466 {
2467 /* using SCIP_CALL_ABORT since there are no allocations or duplicates
2468 * and thus no bad return codes when inserting the elements
2469 */
2470 if( hashes[i] != 0 )
2471 {
2472 SCIP_CALL_ABORT( hashtableInsert(hashtable, slots[i], hashtable->hashgetkey(hashtable->userptr, slots[i]), hashes[i], FALSE) );
2473 }
2474 }
2475 BMSfreeBlockMemoryArray(hashtable->blkmem, &hashes, nslots);
2476 BMSfreeBlockMemoryArray(hashtable->blkmem, &slots, nslots);
2477 }
2478
2479 return SCIP_OKAY;
2480 }
2481
2482
2483 /** inserts element in hash table
2484 *
2485 * @note multiple inserts of same element overrides previous one
2486 */
SCIPhashtableInsert(SCIP_HASHTABLE * hashtable,void * element)2487 SCIP_RETCODE SCIPhashtableInsert(
2488 SCIP_HASHTABLE* hashtable, /**< hash table */
2489 void* element /**< element to insert into the table */
2490 )
2491 {
2492 void* key;
2493 uint64_t keyval;
2494 uint32_t hashval;
2495
2496 assert(hashtable != NULL);
2497 assert(hashtable->slots != NULL);
2498 assert(hashtable->hashes != NULL);
2499 assert(hashtable->mask > 0);
2500 assert(hashtable->hashgetkey != NULL);
2501 assert(hashtable->hashkeyeq != NULL);
2502 assert(hashtable->hashkeyval != NULL);
2503 assert(element != NULL);
2504
2505 SCIP_CALL( hashtableCheckLoad(hashtable) );
2506
2507 /* get the hash key and its hash value */
2508 key = hashtable->hashgetkey(hashtable->userptr, element);
2509 keyval = hashtable->hashkeyval(hashtable->userptr, key);
2510 hashval = hashvalue(keyval);
2511
2512 return hashtableInsert(hashtable, element, key, hashval, TRUE);
2513 }
2514
2515 /** inserts element in hash table
2516 *
2517 * @note multiple insertion of same element is checked and results in an error
2518 */
SCIPhashtableSafeInsert(SCIP_HASHTABLE * hashtable,void * element)2519 SCIP_RETCODE SCIPhashtableSafeInsert(
2520 SCIP_HASHTABLE* hashtable, /**< hash table */
2521 void* element /**< element to insert into the table */
2522 )
2523 {
2524 void* key;
2525 uint64_t keyval;
2526 uint32_t hashval;
2527
2528 assert(hashtable != NULL);
2529 assert(hashtable->slots != NULL);
2530 assert(hashtable->hashes != NULL);
2531 assert(hashtable->mask > 0);
2532 assert(hashtable->hashgetkey != NULL);
2533 assert(hashtable->hashkeyeq != NULL);
2534 assert(hashtable->hashkeyval != NULL);
2535 assert(element != NULL);
2536
2537 SCIP_CALL( hashtableCheckLoad(hashtable) );
2538
2539 /* get the hash key and its hash value */
2540 key = hashtable->hashgetkey(hashtable->userptr, element);
2541 keyval = hashtable->hashkeyval(hashtable->userptr, key);
2542 hashval = hashvalue(keyval);
2543
2544 return hashtableInsert(hashtable, element, key, hashval, FALSE);
2545 }
2546
2547 /** retrieve element with key from hash table, returns NULL if not existing */
SCIPhashtableRetrieve(SCIP_HASHTABLE * hashtable,void * key)2548 void* SCIPhashtableRetrieve(
2549 SCIP_HASHTABLE* hashtable, /**< hash table */
2550 void* key /**< key to retrieve */
2551 )
2552 {
2553 uint64_t keyval;
2554 uint32_t hashval;
2555 uint32_t pos;
2556 uint32_t elemdistance;
2557
2558 assert(hashtable != NULL);
2559 assert(hashtable->slots != NULL);
2560 assert(hashtable->hashes != NULL);
2561 assert(hashtable->mask > 0);
2562 assert(hashtable->hashgetkey != NULL);
2563 assert(hashtable->hashkeyeq != NULL);
2564 assert(hashtable->hashkeyval != NULL);
2565 assert(key != NULL);
2566
2567 /* get the hash value of the key */
2568 keyval = hashtable->hashkeyval(hashtable->userptr, key);
2569 hashval = hashvalue(keyval);
2570
2571 pos = hashval>>(hashtable->shift);
2572 elemdistance = 0;
2573
2574 while( TRUE ) /*lint !e716*/
2575 {
2576 uint32_t distance;
2577
2578 /* slots is empty so element cannot be contained */
2579 if( hashtable->hashes[pos] == 0 )
2580 return NULL;
2581
2582 distance = ELEM_DISTANCE(pos);
2583
2584 /* element cannot be contained since otherwise we would have swapped it with this one during insert */
2585 if( elemdistance > distance )
2586 return NULL;
2587
2588 /* found element */
2589 if( hashtable->hashes[pos] == hashval && hashtable->hashkeyeq(hashtable->userptr,
2590 hashtable->hashgetkey(hashtable->userptr, hashtable->slots[pos]), key) )
2591 return hashtable->slots[pos];
2592
2593 pos = (pos + 1) & hashtable->mask;
2594 ++elemdistance;
2595 }
2596 }
2597
2598 /** returns whether the given element exists in the table */
SCIPhashtableExists(SCIP_HASHTABLE * hashtable,void * element)2599 SCIP_Bool SCIPhashtableExists(
2600 SCIP_HASHTABLE* hashtable, /**< hash table */
2601 void* element /**< element to search in the table */
2602 )
2603 {
2604 assert(hashtable != NULL);
2605 assert(hashtable->slots != NULL);
2606 assert(hashtable->hashes != NULL);
2607 assert(hashtable->mask > 0);
2608 assert(hashtable->hashgetkey != NULL);
2609 assert(hashtable->hashkeyeq != NULL);
2610 assert(hashtable->hashkeyval != NULL);
2611 assert(element != NULL);
2612
2613 return (SCIPhashtableRetrieve(hashtable, hashtable->hashgetkey(hashtable->userptr, element)) != NULL);
2614 }
2615
2616 /** removes element from the hash table, if it exists */
SCIPhashtableRemove(SCIP_HASHTABLE * hashtable,void * element)2617 SCIP_RETCODE SCIPhashtableRemove(
2618 SCIP_HASHTABLE* hashtable, /**< hash table */
2619 void* element /**< element to remove from the table */
2620 )
2621 {
2622 void* key;
2623 uint64_t keyval;
2624 uint32_t hashval;
2625 uint32_t elemdistance;
2626 uint32_t distance;
2627 uint32_t pos;
2628
2629 assert(hashtable != NULL);
2630 assert(hashtable->slots != NULL);
2631 assert(hashtable->hashes != NULL);
2632 assert(hashtable->mask > 0);
2633 assert(hashtable->hashgetkey != NULL);
2634 assert(hashtable->hashkeyeq != NULL);
2635 assert(hashtable->hashkeyval != NULL);
2636 assert(element != NULL);
2637
2638 /* get the hash key and its hash value */
2639 key = hashtable->hashgetkey(hashtable->userptr, element);
2640 keyval = hashtable->hashkeyval(hashtable->userptr, key);
2641 hashval = hashvalue(keyval);
2642
2643 elemdistance = 0;
2644 pos = hashval>>(hashtable->shift);
2645 while( TRUE ) /*lint !e716*/
2646 {
2647 /* slots empty so element not contained */
2648 if( hashtable->hashes[pos] == 0 )
2649 return SCIP_OKAY;
2650
2651 distance = ELEM_DISTANCE(pos);
2652
2653 /* element can not be contained since otherwise we would have swapped it with this one */
2654 if( elemdistance > distance )
2655 return SCIP_OKAY;
2656
2657 if( hashtable->hashes[pos] == hashval && hashtable->hashkeyeq(hashtable->userptr,
2658 hashtable->hashgetkey(hashtable->userptr, hashtable->slots[pos]), key) )
2659 {
2660 /* element exists at pos so break out of loop */
2661 break;
2662 }
2663
2664 pos = (pos + 1) & hashtable->mask;
2665 ++elemdistance;
2666 }
2667
2668 /* remove element */
2669 hashtable->hashes[pos] = 0;
2670 --hashtable->nelements;
2671 while( TRUE ) /*lint !e716*/
2672 {
2673 uint32_t nextpos = (pos + 1) & hashtable->mask;
2674
2675 /* nothing to do since there is no chain that needs to be moved */
2676 if( hashtable->hashes[nextpos] == 0 )
2677 break;
2678
2679 /* check if the element is the start of a new chain and return if that is the case */
2680 if( (hashtable->hashes[nextpos]>>(hashtable->shift)) == nextpos )
2681 break;
2682
2683 /* element should be moved to the left and next element needs to be checked */
2684 hashtable->slots[pos] = hashtable->slots[nextpos];
2685 hashtable->hashes[pos] = hashtable->hashes[nextpos];
2686 hashtable->hashes[nextpos] = 0;
2687
2688 pos = nextpos;
2689 }
2690
2691 return SCIP_OKAY;
2692 }
2693
2694 /** removes all elements of the hash table */
SCIPhashtableRemoveAll(SCIP_HASHTABLE * hashtable)2695 void SCIPhashtableRemoveAll(
2696 SCIP_HASHTABLE* hashtable /**< hash table */
2697 )
2698 {
2699 assert(hashtable != NULL);
2700
2701 BMSclearMemoryArray(hashtable->hashes, hashtable->mask + 1);
2702
2703 hashtable->nelements = 0;
2704 }
2705
2706 /** returns number of hash table elements */
SCIPhashtableGetNElements(SCIP_HASHTABLE * hashtable)2707 SCIP_Longint SCIPhashtableGetNElements(
2708 SCIP_HASHTABLE* hashtable /**< hash table */
2709 )
2710 {
2711 assert(hashtable != NULL);
2712
2713 return hashtable->nelements;
2714 }
2715
2716 /** gives the number of entries in the internal arrays of a hash table */
SCIPhashtableGetNEntries(SCIP_HASHTABLE * hashtable)2717 int SCIPhashtableGetNEntries(
2718 SCIP_HASHTABLE* hashtable /**< hash table */
2719 )
2720 {
2721 return (int) hashtable->mask + 1;
2722 }
2723
2724 /** gives the element at the given index or NULL if entry at that index has no element */
SCIPhashtableGetEntry(SCIP_HASHTABLE * hashtable,int entryidx)2725 void* SCIPhashtableGetEntry(
2726 SCIP_HASHTABLE* hashtable, /**< hash table */
2727 int entryidx /**< index of hash table entry */
2728 )
2729 {
2730 return hashtable->hashes[entryidx] == 0 ? NULL : hashtable->slots[entryidx];
2731 }
2732
2733 /** returns the load of the given hash table in percentage */
SCIPhashtableGetLoad(SCIP_HASHTABLE * hashtable)2734 SCIP_Real SCIPhashtableGetLoad(
2735 SCIP_HASHTABLE* hashtable /**< hash table */
2736 )
2737 {
2738 assert(hashtable != NULL);
2739
2740 return ((SCIP_Real)(hashtable->nelements) / (hashtable->mask + 1) * 100.0);
2741 }
2742
2743 /** prints statistics about hash table usage */
SCIPhashtablePrintStatistics(SCIP_HASHTABLE * hashtable,SCIP_MESSAGEHDLR * messagehdlr)2744 void SCIPhashtablePrintStatistics(
2745 SCIP_HASHTABLE* hashtable, /**< hash table */
2746 SCIP_MESSAGEHDLR* messagehdlr /**< message handler */
2747 )
2748 {
2749 uint32_t maxprobelen = 0;
2750 uint64_t probelensum = 0;
2751 uint32_t nslots;
2752 uint32_t i;
2753
2754 assert(hashtable != NULL);
2755
2756 nslots = hashtable->mask + 1;
2757
2758 /* compute the maximum and average probe length */
2759 for( i = 0; i < nslots; ++i )
2760 {
2761 if( hashtable->hashes[i] != 0 )
2762 {
2763 uint32_t probelen = ELEM_DISTANCE(i) + 1;
2764 probelensum += probelen;
2765 maxprobelen = MAX(probelen, maxprobelen);
2766 }
2767 }
2768
2769 /* print general hash table statistics */
2770 SCIPmessagePrintInfo(messagehdlr, "%u hash entries, used %u/%u slots (%.1f%%)",
2771 (unsigned int)hashtable->nelements, (unsigned int)hashtable->nelements,
2772 (unsigned int)nslots, 100.0*(SCIP_Real)hashtable->nelements/(SCIP_Real)(nslots));
2773
2774 /* if not empty print average and maximum probe length */
2775 if( hashtable->nelements > 0 )
2776 SCIPmessagePrintInfo(messagehdlr, ", avg. probe length is %.1f, max. probe length is %u",
2777 (SCIP_Real)(probelensum)/(SCIP_Real)hashtable->nelements, (unsigned int)maxprobelen);
2778 SCIPmessagePrintInfo(messagehdlr, "\n");
2779 }
2780
2781 /** returns TRUE iff both keys (i.e. strings) are equal */
SCIP_DECL_HASHKEYEQ(SCIPhashKeyEqString)2782 SCIP_DECL_HASHKEYEQ(SCIPhashKeyEqString)
2783 { /*lint --e{715}*/
2784 const char* string1 = (const char*)key1;
2785 const char* string2 = (const char*)key2;
2786
2787 return (strcmp(string1, string2) == 0);
2788 }
2789
2790 /** returns the hash value of the key (i.e. string) */
SCIP_DECL_HASHKEYVAL(SCIPhashKeyValString)2791 SCIP_DECL_HASHKEYVAL(SCIPhashKeyValString)
2792 { /*lint --e{715}*/
2793 const char* str;
2794 uint64_t hash;
2795
2796 str = (const char*)key;
2797 hash = 37;
2798 while( *str != '\0' )
2799 {
2800 hash *= 11;
2801 hash += (unsigned int)(*str); /*lint !e571*/
2802 str++;
2803 }
2804
2805 return hash;
2806 }
2807
2808
2809 /** gets the element as the key */
SCIP_DECL_HASHGETKEY(SCIPhashGetKeyStandard)2810 SCIP_DECL_HASHGETKEY(SCIPhashGetKeyStandard)
2811 { /*lint --e{715}*/
2812 /* the key is the element itself */
2813 return elem;
2814 }
2815
2816 /** returns TRUE iff both keys(pointer) are equal */
SCIP_DECL_HASHKEYEQ(SCIPhashKeyEqPtr)2817 SCIP_DECL_HASHKEYEQ(SCIPhashKeyEqPtr)
2818 { /*lint --e{715}*/
2819 return (key1 == key2);
2820 }
2821
2822 /** returns the hash value of the key */
SCIP_DECL_HASHKEYVAL(SCIPhashKeyValPtr)2823 SCIP_DECL_HASHKEYVAL(SCIPhashKeyValPtr)
2824 { /*lint --e{715}*/
2825 /* the key is used as the keyvalue too */
2826 return (uint64_t) (uintptr_t) key;
2827 }
2828
2829
2830
2831 /*
2832 * Hash Map
2833 */
2834
2835 /* redefine ELEM_DISTANCE macro for hashmap */
2836 #undef ELEM_DISTANCE
2837 /* computes the distance from it's desired position for the element stored at pos */
2838 #define ELEM_DISTANCE(pos) (((pos) + hashmap->mask + 1 - (hashmap->hashes[(pos)]>>(hashmap->shift))) & hashmap->mask)
2839
2840 /** inserts element in hash table */
2841 static
hashmapInsert(SCIP_HASHMAP * hashmap,void * origin,SCIP_HASHMAPIMAGE image,uint32_t hashval,SCIP_Bool override)2842 SCIP_RETCODE hashmapInsert(
2843 SCIP_HASHMAP* hashmap, /**< hash map */
2844 void* origin, /**< element to insert into the table */
2845 SCIP_HASHMAPIMAGE image, /**< key of element */
2846 uint32_t hashval, /**< hash value of element */
2847 SCIP_Bool override /**< should element be overridden or error be returned if already existing */
2848 )
2849 {
2850 uint32_t elemdistance;
2851 uint32_t pos;
2852
2853 assert(hashmap != NULL);
2854 assert(hashmap->slots != NULL);
2855 assert(hashmap->hashes != NULL);
2856 assert(hashmap->mask > 0);
2857 assert(hashval != 0);
2858
2859 pos = hashval>>(hashmap->shift);
2860 elemdistance = 0;
2861 while( TRUE ) /*lint !e716*/
2862 {
2863 uint32_t distance;
2864
2865 /* if position is empty or key equal insert element */
2866 if( hashmap->hashes[pos] == 0 )
2867 {
2868 hashmap->slots[pos].origin = origin;
2869 hashmap->slots[pos].image = image;
2870 hashmap->hashes[pos] = hashval;
2871 ++hashmap->nelements;
2872 return SCIP_OKAY;
2873 }
2874
2875 if( hashval == hashmap->hashes[pos] && origin == hashmap->slots[pos].origin )
2876 {
2877 if( override )
2878 {
2879 hashmap->slots[pos].origin = origin;
2880 hashmap->slots[pos].image = image;
2881 hashmap->hashes[pos] = hashval;
2882 return SCIP_OKAY;
2883 }
2884 else
2885 {
2886 return SCIP_KEYALREADYEXISTING;
2887 }
2888 }
2889
2890 /* otherwise check if the current element at this position is closer to its hashvalue */
2891 distance = ELEM_DISTANCE(pos);
2892 if( distance < elemdistance )
2893 {
2894 SCIP_HASHMAPIMAGE tmp;
2895 uint32_t tmphash;
2896
2897 /* if this is the case we insert the new element here and find a new position for the old one */
2898 elemdistance = distance;
2899 tmphash = hashval;
2900 hashval = hashmap->hashes[pos];
2901 hashmap->hashes[pos] = tmphash;
2902 SCIPswapPointers(&hashmap->slots[pos].origin, &origin);
2903 tmp = image;
2904 image = hashmap->slots[pos].image;
2905 hashmap->slots[pos].image = tmp;
2906 }
2907
2908 /* continue until we have found an empty position */
2909 pos = (pos + 1) & hashmap->mask;
2910 ++elemdistance;
2911 }
2912 }
2913
2914 /** lookup origin in the hashmap. If element is found returns true and the position of the element,
2915 * otherwise returns FALSE.
2916 */
2917 static
hashmapLookup(SCIP_HASHMAP * hashmap,void * origin,uint32_t * pos)2918 SCIP_Bool hashmapLookup(
2919 SCIP_HASHMAP* hashmap, /**< hash table */
2920 void* origin, /**< origin to lookup */
2921 uint32_t* pos /**< pointer to store position of element, if exists */
2922 )
2923 {
2924 uint32_t hashval;
2925 uint32_t elemdistance;
2926
2927 assert(hashmap != NULL);
2928 assert(hashmap->slots != NULL);
2929 assert(hashmap->hashes != NULL);
2930 assert(hashmap->mask > 0);
2931
2932 /* get the hash value */
2933 hashval = hashvalue((size_t)origin);
2934 assert(hashval != 0);
2935
2936 *pos = hashval>>(hashmap->shift);
2937 elemdistance = 0;
2938
2939 while( TRUE ) /*lint !e716*/
2940 {
2941 uint32_t distance;
2942
2943 /* slots is empty so element cannot be contained */
2944 if( hashmap->hashes[*pos] == 0 )
2945 return FALSE;
2946
2947 distance = ELEM_DISTANCE(*pos);
2948 /* element can not be contained since otherwise we would have swapped it with this one during insert */
2949 if( elemdistance > distance )
2950 return FALSE;
2951
2952 /* found element */
2953 if( hashmap->hashes[*pos] == hashval && hashmap->slots[*pos].origin == origin )
2954 return TRUE;
2955
2956 *pos = (*pos + 1) & hashmap->mask;
2957 ++elemdistance;
2958 }
2959 }
2960
2961 /** check if the load factor of the hashmap is too high and rebuild if necessary */
2962 static
hashmapCheckLoad(SCIP_HASHMAP * hashmap)2963 SCIP_RETCODE hashmapCheckLoad(
2964 SCIP_HASHMAP* hashmap /**< hash table */
2965 )
2966 {
2967 assert(hashmap != NULL);
2968 assert(hashmap->shift < 32);
2969
2970 /* use integer arithmetic to approximately check if load factor is above 90% */
2971 if( ((((uint64_t)hashmap->nelements)<<10)>>(32-hashmap->shift) > 921) )
2972 {
2973 SCIP_HASHMAPENTRY* slots;
2974 uint32_t* hashes;
2975 uint32_t nslots;
2976 uint32_t newnslots;
2977 uint32_t i;
2978
2979 /* calculate new size (always power of two) */
2980 nslots = hashmap->mask + 1;
2981 --hashmap->shift;
2982 newnslots = 2*nslots;
2983 hashmap->mask = newnslots-1;
2984
2985 /* reallocate array */
2986 SCIP_ALLOC( BMSallocBlockMemoryArray(hashmap->blkmem, &slots, newnslots) );
2987 SCIP_ALLOC( BMSallocClearBlockMemoryArray(hashmap->blkmem, &hashes, newnslots) );
2988
2989 SCIPswapPointers((void**) &slots, (void**) &hashmap->slots);
2990 SCIPswapPointers((void**) &hashes, (void**) &hashmap->hashes);
2991 hashmap->nelements = 0;
2992
2993 /* reinsert all elements */
2994 for( i = 0; i < nslots; ++i )
2995 {
2996 /* using SCIP_CALL_ABORT since there are no allocations or duplicates
2997 * and thus no bad return codes when inserting the elements
2998 */
2999 if( hashes[i] != 0 )
3000 {
3001 SCIP_CALL_ABORT( hashmapInsert(hashmap, slots[i].origin, slots[i].image, hashes[i], FALSE) );
3002 }
3003 }
3004
3005 /* free old arrays */
3006 BMSfreeBlockMemoryArray(hashmap->blkmem, &hashes, nslots);
3007 BMSfreeBlockMemoryArray(hashmap->blkmem, &slots, nslots);
3008 }
3009
3010 return SCIP_OKAY;
3011 }
3012
3013 /** creates a hash map mapping pointers to pointers */
SCIPhashmapCreate(SCIP_HASHMAP ** hashmap,BMS_BLKMEM * blkmem,int mapsize)3014 SCIP_RETCODE SCIPhashmapCreate(
3015 SCIP_HASHMAP** hashmap, /**< pointer to store the created hash map */
3016 BMS_BLKMEM* blkmem, /**< block memory used to store hash map entries */
3017 int mapsize /**< size of the hash map */
3018 )
3019 {
3020 uint32_t nslots;
3021
3022 assert(hashmap != NULL);
3023 assert(mapsize >= 0);
3024 assert(blkmem != NULL);
3025
3026 SCIP_ALLOC( BMSallocBlockMemory(blkmem, hashmap) );
3027
3028 /* dont create too small hashtables, i.e. at least size 32, and increase
3029 * the given size by divinding it by 0.9, since then no rebuilding will
3030 * be necessary if the given number of elements are inserted. Finally round
3031 * to the next power of two.
3032 */
3033 (*hashmap)->shift = 32;
3034 (*hashmap)->shift -= (unsigned int)ceil(log(MAX(32, mapsize / 0.9)) / log(2.0));
3035 nslots = 1u << (32 - (*hashmap)->shift);
3036 (*hashmap)->mask = nslots - 1;
3037 (*hashmap)->blkmem = blkmem;
3038 (*hashmap)->nelements = 0;
3039 (*hashmap)->hashmaptype = SCIP_HASHMAPTYPE_UNKNOWN;
3040
3041 SCIP_ALLOC( BMSallocBlockMemoryArray((*hashmap)->blkmem, &(*hashmap)->slots, nslots) );
3042 SCIP_ALLOC( BMSallocClearBlockMemoryArray((*hashmap)->blkmem, &(*hashmap)->hashes, nslots) );
3043
3044 return SCIP_OKAY;
3045 }
3046
3047 /** frees the hash map */
SCIPhashmapFree(SCIP_HASHMAP ** hashmap)3048 void SCIPhashmapFree(
3049 SCIP_HASHMAP** hashmap /**< pointer to the hash map */
3050 )
3051 {
3052 uint32_t nslots;
3053
3054 assert(hashmap != NULL);
3055 assert(*hashmap != NULL);
3056
3057 nslots = (*hashmap)->mask + 1;
3058 #ifdef SCIP_DEBUG
3059 {
3060 uint32_t maxprobelen = 0;
3061 uint64_t probelensum = 0;
3062 uint32_t i;
3063
3064 assert(hashmap != NULL);
3065
3066 for( i = 0; i < nslots; ++i )
3067 {
3068 if( (*hashmap)->hashes[i] != 0 )
3069 {
3070 uint32_t probelen = ((i + (*hashmap)->mask + 1 - ((*hashmap)->hashes[i]>>((*hashmap)->shift))) & (*hashmap)->mask) + 1;
3071 probelensum += probelen;
3072 maxprobelen = MAX(probelen, maxprobelen);
3073 }
3074 }
3075
3076 SCIPdebugMessage("%u hash map entries, used %u/%u slots (%.1f%%)",
3077 (unsigned int)(*hashmap)->nelements, (unsigned int)(*hashmap)->nelements, (unsigned int)nslots,
3078 100.0*(SCIP_Real)(*hashmap)->nelements/(SCIP_Real)(nslots));
3079 if( (*hashmap)->nelements > 0 )
3080 SCIPdebugPrintf(", avg. probe length is %.1f, max. probe length is %u",
3081 (SCIP_Real)(probelensum)/(SCIP_Real)(*hashmap)->nelements, (unsigned int)maxprobelen);
3082 SCIPdebugPrintf("\n");
3083 }
3084 #endif
3085
3086 /* free main hash map data structure */
3087 BMSfreeBlockMemoryArray((*hashmap)->blkmem, &(*hashmap)->hashes, nslots);
3088 BMSfreeBlockMemoryArray((*hashmap)->blkmem, &(*hashmap)->slots, nslots);
3089 BMSfreeBlockMemory((*hashmap)->blkmem, hashmap);
3090 }
3091
3092 /** inserts new origin->image pair in hash map
3093 *
3094 * @note multiple insertion of same element is checked and results in an error
3095 */
SCIPhashmapInsert(SCIP_HASHMAP * hashmap,void * origin,void * image)3096 SCIP_RETCODE SCIPhashmapInsert(
3097 SCIP_HASHMAP* hashmap, /**< hash map */
3098 void* origin, /**< origin to set image for */
3099 void* image /**< new image for origin */
3100 )
3101 {
3102 uint32_t hashval;
3103 SCIP_HASHMAPIMAGE img;
3104
3105 assert(hashmap != NULL);
3106 assert(hashmap->slots != NULL);
3107 assert(hashmap->hashes != NULL);
3108 assert(hashmap->mask > 0);
3109 assert(hashmap->hashmaptype == SCIP_HASHMAPTYPE_UNKNOWN || hashmap->hashmaptype == SCIP_HASHMAPTYPE_POINTER);
3110
3111 #ifndef NDEBUG
3112 if( hashmap->hashmaptype == SCIP_HASHMAPTYPE_UNKNOWN )
3113 hashmap->hashmaptype = SCIP_HASHMAPTYPE_POINTER;
3114 #endif
3115
3116 SCIP_CALL( hashmapCheckLoad(hashmap) );
3117
3118 /* get the hash value */
3119 hashval = hashvalue((size_t)origin);
3120
3121 /* append origin->image pair to hash map */
3122 img.ptr = image;
3123 SCIP_CALL( hashmapInsert(hashmap, origin, img, hashval, FALSE) );
3124
3125 return SCIP_OKAY;
3126 }
3127
3128 /** inserts new origin->image pair in hash map
3129 *
3130 * @note multiple insertion of same element is checked and results in an error
3131 */
SCIPhashmapInsertInt(SCIP_HASHMAP * hashmap,void * origin,int image)3132 SCIP_RETCODE SCIPhashmapInsertInt(
3133 SCIP_HASHMAP* hashmap, /**< hash map */
3134 void* origin, /**< origin to set image for */
3135 int image /**< new image for origin */
3136 )
3137 {
3138 uint32_t hashval;
3139 SCIP_HASHMAPIMAGE img;
3140
3141 assert(hashmap != NULL);
3142 assert(hashmap->slots != NULL);
3143 assert(hashmap->hashes != NULL);
3144 assert(hashmap->mask > 0);
3145 assert(hashmap->hashmaptype == SCIP_HASHMAPTYPE_UNKNOWN || hashmap->hashmaptype == SCIP_HASHMAPTYPE_INT);
3146
3147 #ifndef NDEBUG
3148 if( hashmap->hashmaptype == SCIP_HASHMAPTYPE_UNKNOWN )
3149 hashmap->hashmaptype = SCIP_HASHMAPTYPE_INT;
3150 #endif
3151
3152 SCIP_CALL( hashmapCheckLoad(hashmap) );
3153
3154 /* get the hash value */
3155 hashval = hashvalue((size_t)origin);
3156
3157 /* append origin->image pair to hash map */
3158 img.integer = image;
3159 SCIP_CALL( hashmapInsert(hashmap, origin, img, hashval, FALSE) );
3160
3161 return SCIP_OKAY;
3162 }
3163
3164 /** inserts new origin->image pair in hash map
3165 *
3166 * @note multiple insertion of same element is checked and results in an error
3167 */
SCIPhashmapInsertReal(SCIP_HASHMAP * hashmap,void * origin,SCIP_Real image)3168 SCIP_RETCODE SCIPhashmapInsertReal(
3169 SCIP_HASHMAP* hashmap, /**< hash map */
3170 void* origin, /**< origin to set image for */
3171 SCIP_Real image /**< new image for origin */
3172 )
3173 {
3174 uint32_t hashval;
3175 SCIP_HASHMAPIMAGE img;
3176
3177 assert(hashmap != NULL);
3178 assert(hashmap->slots != NULL);
3179 assert(hashmap->hashes != NULL);
3180 assert(hashmap->mask > 0);
3181 assert(hashmap->hashmaptype == SCIP_HASHMAPTYPE_UNKNOWN || hashmap->hashmaptype == SCIP_HASHMAPTYPE_REAL);
3182
3183 #ifndef NDEBUG
3184 if( hashmap->hashmaptype == SCIP_HASHMAPTYPE_UNKNOWN )
3185 hashmap->hashmaptype = SCIP_HASHMAPTYPE_REAL;
3186 #endif
3187
3188 SCIP_CALL( hashmapCheckLoad(hashmap) );
3189
3190 /* get the hash value */
3191 hashval = hashvalue((size_t)origin);
3192
3193 /* append origin->image pair to hash map */
3194 img.real = image;
3195 SCIP_CALL( hashmapInsert(hashmap, origin, img, hashval, FALSE) );
3196
3197 return SCIP_OKAY;
3198 }
3199
3200 /** retrieves image of given origin from the hash map, or NULL if no image exists */
SCIPhashmapGetImage(SCIP_HASHMAP * hashmap,void * origin)3201 void* SCIPhashmapGetImage(
3202 SCIP_HASHMAP* hashmap, /**< hash map */
3203 void* origin /**< origin to retrieve image for */
3204 )
3205 {
3206 uint32_t pos;
3207
3208 assert(hashmap != NULL);
3209 assert(hashmap->slots != NULL);
3210 assert(hashmap->hashes != NULL);
3211 assert(hashmap->mask > 0);
3212 assert(hashmap->hashmaptype == SCIP_HASHMAPTYPE_UNKNOWN || hashmap->hashmaptype == SCIP_HASHMAPTYPE_POINTER);
3213
3214 if( hashmapLookup(hashmap, origin, &pos) )
3215 return hashmap->slots[pos].image.ptr;
3216
3217 return NULL;
3218 }
3219
3220 /** retrieves image of given origin from the hash map, or INT_MAX if no image exists */
SCIPhashmapGetImageInt(SCIP_HASHMAP * hashmap,void * origin)3221 int SCIPhashmapGetImageInt(
3222 SCIP_HASHMAP* hashmap, /**< hash map */
3223 void* origin /**< origin to retrieve image for */
3224 )
3225 {
3226 uint32_t pos;
3227
3228 assert(hashmap != NULL);
3229 assert(hashmap->slots != NULL);
3230 assert(hashmap->hashes != NULL);
3231 assert(hashmap->mask > 0);
3232 assert(hashmap->hashmaptype == SCIP_HASHMAPTYPE_UNKNOWN || hashmap->hashmaptype == SCIP_HASHMAPTYPE_INT);
3233
3234 if( hashmapLookup(hashmap, origin, &pos) )
3235 return hashmap->slots[pos].image.integer;
3236
3237 return INT_MAX;
3238 }
3239
3240 /** retrieves image of given origin from the hash map, or SCIP_INVALID if no image exists */
SCIPhashmapGetImageReal(SCIP_HASHMAP * hashmap,void * origin)3241 SCIP_Real SCIPhashmapGetImageReal(
3242 SCIP_HASHMAP* hashmap, /**< hash map */
3243 void* origin /**< origin to retrieve image for */
3244 )
3245 {
3246 uint32_t pos;
3247
3248 assert(hashmap != NULL);
3249 assert(hashmap->slots != NULL);
3250 assert(hashmap->hashes != NULL);
3251 assert(hashmap->mask > 0);
3252 assert(hashmap->hashmaptype == SCIP_HASHMAPTYPE_UNKNOWN || hashmap->hashmaptype == SCIP_HASHMAPTYPE_REAL);
3253
3254 if( hashmapLookup(hashmap, origin, &pos) )
3255 return hashmap->slots[pos].image.real;
3256
3257 return SCIP_INVALID;
3258 }
3259
3260 /** sets image for given origin in the hash map, either by modifying existing origin->image pair
3261 * or by appending a new origin->image pair
3262 */
SCIPhashmapSetImage(SCIP_HASHMAP * hashmap,void * origin,void * image)3263 SCIP_RETCODE SCIPhashmapSetImage(
3264 SCIP_HASHMAP* hashmap, /**< hash map */
3265 void* origin, /**< origin to set image for */
3266 void* image /**< new image for origin */
3267 )
3268 {
3269 uint32_t hashval;
3270 SCIP_HASHMAPIMAGE img;
3271
3272 assert(hashmap != NULL);
3273 assert(hashmap->slots != NULL);
3274 assert(hashmap->mask > 0);
3275 assert(hashmap->hashmaptype == SCIP_HASHMAPTYPE_UNKNOWN || hashmap->hashmaptype == SCIP_HASHMAPTYPE_POINTER);
3276
3277 #ifndef NDEBUG
3278 if( hashmap->hashmaptype == SCIP_HASHMAPTYPE_UNKNOWN )
3279 hashmap->hashmaptype = SCIP_HASHMAPTYPE_POINTER;
3280 #endif
3281
3282 SCIP_CALL( hashmapCheckLoad(hashmap) );
3283
3284 /* get the hash value */
3285 hashval = hashvalue((size_t)origin);
3286
3287 /* append origin->image pair to hash map */
3288 img.ptr = image;
3289 SCIP_CALL( hashmapInsert(hashmap, origin, img, hashval, TRUE) );
3290
3291 return SCIP_OKAY;
3292 }
3293
3294 /** sets image for given origin in the hash map, either by modifying existing origin->image pair
3295 * or by appending a new origin->image pair
3296 */
SCIPhashmapSetImageInt(SCIP_HASHMAP * hashmap,void * origin,int image)3297 SCIP_RETCODE SCIPhashmapSetImageInt(
3298 SCIP_HASHMAP* hashmap, /**< hash map */
3299 void* origin, /**< origin to set image for */
3300 int image /**< new image for origin */
3301 )
3302 {
3303 uint32_t hashval;
3304 SCIP_HASHMAPIMAGE img;
3305
3306 assert(hashmap != NULL);
3307 assert(hashmap->slots != NULL);
3308 assert(hashmap->mask > 0);
3309 assert(hashmap->hashmaptype == SCIP_HASHMAPTYPE_UNKNOWN || hashmap->hashmaptype == SCIP_HASHMAPTYPE_INT);
3310
3311 #ifndef NDEBUG
3312 if( hashmap->hashmaptype == SCIP_HASHMAPTYPE_UNKNOWN )
3313 hashmap->hashmaptype = SCIP_HASHMAPTYPE_INT;
3314 #endif
3315
3316 SCIP_CALL( hashmapCheckLoad(hashmap) );
3317
3318 /* get the hash value */
3319 hashval = hashvalue((size_t)origin);
3320
3321 /* append origin->image pair to hash map */
3322 img.integer = image;
3323 SCIP_CALL( hashmapInsert(hashmap, origin, img, hashval, TRUE) );
3324
3325 return SCIP_OKAY;
3326 }
3327
3328 /** sets image for given origin in the hash map, either by modifying existing origin->image pair
3329 * or by appending a new origin->image pair
3330 */
SCIPhashmapSetImageReal(SCIP_HASHMAP * hashmap,void * origin,SCIP_Real image)3331 SCIP_RETCODE SCIPhashmapSetImageReal(
3332 SCIP_HASHMAP* hashmap, /**< hash map */
3333 void* origin, /**< origin to set image for */
3334 SCIP_Real image /**< new image for origin */
3335 )
3336 {
3337 uint32_t hashval;
3338 SCIP_HASHMAPIMAGE img;
3339
3340 assert(hashmap != NULL);
3341 assert(hashmap->slots != NULL);
3342 assert(hashmap->mask > 0);
3343 assert(hashmap->hashmaptype == SCIP_HASHMAPTYPE_UNKNOWN || hashmap->hashmaptype == SCIP_HASHMAPTYPE_REAL);
3344
3345 #ifndef NDEBUG
3346 if( hashmap->hashmaptype == SCIP_HASHMAPTYPE_UNKNOWN )
3347 hashmap->hashmaptype = SCIP_HASHMAPTYPE_REAL;
3348 #endif
3349
3350 SCIP_CALL( hashmapCheckLoad(hashmap) );
3351
3352 /* get the hash value */
3353 hashval = hashvalue((size_t)origin);
3354
3355 /* append origin->image pair to hash map */
3356 img.real = image;
3357 SCIP_CALL( hashmapInsert(hashmap, origin, img, hashval, TRUE) );
3358
3359 return SCIP_OKAY;
3360 }
3361
3362 /** checks whether an image to the given origin exists in the hash map */
SCIPhashmapExists(SCIP_HASHMAP * hashmap,void * origin)3363 SCIP_Bool SCIPhashmapExists(
3364 SCIP_HASHMAP* hashmap, /**< hash map */
3365 void* origin /**< origin to search for */
3366 )
3367 {
3368 uint32_t pos;
3369
3370 assert(hashmap != NULL);
3371 assert(hashmap->slots != NULL);
3372 assert(hashmap->hashes != NULL);
3373 assert(hashmap->mask > 0);
3374
3375 return hashmapLookup(hashmap, origin, &pos);
3376 }
3377
3378 /** removes origin->image pair from the hash map, if it exists */
SCIPhashmapRemove(SCIP_HASHMAP * hashmap,void * origin)3379 SCIP_RETCODE SCIPhashmapRemove(
3380 SCIP_HASHMAP* hashmap, /**< hash map */
3381 void* origin /**< origin to remove from the list */
3382 )
3383 {
3384 uint32_t pos;
3385
3386 assert(hashmap != NULL);
3387 assert(hashmap->slots != NULL);
3388 assert(hashmap->mask > 0);
3389
3390 assert(origin != NULL);
3391
3392 if( hashmapLookup(hashmap, origin, &pos) )
3393 {
3394 /* remove element */
3395 hashmap->hashes[pos] = 0;
3396 --hashmap->nelements;
3397
3398 /* move other elements if necessary */
3399 while( TRUE ) /*lint !e716*/
3400 {
3401 uint32_t nextpos = (pos + 1) & hashmap->mask;
3402
3403 /* nothing to do since there is no chain that needs to be moved */
3404 if( hashmap->hashes[nextpos] == 0 )
3405 return SCIP_OKAY;
3406
3407 /* check if the element is the start of a new chain and return if that is the case */
3408 if( (hashmap->hashes[nextpos]>>(hashmap->shift)) == nextpos )
3409 return SCIP_OKAY;
3410
3411 /* element should be moved to the left and next element needs to be checked */
3412 hashmap->slots[pos].origin = hashmap->slots[nextpos].origin;
3413 hashmap->slots[pos].image = hashmap->slots[nextpos].image;
3414 hashmap->hashes[pos] = hashmap->hashes[nextpos];
3415 hashmap->hashes[nextpos] = 0;
3416
3417 pos = nextpos;
3418 }
3419 }
3420
3421 return SCIP_OKAY;
3422 }
3423
3424 /** prints statistics about hash map usage */
SCIPhashmapPrintStatistics(SCIP_HASHMAP * hashmap,SCIP_MESSAGEHDLR * messagehdlr)3425 void SCIPhashmapPrintStatistics(
3426 SCIP_HASHMAP* hashmap, /**< hash map */
3427 SCIP_MESSAGEHDLR* messagehdlr /**< message handler */
3428 )
3429 {
3430 uint32_t maxprobelen = 0;
3431 uint64_t probelensum = 0;
3432 uint32_t nslots;
3433 uint32_t i;
3434
3435 assert(hashmap != NULL);
3436
3437 nslots = hashmap->mask + 1;
3438
3439 /* compute the maximum and average probe length */
3440 for( i = 0; i < nslots; ++i )
3441 {
3442 if( hashmap->hashes[i] != 0 )
3443 {
3444 uint32_t probelen = ELEM_DISTANCE(i) + 1;
3445 probelensum += probelen;
3446 maxprobelen = MAX(probelen, maxprobelen);
3447 }
3448 }
3449
3450 /* print general hash map statistics */
3451 SCIPmessagePrintInfo(messagehdlr, "%u hash entries, used %u/%u slots (%.1f%%)",
3452 (unsigned int)hashmap->nelements, (unsigned int)hashmap->nelements,
3453 (unsigned int)nslots, 100.0*(SCIP_Real)hashmap->nelements/(SCIP_Real)(nslots));
3454
3455 /* if not empty print average and maximum probe length */
3456 if( hashmap->nelements > 0 )
3457 SCIPmessagePrintInfo(messagehdlr, ", avg. probe length is %.1f, max. probe length is %u",
3458 (SCIP_Real)(probelensum)/(SCIP_Real)hashmap->nelements, (unsigned int)maxprobelen);
3459 SCIPmessagePrintInfo(messagehdlr, "\n");
3460 }
3461
3462 /** indicates whether a hash map has no entries */
SCIPhashmapIsEmpty(SCIP_HASHMAP * hashmap)3463 SCIP_Bool SCIPhashmapIsEmpty(
3464 SCIP_HASHMAP* hashmap /**< hash map */
3465 )
3466 {
3467 assert(hashmap != NULL);
3468
3469 return hashmap->nelements == 0;
3470 }
3471
3472 /** gives the number of elements in a hash map */
SCIPhashmapGetNElements(SCIP_HASHMAP * hashmap)3473 int SCIPhashmapGetNElements(
3474 SCIP_HASHMAP* hashmap /**< hash map */
3475 )
3476 {
3477 return (int) hashmap->nelements;
3478 }
3479
3480 /** gives the number of entries in the internal arrays of a hash map */
SCIPhashmapGetNEntries(SCIP_HASHMAP * hashmap)3481 int SCIPhashmapGetNEntries(
3482 SCIP_HASHMAP* hashmap /**< hash map */
3483 )
3484 {
3485 return (int) hashmap->mask + 1;
3486 }
3487
3488 /** gives the hashmap entry at the given index or NULL if entry is empty */
SCIPhashmapGetEntry(SCIP_HASHMAP * hashmap,int entryidx)3489 SCIP_HASHMAPENTRY* SCIPhashmapGetEntry(
3490 SCIP_HASHMAP* hashmap, /**< hash map */
3491 int entryidx /**< index of hash map entry */
3492 )
3493 {
3494 assert(hashmap != NULL);
3495
3496 return hashmap->hashes[entryidx] == 0 ? NULL : &hashmap->slots[entryidx];
3497 }
3498
3499 /** gives the origin of the hashmap entry */
SCIPhashmapEntryGetOrigin(SCIP_HASHMAPENTRY * entry)3500 void* SCIPhashmapEntryGetOrigin(
3501 SCIP_HASHMAPENTRY* entry /**< hash map entry */
3502 )
3503 {
3504 assert(entry != NULL);
3505
3506 return entry->origin;
3507 }
3508
3509 /** gives the image of the hashmap entry */
SCIPhashmapEntryGetImage(SCIP_HASHMAPENTRY * entry)3510 void* SCIPhashmapEntryGetImage(
3511 SCIP_HASHMAPENTRY* entry /**< hash map entry */
3512 )
3513 {
3514 assert(entry != NULL);
3515
3516 return entry->image.ptr;
3517 }
3518
3519 /** gives the image of the hashmap entry */
SCIPhashmapEntryGetImageInt(SCIP_HASHMAPENTRY * entry)3520 int SCIPhashmapEntryGetImageInt(
3521 SCIP_HASHMAPENTRY* entry /**< hash map entry */
3522 )
3523 {
3524 assert(entry != NULL);
3525
3526 return entry->image.integer;
3527 }
3528
3529 /** gives the image of the hashmap entry */
SCIPhashmapEntryGetImageReal(SCIP_HASHMAPENTRY * entry)3530 SCIP_Real SCIPhashmapEntryGetImageReal(
3531 SCIP_HASHMAPENTRY* entry /**< hash map entry */
3532 )
3533 {
3534 assert(entry != NULL);
3535
3536 return entry->image.real;
3537 }
3538
3539 /** sets pointer image of a hashmap entry */
SCIPhashmapEntrySetImage(SCIP_HASHMAPENTRY * entry,void * image)3540 void SCIPhashmapEntrySetImage(
3541 SCIP_HASHMAPENTRY* entry, /**< hash map entry */
3542 void* image /**< new image */
3543 )
3544 {
3545 assert(entry != NULL);
3546
3547 entry->image.ptr = image;
3548 }
3549
3550 /** sets integer image of a hashmap entry */
SCIPhashmapEntrySetImageInt(SCIP_HASHMAPENTRY * entry,int image)3551 void SCIPhashmapEntrySetImageInt(
3552 SCIP_HASHMAPENTRY* entry, /**< hash map entry */
3553 int image /**< new image */
3554 )
3555 {
3556 assert(entry != NULL);
3557
3558 entry->image.integer = image;
3559 }
3560
3561 /** sets real image of a hashmap entry */
SCIPhashmapEntrySetImageReal(SCIP_HASHMAPENTRY * entry,SCIP_Real image)3562 void SCIPhashmapEntrySetImageReal(
3563 SCIP_HASHMAPENTRY* entry, /**< hash map entry */
3564 SCIP_Real image /**< new image */
3565 )
3566 {
3567 assert(entry != NULL);
3568
3569 entry->image.real = image;
3570 }
3571
3572 /** removes all entries in a hash map. */
SCIPhashmapRemoveAll(SCIP_HASHMAP * hashmap)3573 SCIP_RETCODE SCIPhashmapRemoveAll(
3574 SCIP_HASHMAP* hashmap /**< hash map */
3575 )
3576 {
3577 assert(hashmap != NULL);
3578
3579 BMSclearMemoryArray(hashmap->hashes, hashmap->mask + 1);
3580
3581 hashmap->nelements = 0;
3582
3583 return SCIP_OKAY;
3584 }
3585
3586
3587 /*
3588 * Hash Set
3589 */
3590
3591 /* redefine ELEM_DISTANCE macro for hashset */
3592 #undef ELEM_DISTANCE
3593 /* computes the distance from it's desired position for the element stored at pos */
3594 #define ELEM_DISTANCE(pos) (((pos) + nslots - hashSetDesiredPos(hashset, hashset->slots[(pos)])) & mask)
3595
3596 /* calculate desired position of element in hash set */
3597 static
hashSetDesiredPos(SCIP_HASHSET * hashset,void * element)3598 uint32_t hashSetDesiredPos(
3599 SCIP_HASHSET* hashset, /**< the hash set */
3600 void* element /**< element to calculate position for */
3601 )
3602 {
3603 return (uint32_t)((UINT64_C(0x9e3779b97f4a7c15) * (uintptr_t)element)>>(hashset->shift));
3604 }
3605
3606 static
hashsetInsert(SCIP_HASHSET * hashset,void * element)3607 void hashsetInsert(
3608 SCIP_HASHSET* hashset, /**< hash set */
3609 void* element /**< element to insert */
3610 )
3611 {
3612 uint32_t elemdistance;
3613 uint32_t pos;
3614 uint32_t nslots;
3615 uint32_t mask;
3616
3617 assert(hashset != NULL);
3618 assert(hashset->slots != NULL);
3619 assert(element != NULL);
3620
3621 pos = hashSetDesiredPos(hashset, element);
3622 nslots = (uint32_t)SCIPhashsetGetNSlots(hashset);
3623 mask = nslots - 1;
3624
3625 elemdistance = 0;
3626 while( TRUE ) /*lint !e716*/
3627 {
3628 uint32_t distance;
3629
3630 /* if position is empty or key equal insert element */
3631 if( hashset->slots[pos] == NULL )
3632 {
3633 hashset->slots[pos] = element;
3634 ++hashset->nelements;
3635 return;
3636 }
3637
3638 if( hashset->slots[pos] == element )
3639 return;
3640
3641 /* otherwise check if the current element at this position is closer to its hashvalue */
3642 distance = ELEM_DISTANCE(pos);
3643 if( distance < elemdistance )
3644 {
3645 /* if this is the case we insert the new element here and find a new position for the old one */
3646 elemdistance = distance;
3647 SCIPswapPointers(&hashset->slots[pos], &element);
3648 }
3649
3650 /* continue until we have found an empty position */
3651 pos = (pos + 1) & mask;
3652 ++elemdistance;
3653 }
3654 }
3655
3656 /** check if the load factor of the hash set is too high and rebuild if necessary */
3657 static
hashsetCheckLoad(SCIP_HASHSET * hashset,BMS_BLKMEM * blkmem)3658 SCIP_RETCODE hashsetCheckLoad(
3659 SCIP_HASHSET* hashset, /**< hash set */
3660 BMS_BLKMEM* blkmem /**< block memory used to store hash set entries */
3661 )
3662 {
3663 assert(hashset != NULL);
3664 assert(hashset->shift < 64);
3665
3666 /* use integer arithmetic to approximately check if load factor is above 90% */
3667 if( ((((uint64_t)hashset->nelements)<<10)>>(64-hashset->shift) > 921) )
3668 {
3669 void** slots;
3670 uint32_t nslots;
3671 uint32_t newnslots;
3672 uint32_t i;
3673
3674 /* calculate new size (always power of two) */
3675 nslots = (uint32_t)SCIPhashsetGetNSlots(hashset);
3676 newnslots = 2*nslots;
3677 --hashset->shift;
3678
3679 /* reallocate array */
3680 SCIP_ALLOC( BMSallocClearBlockMemoryArray(blkmem, &slots, newnslots) );
3681
3682 SCIPswapPointers((void**) &slots, (void**) &hashset->slots);
3683 hashset->nelements = 0;
3684
3685 /* reinsert all elements */
3686 for( i = 0; i < nslots; ++i )
3687 {
3688 if( slots[i] != NULL )
3689 hashsetInsert(hashset, slots[i]);
3690 }
3691
3692 BMSfreeBlockMemoryArray(blkmem, &slots, nslots);
3693 }
3694
3695 return SCIP_OKAY;
3696 }
3697
3698 /** creates a hash set of pointers */
SCIPhashsetCreate(SCIP_HASHSET ** hashset,BMS_BLKMEM * blkmem,int size)3699 SCIP_RETCODE SCIPhashsetCreate(
3700 SCIP_HASHSET** hashset, /**< pointer to store the created hash set */
3701 BMS_BLKMEM* blkmem, /**< block memory used to store hash set entries */
3702 int size /**< initial size of the hash set; it is guaranteed that the set is not
3703 * resized if at most that many elements are inserted */
3704 )
3705 {
3706 uint32_t nslots;
3707
3708 assert(hashset != NULL);
3709 assert(size >= 0);
3710 assert(blkmem != NULL);
3711
3712 SCIP_ALLOC( BMSallocBlockMemory(blkmem, hashset) );
3713
3714 /* do not create too small hashtables, i.e. at least size 32, and increase
3715 * the given size by dividing it by 0.9, since then no rebuilding will
3716 * be necessary if the given number of elements are inserted. Finally round
3717 * to the next power of two.
3718 */
3719 (*hashset)->shift = 64;
3720 (*hashset)->shift -= (unsigned int)ceil(log(MAX(8.0, size / 0.9)) / log(2.0));
3721 nslots = (uint32_t)SCIPhashsetGetNSlots(*hashset);
3722 (*hashset)->nelements = 0;
3723
3724 SCIP_ALLOC( BMSallocClearBlockMemoryArray(blkmem, &(*hashset)->slots, nslots) );
3725
3726 return SCIP_OKAY;
3727 }
3728
3729 /** frees the hash set */
SCIPhashsetFree(SCIP_HASHSET ** hashset,BMS_BLKMEM * blkmem)3730 void SCIPhashsetFree(
3731 SCIP_HASHSET** hashset, /**< pointer to the hash set */
3732 BMS_BLKMEM* blkmem /**< block memory used to store hash set entries */
3733 )
3734 {
3735 BMSfreeBlockMemoryArray(blkmem, &(*hashset)->slots, SCIPhashsetGetNSlots(*hashset));
3736 BMSfreeBlockMemory(blkmem, hashset);
3737 }
3738
3739 /** inserts new element into the hash set */
SCIPhashsetInsert(SCIP_HASHSET * hashset,BMS_BLKMEM * blkmem,void * element)3740 SCIP_RETCODE SCIPhashsetInsert(
3741 SCIP_HASHSET* hashset, /**< hash set */
3742 BMS_BLKMEM* blkmem, /**< block memory used to store hash set entries */
3743 void* element /**< element to insert */
3744 )
3745 {
3746 assert(hashset != NULL);
3747 assert(hashset->slots != NULL);
3748
3749 SCIP_CALL( hashsetCheckLoad(hashset, blkmem) );
3750
3751 hashsetInsert(hashset, element);
3752
3753 return SCIP_OKAY;
3754 }
3755
3756 /** checks whether an element exists in the hash set */
SCIPhashsetExists(SCIP_HASHSET * hashset,void * element)3757 SCIP_Bool SCIPhashsetExists(
3758 SCIP_HASHSET* hashset, /**< hash set */
3759 void* element /**< element to search for */
3760 )
3761 {
3762 uint32_t pos;
3763 uint32_t nslots;
3764 uint32_t mask;
3765 uint32_t elemdistance;
3766
3767 assert(hashset != NULL);
3768 assert(hashset->slots != NULL);
3769
3770 pos = hashSetDesiredPos(hashset, element);
3771 nslots = (uint32_t)SCIPhashsetGetNSlots(hashset);
3772 mask = nslots - 1;
3773 elemdistance = 0;
3774
3775 while( TRUE ) /*lint !e716*/
3776 {
3777 uint32_t distance;
3778
3779 /* found element */
3780 if( hashset->slots[pos] == element )
3781 return TRUE;
3782
3783 /* slots is empty so element cannot be contained */
3784 if( hashset->slots[pos] == NULL )
3785 return FALSE;
3786
3787 distance = ELEM_DISTANCE(pos);
3788 /* element can not be contained since otherwise we would have swapped it with this one during insert */
3789 if( elemdistance > distance )
3790 return FALSE;
3791
3792 pos = (pos + 1) & mask;
3793 ++elemdistance;
3794 }
3795 }
3796
3797 /** removes an element from the hash set, if it exists */
SCIPhashsetRemove(SCIP_HASHSET * hashset,void * element)3798 SCIP_RETCODE SCIPhashsetRemove(
3799 SCIP_HASHSET* hashset, /**< hash set */
3800 void* element /**< origin to remove from the list */
3801 )
3802 {
3803 uint32_t pos;
3804 uint32_t nslots;
3805 uint32_t mask;
3806 uint32_t elemdistance;
3807
3808 assert(hashset != NULL);
3809 assert(hashset->slots != NULL);
3810 assert(element != NULL);
3811
3812 pos = hashSetDesiredPos(hashset, element);
3813 nslots = (uint32_t)SCIPhashsetGetNSlots(hashset);
3814 mask = nslots - 1;
3815 elemdistance = 0;
3816
3817 while( TRUE ) /*lint !e716*/
3818 {
3819 uint32_t distance;
3820
3821 /* found element */
3822 if( hashset->slots[pos] == element )
3823 break;
3824
3825 /* slots is empty so element cannot be contained */
3826 if( hashset->slots[pos] == NULL )
3827 return SCIP_OKAY;
3828
3829 distance = ELEM_DISTANCE(pos);
3830 /* element can not be contained since otherwise we would have swapped it with this one during insert */
3831 if( elemdistance > distance )
3832 return SCIP_OKAY;
3833
3834 pos = (pos + 1) & mask;
3835 ++elemdistance;
3836 }
3837
3838 assert(hashset->slots[pos] == element);
3839 assert(SCIPhashsetExists(hashset, element));
3840
3841 /* remove element */
3842 --hashset->nelements;
3843
3844 /* move other elements if necessary */
3845 while( TRUE ) /*lint !e716*/
3846 {
3847 uint32_t nextpos = (pos + 1) & mask;
3848
3849 /* nothing to do since there is no chain that needs to be moved */
3850 if( hashset->slots[nextpos] == NULL )
3851 {
3852 hashset->slots[pos] = NULL;
3853 assert(!SCIPhashsetExists(hashset, element));
3854 return SCIP_OKAY;
3855 }
3856
3857 /* check if the element is the start of a new chain and return if that is the case */
3858 if( hashSetDesiredPos(hashset, hashset->slots[nextpos]) == nextpos )
3859 {
3860 hashset->slots[pos] = NULL;
3861 assert(!SCIPhashsetExists(hashset, element));
3862 return SCIP_OKAY;
3863 }
3864
3865 /* element should be moved to the left and next element needs to be checked */
3866 hashset->slots[pos] = hashset->slots[nextpos];
3867
3868 pos = nextpos;
3869 }
3870 }
3871
3872 /** prints statistics about hash set usage */
SCIPhashsetPrintStatistics(SCIP_HASHSET * hashset,SCIP_MESSAGEHDLR * messagehdlr)3873 void SCIPhashsetPrintStatistics(
3874 SCIP_HASHSET* hashset, /**< hash set */
3875 SCIP_MESSAGEHDLR* messagehdlr /**< message handler */
3876 )
3877 {
3878 uint32_t maxprobelen = 0;
3879 uint64_t probelensum = 0;
3880 uint32_t nslots;
3881 uint32_t mask;
3882 uint32_t i;
3883
3884 assert(hashset != NULL);
3885
3886 nslots = (uint32_t)SCIPhashsetGetNSlots(hashset);
3887 mask = nslots - 1;
3888
3889 /* compute the maximum and average probe length */
3890 for( i = 0; i < nslots; ++i )
3891 {
3892 if( hashset->slots[i] != NULL )
3893 {
3894 uint32_t probelen = ((hashSetDesiredPos(hashset, hashset->slots[i]) + nslots - i) & mask) + 1;
3895 probelensum += probelen;
3896 maxprobelen = MAX(probelen, maxprobelen);
3897 }
3898 }
3899
3900 /* print general hash set statistics */
3901 SCIPmessagePrintInfo(messagehdlr, "%u hash entries, used %u/%u slots (%.1f%%)",
3902 (unsigned int)hashset->nelements, (unsigned int)hashset->nelements,
3903 (unsigned int)nslots, 100.0*(SCIP_Real)hashset->nelements/(SCIP_Real)(nslots));
3904
3905 /* if not empty print average and maximum probe length */
3906 if( hashset->nelements > 0 )
3907 SCIPmessagePrintInfo(messagehdlr, ", avg. probe length is %.1f, max. probe length is %u",
3908 (SCIP_Real)(probelensum)/(SCIP_Real)hashset->nelements, (unsigned int)maxprobelen);
3909 SCIPmessagePrintInfo(messagehdlr, "\n");
3910 }
3911
3912 /* In debug mode, the following methods are implemented as function calls to ensure
3913 * type validity.
3914 * In optimized mode, the methods are implemented as defines to improve performance.
3915 * However, we want to have them in the library anyways, so we have to undef the defines.
3916 */
3917
3918 #undef SCIPhashsetIsEmpty
3919 #undef SCIPhashsetGetNElements
3920 #undef SCIPhashsetGetNSlots
3921 #undef SCIPhashsetGetSlots
3922
3923 /** indicates whether a hash set has no entries */
SCIPhashsetIsEmpty(SCIP_HASHSET * hashset)3924 SCIP_Bool SCIPhashsetIsEmpty(
3925 SCIP_HASHSET* hashset /**< hash set */
3926 )
3927 {
3928 return hashset->nelements == 0;
3929 }
3930
3931 /** gives the number of elements in a hash set */
SCIPhashsetGetNElements(SCIP_HASHSET * hashset)3932 int SCIPhashsetGetNElements(
3933 SCIP_HASHSET* hashset /**< hash set */
3934 )
3935 {
3936 return (int)hashset->nelements;
3937 }
3938
3939 /** gives the number of slots of a hash set */
SCIPhashsetGetNSlots(SCIP_HASHSET * hashset)3940 int SCIPhashsetGetNSlots(
3941 SCIP_HASHSET* hashset /**< hash set */
3942 )
3943 {
3944 return (int) (1u << (64 - hashset->shift));
3945 }
3946
3947 /** gives the array of hash set slots; contains all elements in indetermined order and may contain NULL values */
SCIPhashsetGetSlots(SCIP_HASHSET * hashset)3948 void** SCIPhashsetGetSlots(
3949 SCIP_HASHSET* hashset /**< hash set */
3950 )
3951 {
3952 return hashset->slots;
3953 }
3954
3955 /** removes all entries in a hash set. */
SCIPhashsetRemoveAll(SCIP_HASHSET * hashset)3956 void SCIPhashsetRemoveAll(
3957 SCIP_HASHSET* hashset /**< hash set */
3958 )
3959 {
3960 BMSclearMemoryArray(hashset->slots, SCIPhashsetGetNSlots(hashset));
3961
3962 hashset->nelements = 0;
3963 }
3964
3965 /*
3966 * Dynamic Arrays
3967 */
3968
3969 /** creates a dynamic array of real values */
SCIPrealarrayCreate(SCIP_REALARRAY ** realarray,BMS_BLKMEM * blkmem)3970 SCIP_RETCODE SCIPrealarrayCreate(
3971 SCIP_REALARRAY** realarray, /**< pointer to store the real array */
3972 BMS_BLKMEM* blkmem /**< block memory */
3973 )
3974 {
3975 assert(realarray != NULL);
3976 assert(blkmem != NULL);
3977
3978 SCIP_ALLOC( BMSallocBlockMemory(blkmem, realarray) );
3979 (*realarray)->blkmem = blkmem;
3980 (*realarray)->vals = NULL;
3981 (*realarray)->valssize = 0;
3982 (*realarray)->firstidx = -1;
3983 (*realarray)->minusedidx = INT_MAX;
3984 (*realarray)->maxusedidx = INT_MIN;
3985
3986 return SCIP_OKAY;
3987 }
3988
3989 /** creates a copy of a dynamic array of real values */
SCIPrealarrayCopy(SCIP_REALARRAY ** realarray,BMS_BLKMEM * blkmem,SCIP_REALARRAY * sourcerealarray)3990 SCIP_RETCODE SCIPrealarrayCopy(
3991 SCIP_REALARRAY** realarray, /**< pointer to store the copied real array */
3992 BMS_BLKMEM* blkmem, /**< block memory */
3993 SCIP_REALARRAY* sourcerealarray /**< dynamic real array to copy */
3994 )
3995 {
3996 assert(realarray != NULL);
3997 assert(sourcerealarray != NULL);
3998
3999 SCIP_CALL( SCIPrealarrayCreate(realarray, blkmem) );
4000 if( sourcerealarray->valssize > 0 )
4001 {
4002 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*realarray)->vals, sourcerealarray->vals, \
4003 sourcerealarray->valssize) );
4004 }
4005 (*realarray)->valssize = sourcerealarray->valssize;
4006 (*realarray)->firstidx = sourcerealarray->firstidx;
4007 (*realarray)->minusedidx = sourcerealarray->minusedidx;
4008 (*realarray)->maxusedidx = sourcerealarray->maxusedidx;
4009
4010 return SCIP_OKAY;
4011 }
4012
4013 /** frees a dynamic array of real values */
SCIPrealarrayFree(SCIP_REALARRAY ** realarray)4014 SCIP_RETCODE SCIPrealarrayFree(
4015 SCIP_REALARRAY** realarray /**< pointer to the real array */
4016 )
4017 {
4018 assert(realarray != NULL);
4019 assert(*realarray != NULL);
4020
4021 BMSfreeBlockMemoryArrayNull((*realarray)->blkmem, &(*realarray)->vals, (*realarray)->valssize);
4022 BMSfreeBlockMemory((*realarray)->blkmem, realarray);
4023
4024 return SCIP_OKAY;
4025 }
4026
4027 /** extends dynamic array to be able to store indices from minidx to maxidx */
SCIPrealarrayExtend(SCIP_REALARRAY * realarray,int arraygrowinit,SCIP_Real arraygrowfac,int minidx,int maxidx)4028 SCIP_RETCODE SCIPrealarrayExtend(
4029 SCIP_REALARRAY* realarray, /**< dynamic real array */
4030 int arraygrowinit, /**< initial size of array */
4031 SCIP_Real arraygrowfac, /**< growing factor of array */
4032 int minidx, /**< smallest index to allocate storage for */
4033 int maxidx /**< largest index to allocate storage for */
4034 )
4035 {
4036 int nused;
4037 int nfree;
4038 int newfirstidx;
4039 int i;
4040
4041 assert(realarray != NULL);
4042 assert(realarray->minusedidx == INT_MAX || realarray->firstidx >= 0);
4043 assert(realarray->maxusedidx == INT_MIN || realarray->firstidx >= 0);
4044 assert(realarray->minusedidx == INT_MAX || realarray->minusedidx >= realarray->firstidx);
4045 assert(realarray->maxusedidx == INT_MIN || realarray->maxusedidx < realarray->firstidx + realarray->valssize);
4046 assert(0 <= minidx);
4047 assert(minidx <= maxidx);
4048
4049 minidx = MIN(minidx, realarray->minusedidx);
4050 maxidx = MAX(maxidx, realarray->maxusedidx);
4051 assert(0 <= minidx);
4052 assert(minidx <= maxidx);
4053
4054 SCIPdebugMessage("extending realarray %p (firstidx=%d, size=%d, range=[%d,%d]) to range [%d,%d]\n",
4055 (void*)realarray, realarray->firstidx, realarray->valssize, realarray->minusedidx, realarray->maxusedidx, minidx, maxidx);
4056
4057 /* check, whether we have to allocate additional memory, or shift the array */
4058 nused = maxidx - minidx + 1;
4059 if( nused > realarray->valssize )
4060 {
4061 SCIP_Real* newvals;
4062 int newvalssize;
4063
4064 /* allocate new memory storage */
4065 newvalssize = calcGrowSize(arraygrowinit, arraygrowfac, nused);
4066 SCIP_ALLOC( BMSallocBlockMemoryArray(realarray->blkmem, &newvals, newvalssize) );
4067 nfree = newvalssize - nused;
4068 newfirstidx = minidx - nfree/2;
4069 newfirstidx = MAX(newfirstidx, 0);
4070 assert(newfirstidx <= minidx);
4071 assert(maxidx < newfirstidx + newvalssize);
4072
4073 /* initialize memory array by copying old values and setting new values to zero */
4074 if( realarray->firstidx != -1 )
4075 {
4076 for( i = 0; i < realarray->minusedidx - newfirstidx; ++i )
4077 newvals[i] = 0.0;
4078
4079 /* check for possible overflow or negative value */
4080 assert(realarray->maxusedidx - realarray->minusedidx + 1 > 0);
4081
4082 BMScopyMemoryArray(&newvals[realarray->minusedidx - newfirstidx],
4083 &(realarray->vals[realarray->minusedidx - realarray->firstidx]),
4084 realarray->maxusedidx - realarray->minusedidx + 1); /*lint !e866 !e776*/
4085 for( i = realarray->maxusedidx - newfirstidx + 1; i < newvalssize; ++i )
4086 newvals[i] = 0.0;
4087 }
4088 else
4089 {
4090 for( i = 0; i < newvalssize; ++i )
4091 newvals[i] = 0.0;
4092 }
4093
4094 /* free old memory storage, and set the new array parameters */
4095 BMSfreeBlockMemoryArrayNull(realarray->blkmem, &realarray->vals, realarray->valssize);
4096 realarray->vals = newvals;
4097 realarray->valssize = newvalssize;
4098 realarray->firstidx = newfirstidx;
4099 }
4100 else if( realarray->firstidx == -1 )
4101 {
4102 /* a sufficiently large memory storage exists, but it was cleared */
4103 nfree = realarray->valssize - nused;
4104 assert(nfree >= 0);
4105 realarray->firstidx = minidx - nfree/2;
4106 assert(realarray->firstidx <= minidx);
4107 assert(maxidx < realarray->firstidx + realarray->valssize);
4108 #ifndef NDEBUG
4109 for( i = 0; i < realarray->valssize; ++i )
4110 assert(realarray->vals[i] == 0.0);
4111 #endif
4112 }
4113 else if( minidx < realarray->firstidx )
4114 {
4115 /* a sufficiently large memory storage exists, but it has to be shifted to the right */
4116 nfree = realarray->valssize - nused;
4117 assert(nfree >= 0);
4118 newfirstidx = minidx - nfree/2;
4119 newfirstidx = MAX(newfirstidx, 0);
4120 assert(newfirstidx <= minidx);
4121 assert(maxidx < newfirstidx + realarray->valssize);
4122
4123 if( realarray->minusedidx <= realarray->maxusedidx )
4124 {
4125 int shift;
4126
4127 assert(realarray->firstidx <= realarray->minusedidx);
4128 assert(realarray->maxusedidx < realarray->firstidx + realarray->valssize);
4129
4130 /* shift used part of array to the right */
4131 shift = realarray->firstidx - newfirstidx;
4132 assert(shift > 0);
4133 for( i = realarray->maxusedidx - realarray->firstidx; i >= realarray->minusedidx - realarray->firstidx; --i )
4134 {
4135 assert(0 <= i + shift && i + shift < realarray->valssize);
4136 realarray->vals[i + shift] = realarray->vals[i];
4137 }
4138 /* clear the formerly used head of the array */
4139 for( i = 0; i < shift; ++i )
4140 realarray->vals[realarray->minusedidx - realarray->firstidx + i] = 0.0;
4141 }
4142 realarray->firstidx = newfirstidx;
4143 }
4144 else if( maxidx >= realarray->firstidx + realarray->valssize )
4145 {
4146 /* a sufficiently large memory storage exists, but it has to be shifted to the left */
4147 nfree = realarray->valssize - nused;
4148 assert(nfree >= 0);
4149 newfirstidx = minidx - nfree/2;
4150 newfirstidx = MAX(newfirstidx, 0);
4151 assert(newfirstidx <= minidx);
4152 assert(maxidx < newfirstidx + realarray->valssize);
4153
4154 if( realarray->minusedidx <= realarray->maxusedidx )
4155 {
4156 int shift;
4157
4158 assert(realarray->firstidx <= realarray->minusedidx);
4159 assert(realarray->maxusedidx < realarray->firstidx + realarray->valssize);
4160
4161 /* shift used part of array to the left */
4162 shift = newfirstidx - realarray->firstidx;
4163 assert(shift > 0);
4164 for( i = realarray->minusedidx - realarray->firstidx; i <= realarray->maxusedidx - realarray->firstidx; ++i )
4165 {
4166 assert(0 <= i - shift && i - shift < realarray->valssize);
4167 realarray->vals[i - shift] = realarray->vals[i];
4168 }
4169 /* clear the formerly used tail of the array */
4170 for( i = 0; i < shift; ++i )
4171 realarray->vals[realarray->maxusedidx - realarray->firstidx - i] = 0.0;
4172 }
4173 realarray->firstidx = newfirstidx;
4174 }
4175
4176 assert(minidx >= realarray->firstidx);
4177 assert(maxidx < realarray->firstidx + realarray->valssize);
4178
4179 return SCIP_OKAY;
4180 }
4181
4182 /** clears a dynamic real array */
SCIPrealarrayClear(SCIP_REALARRAY * realarray)4183 SCIP_RETCODE SCIPrealarrayClear(
4184 SCIP_REALARRAY* realarray /**< dynamic real array */
4185 )
4186 {
4187 assert(realarray != NULL);
4188
4189 SCIPdebugMessage("clearing realarray %p (firstidx=%d, size=%d, range=[%d,%d])\n",
4190 (void*)realarray, realarray->firstidx, realarray->valssize, realarray->minusedidx, realarray->maxusedidx);
4191
4192 if( realarray->minusedidx <= realarray->maxusedidx )
4193 {
4194 assert(realarray->firstidx <= realarray->minusedidx);
4195 assert(realarray->maxusedidx < realarray->firstidx + realarray->valssize);
4196 assert(realarray->firstidx != -1);
4197 assert(realarray->valssize > 0);
4198
4199 /* clear the used part of array */
4200 BMSclearMemoryArray(&realarray->vals[realarray->minusedidx - realarray->firstidx],
4201 realarray->maxusedidx - realarray->minusedidx + 1); /*lint !e866*/
4202
4203 /* mark the array cleared */
4204 realarray->minusedidx = INT_MAX;
4205 realarray->maxusedidx = INT_MIN;
4206 }
4207 assert(realarray->minusedidx == INT_MAX);
4208 assert(realarray->maxusedidx == INT_MIN);
4209
4210 return SCIP_OKAY;
4211 }
4212
4213 /** gets value of entry in dynamic array */
SCIPrealarrayGetVal(SCIP_REALARRAY * realarray,int idx)4214 SCIP_Real SCIPrealarrayGetVal(
4215 SCIP_REALARRAY* realarray, /**< dynamic real array */
4216 int idx /**< array index to get value for */
4217 )
4218 {
4219 assert(realarray != NULL);
4220 assert(idx >= 0);
4221
4222 if( idx < realarray->minusedidx || idx > realarray->maxusedidx )
4223 return 0.0;
4224 else
4225 {
4226 assert(realarray->vals != NULL);
4227 assert(idx - realarray->firstidx >= 0);
4228 assert(idx - realarray->firstidx < realarray->valssize);
4229
4230 return realarray->vals[idx - realarray->firstidx];
4231 }
4232 }
4233
4234 /** sets value of entry in dynamic array */
SCIPrealarraySetVal(SCIP_REALARRAY * realarray,int arraygrowinit,SCIP_Real arraygrowfac,int idx,SCIP_Real val)4235 SCIP_RETCODE SCIPrealarraySetVal(
4236 SCIP_REALARRAY* realarray, /**< dynamic real array */
4237 int arraygrowinit, /**< initial size of array */
4238 SCIP_Real arraygrowfac, /**< growing factor of array */
4239 int idx, /**< array index to set value for */
4240 SCIP_Real val /**< value to set array index to */
4241 )
4242 {
4243 assert(realarray != NULL);
4244 assert(idx >= 0);
4245
4246 SCIPdebugMessage("setting realarray %p (firstidx=%d, size=%d, range=[%d,%d]) index %d to %g\n",
4247 (void*)realarray, realarray->firstidx, realarray->valssize, realarray->minusedidx, realarray->maxusedidx, idx, val);
4248
4249 if( val != 0.0 )
4250 {
4251 /* extend array to be able to store the index */
4252 SCIP_CALL( SCIPrealarrayExtend(realarray, arraygrowinit, arraygrowfac, idx, idx) );
4253 assert(idx >= realarray->firstidx);
4254 assert(idx < realarray->firstidx + realarray->valssize);
4255
4256 /* set the array value of the index */
4257 realarray->vals[idx - realarray->firstidx] = val;
4258
4259 /* update min/maxusedidx */
4260 realarray->minusedidx = MIN(realarray->minusedidx, idx);
4261 realarray->maxusedidx = MAX(realarray->maxusedidx, idx);
4262 }
4263 else if( idx >= realarray->firstidx && idx < realarray->firstidx + realarray->valssize )
4264 {
4265 /* set the array value of the index to zero */
4266 realarray->vals[idx - realarray->firstidx] = 0.0;
4267
4268 /* check, if we can tighten the min/maxusedidx */
4269 if( idx == realarray->minusedidx )
4270 {
4271 assert(realarray->maxusedidx >= 0);
4272 assert(realarray->maxusedidx < realarray->firstidx + realarray->valssize);
4273 do
4274 {
4275 realarray->minusedidx++;
4276 }
4277 while( realarray->minusedidx <= realarray->maxusedidx
4278 && realarray->vals[realarray->minusedidx - realarray->firstidx] == 0.0 );
4279
4280 if( realarray->minusedidx > realarray->maxusedidx )
4281 {
4282 realarray->minusedidx = INT_MAX;
4283 realarray->maxusedidx = INT_MIN;
4284 }
4285 }
4286 else if( idx == realarray->maxusedidx )
4287 {
4288 assert(realarray->minusedidx >= 0);
4289 assert(realarray->minusedidx < realarray->maxusedidx);
4290 assert(realarray->maxusedidx < realarray->firstidx + realarray->valssize);
4291 do
4292 {
4293 realarray->maxusedidx--;
4294 assert(realarray->minusedidx <= realarray->maxusedidx);
4295 }
4296 while( realarray->vals[realarray->maxusedidx - realarray->firstidx] == 0.0 );
4297 }
4298 }
4299
4300 return SCIP_OKAY;
4301 }
4302
4303 /** increases value of entry in dynamic array */
SCIPrealarrayIncVal(SCIP_REALARRAY * realarray,int arraygrowinit,SCIP_Real arraygrowfac,int idx,SCIP_Real incval)4304 SCIP_RETCODE SCIPrealarrayIncVal(
4305 SCIP_REALARRAY* realarray, /**< dynamic real array */
4306 int arraygrowinit, /**< initial size of array */
4307 SCIP_Real arraygrowfac, /**< growing factor of array */
4308 int idx, /**< array index to increase value for */
4309 SCIP_Real incval /**< value to increase array index */
4310 )
4311 {
4312 SCIP_Real oldval;
4313
4314 oldval = SCIPrealarrayGetVal(realarray, idx);
4315 if( oldval != SCIP_INVALID ) /*lint !e777*/
4316 return SCIPrealarraySetVal(realarray, arraygrowinit, arraygrowfac, idx, oldval + incval);
4317 else
4318 return SCIP_OKAY;
4319 }
4320
4321 /** returns the minimal index of all stored non-zero elements */
SCIPrealarrayGetMinIdx(SCIP_REALARRAY * realarray)4322 int SCIPrealarrayGetMinIdx(
4323 SCIP_REALARRAY* realarray /**< dynamic real array */
4324 )
4325 {
4326 assert(realarray != NULL);
4327
4328 return realarray->minusedidx;
4329 }
4330
4331 /** returns the maximal index of all stored non-zero elements */
SCIPrealarrayGetMaxIdx(SCIP_REALARRAY * realarray)4332 int SCIPrealarrayGetMaxIdx(
4333 SCIP_REALARRAY* realarray /**< dynamic real array */
4334 )
4335 {
4336 assert(realarray != NULL);
4337
4338 return realarray->maxusedidx;
4339 }
4340
4341 /** creates a dynamic array of int values */
SCIPintarrayCreate(SCIP_INTARRAY ** intarray,BMS_BLKMEM * blkmem)4342 SCIP_RETCODE SCIPintarrayCreate(
4343 SCIP_INTARRAY** intarray, /**< pointer to store the int array */
4344 BMS_BLKMEM* blkmem /**< block memory */
4345 )
4346 {
4347 assert(intarray != NULL);
4348 assert(blkmem != NULL);
4349
4350 SCIP_ALLOC( BMSallocBlockMemory(blkmem, intarray) );
4351 (*intarray)->blkmem = blkmem;
4352 (*intarray)->vals = NULL;
4353 (*intarray)->valssize = 0;
4354 (*intarray)->firstidx = -1;
4355 (*intarray)->minusedidx = INT_MAX;
4356 (*intarray)->maxusedidx = INT_MIN;
4357
4358 return SCIP_OKAY;
4359 }
4360
4361 /** creates a copy of a dynamic array of int values */
SCIPintarrayCopy(SCIP_INTARRAY ** intarray,BMS_BLKMEM * blkmem,SCIP_INTARRAY * sourceintarray)4362 SCIP_RETCODE SCIPintarrayCopy(
4363 SCIP_INTARRAY** intarray, /**< pointer to store the copied int array */
4364 BMS_BLKMEM* blkmem, /**< block memory */
4365 SCIP_INTARRAY* sourceintarray /**< dynamic int array to copy */
4366 )
4367 {
4368 assert(intarray != NULL);
4369 assert(sourceintarray != NULL);
4370
4371 SCIP_CALL( SCIPintarrayCreate(intarray, blkmem) );
4372 if( sourceintarray->valssize > 0 )
4373 {
4374 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*intarray)->vals, sourceintarray->vals, sourceintarray->valssize) );
4375 }
4376 (*intarray)->valssize = sourceintarray->valssize;
4377 (*intarray)->firstidx = sourceintarray->firstidx;
4378 (*intarray)->minusedidx = sourceintarray->minusedidx;
4379 (*intarray)->maxusedidx = sourceintarray->maxusedidx;
4380
4381 return SCIP_OKAY;
4382 }
4383
4384 /** frees a dynamic array of int values */
SCIPintarrayFree(SCIP_INTARRAY ** intarray)4385 SCIP_RETCODE SCIPintarrayFree(
4386 SCIP_INTARRAY** intarray /**< pointer to the int array */
4387 )
4388 {
4389 assert(intarray != NULL);
4390 assert(*intarray != NULL);
4391
4392 BMSfreeBlockMemoryArrayNull((*intarray)->blkmem, &(*intarray)->vals, (*intarray)->valssize);
4393 BMSfreeBlockMemory((*intarray)->blkmem, intarray);
4394
4395 return SCIP_OKAY;
4396 }
4397
4398 /** extends dynamic array to be able to store indices from minidx to maxidx */
SCIPintarrayExtend(SCIP_INTARRAY * intarray,int arraygrowinit,SCIP_Real arraygrowfac,int minidx,int maxidx)4399 SCIP_RETCODE SCIPintarrayExtend(
4400 SCIP_INTARRAY* intarray, /**< dynamic int array */
4401 int arraygrowinit, /**< initial size of array */
4402 SCIP_Real arraygrowfac, /**< growing factor of array */
4403 int minidx, /**< smallest index to allocate storage for */
4404 int maxidx /**< largest index to allocate storage for */
4405 )
4406 {
4407 int nused;
4408 int nfree;
4409 int newfirstidx;
4410 int i;
4411
4412 assert(intarray != NULL);
4413 assert(intarray->minusedidx == INT_MAX || intarray->firstidx >= 0);
4414 assert(intarray->maxusedidx == INT_MIN || intarray->firstidx >= 0);
4415 assert(intarray->minusedidx == INT_MAX || intarray->minusedidx >= intarray->firstidx);
4416 assert(intarray->maxusedidx == INT_MIN || intarray->maxusedidx < intarray->firstidx + intarray->valssize);
4417 assert(0 <= minidx);
4418 assert(minidx <= maxidx);
4419
4420 minidx = MIN(minidx, intarray->minusedidx);
4421 maxidx = MAX(maxidx, intarray->maxusedidx);
4422 assert(0 <= minidx);
4423 assert(minidx <= maxidx);
4424
4425 SCIPdebugMessage("extending intarray %p (firstidx=%d, size=%d, range=[%d,%d]) to range [%d,%d]\n",
4426 (void*)intarray, intarray->firstidx, intarray->valssize, intarray->minusedidx, intarray->maxusedidx, minidx, maxidx);
4427
4428 /* check, whether we have to allocate additional memory, or shift the array */
4429 nused = maxidx - minidx + 1;
4430 if( nused > intarray->valssize )
4431 {
4432 int* newvals;
4433 int newvalssize;
4434
4435 /* allocate new memory storage */
4436 newvalssize = calcGrowSize(arraygrowinit, arraygrowfac, nused);
4437 SCIP_ALLOC( BMSallocBlockMemoryArray(intarray->blkmem, &newvals, newvalssize) );
4438 nfree = newvalssize - nused;
4439 newfirstidx = minidx - nfree/2;
4440 newfirstidx = MAX(newfirstidx, 0);
4441 assert(newfirstidx <= minidx);
4442 assert(maxidx < newfirstidx + newvalssize);
4443
4444 /* initialize memory array by copying old values and setting new values to zero */
4445 if( intarray->firstidx != -1 )
4446 {
4447 for( i = 0; i < intarray->minusedidx - newfirstidx; ++i )
4448 newvals[i] = 0;
4449
4450 /* check for possible overflow or negative value */
4451 assert(intarray->maxusedidx - intarray->minusedidx + 1 > 0);
4452
4453 BMScopyMemoryArray(&newvals[intarray->minusedidx - newfirstidx],
4454 &intarray->vals[intarray->minusedidx - intarray->firstidx],
4455 intarray->maxusedidx - intarray->minusedidx + 1); /*lint !e866 !e776*/
4456 for( i = intarray->maxusedidx - newfirstidx + 1; i < newvalssize; ++i )
4457 newvals[i] = 0;
4458 }
4459 else
4460 {
4461 for( i = 0; i < newvalssize; ++i )
4462 newvals[i] = 0;
4463 }
4464
4465 /* free old memory storage, and set the new array parameters */
4466 BMSfreeBlockMemoryArrayNull(intarray->blkmem, &intarray->vals, intarray->valssize);
4467 intarray->vals = newvals;
4468 intarray->valssize = newvalssize;
4469 intarray->firstidx = newfirstidx;
4470 }
4471 else if( intarray->firstidx == -1 )
4472 {
4473 /* a sufficiently large memory storage exists, but it was cleared */
4474 nfree = intarray->valssize - nused;
4475 assert(nfree >= 0);
4476 intarray->firstidx = minidx - nfree/2;
4477 assert(intarray->firstidx <= minidx);
4478 assert(maxidx < intarray->firstidx + intarray->valssize);
4479 #ifndef NDEBUG
4480 for( i = 0; i < intarray->valssize; ++i )
4481 assert(intarray->vals[i] == 0);
4482 #endif
4483 }
4484 else if( minidx < intarray->firstidx )
4485 {
4486 /* a sufficiently large memory storage exists, but it has to be shifted to the right */
4487 nfree = intarray->valssize - nused;
4488 assert(nfree >= 0);
4489 newfirstidx = minidx - nfree/2;
4490 newfirstidx = MAX(newfirstidx, 0);
4491 assert(newfirstidx <= minidx);
4492 assert(maxidx < newfirstidx + intarray->valssize);
4493
4494 if( intarray->minusedidx <= intarray->maxusedidx )
4495 {
4496 int shift;
4497
4498 assert(intarray->firstidx <= intarray->minusedidx);
4499 assert(intarray->maxusedidx < intarray->firstidx + intarray->valssize);
4500
4501 /* shift used part of array to the right */
4502 shift = intarray->firstidx - newfirstidx;
4503 assert(shift > 0);
4504 for( i = intarray->maxusedidx - intarray->firstidx; i >= intarray->minusedidx - intarray->firstidx; --i )
4505 {
4506 assert(0 <= i + shift && i + shift < intarray->valssize);
4507 intarray->vals[i + shift] = intarray->vals[i];
4508 }
4509 /* clear the formerly used head of the array */
4510 for( i = 0; i < shift; ++i )
4511 intarray->vals[intarray->minusedidx - intarray->firstidx + i] = 0;
4512 }
4513 intarray->firstidx = newfirstidx;
4514 }
4515 else if( maxidx >= intarray->firstidx + intarray->valssize )
4516 {
4517 /* a sufficiently large memory storage exists, but it has to be shifted to the left */
4518 nfree = intarray->valssize - nused;
4519 assert(nfree >= 0);
4520 newfirstidx = minidx - nfree/2;
4521 newfirstidx = MAX(newfirstidx, 0);
4522 assert(newfirstidx <= minidx);
4523 assert(maxidx < newfirstidx + intarray->valssize);
4524
4525 if( intarray->minusedidx <= intarray->maxusedidx )
4526 {
4527 int shift;
4528
4529 assert(intarray->firstidx <= intarray->minusedidx);
4530 assert(intarray->maxusedidx < intarray->firstidx + intarray->valssize);
4531
4532 /* shift used part of array to the left */
4533 shift = newfirstidx - intarray->firstidx;
4534 assert(shift > 0);
4535 for( i = intarray->minusedidx - intarray->firstidx; i <= intarray->maxusedidx - intarray->firstidx; ++i )
4536 {
4537 assert(0 <= i - shift && i - shift < intarray->valssize);
4538 intarray->vals[i - shift] = intarray->vals[i];
4539 }
4540 /* clear the formerly used tail of the array */
4541 for( i = 0; i < shift; ++i )
4542 intarray->vals[intarray->maxusedidx - intarray->firstidx - i] = 0;
4543 }
4544 intarray->firstidx = newfirstidx;
4545 }
4546
4547 assert(minidx >= intarray->firstidx);
4548 assert(maxidx < intarray->firstidx + intarray->valssize);
4549
4550 return SCIP_OKAY;
4551 }
4552
4553 /** clears a dynamic int array */
SCIPintarrayClear(SCIP_INTARRAY * intarray)4554 SCIP_RETCODE SCIPintarrayClear(
4555 SCIP_INTARRAY* intarray /**< dynamic int array */
4556 )
4557 {
4558 assert(intarray != NULL);
4559
4560 SCIPdebugMessage("clearing intarray %p (firstidx=%d, size=%d, range=[%d,%d])\n",
4561 (void*)intarray, intarray->firstidx, intarray->valssize, intarray->minusedidx, intarray->maxusedidx);
4562
4563 if( intarray->minusedidx <= intarray->maxusedidx )
4564 {
4565 assert(intarray->firstidx <= intarray->minusedidx);
4566 assert(intarray->maxusedidx < intarray->firstidx + intarray->valssize);
4567 assert(intarray->firstidx != -1);
4568 assert(intarray->valssize > 0);
4569
4570 /* clear the used part of array */
4571 BMSclearMemoryArray(&intarray->vals[intarray->minusedidx - intarray->firstidx],
4572 intarray->maxusedidx - intarray->minusedidx + 1); /*lint !e866*/
4573
4574 /* mark the array cleared */
4575 intarray->minusedidx = INT_MAX;
4576 intarray->maxusedidx = INT_MIN;
4577 }
4578 assert(intarray->minusedidx == INT_MAX);
4579 assert(intarray->maxusedidx == INT_MIN);
4580
4581 return SCIP_OKAY;
4582 }
4583
4584 /** gets value of entry in dynamic array */
SCIPintarrayGetVal(SCIP_INTARRAY * intarray,int idx)4585 int SCIPintarrayGetVal(
4586 SCIP_INTARRAY* intarray, /**< dynamic int array */
4587 int idx /**< array index to get value for */
4588 )
4589 {
4590 assert(intarray != NULL);
4591 assert(idx >= 0);
4592
4593 if( idx < intarray->minusedidx || idx > intarray->maxusedidx )
4594 return 0;
4595 else
4596 {
4597 assert(intarray->vals != NULL);
4598 assert(idx - intarray->firstidx >= 0);
4599 assert(idx - intarray->firstidx < intarray->valssize);
4600
4601 return intarray->vals[idx - intarray->firstidx];
4602 }
4603 }
4604
4605 /** sets value of entry in dynamic array */
SCIPintarraySetVal(SCIP_INTARRAY * intarray,int arraygrowinit,SCIP_Real arraygrowfac,int idx,int val)4606 SCIP_RETCODE SCIPintarraySetVal(
4607 SCIP_INTARRAY* intarray, /**< dynamic int array */
4608 int arraygrowinit, /**< initial size of array */
4609 SCIP_Real arraygrowfac, /**< growing factor of array */
4610 int idx, /**< array index to set value for */
4611 int val /**< value to set array index to */
4612 )
4613 {
4614 assert(intarray != NULL);
4615 assert(idx >= 0);
4616
4617 SCIPdebugMessage("setting intarray %p (firstidx=%d, size=%d, range=[%d,%d]) index %d to %d\n",
4618 (void*)intarray, intarray->firstidx, intarray->valssize, intarray->minusedidx, intarray->maxusedidx, idx, val);
4619
4620 if( val != 0 )
4621 {
4622 /* extend array to be able to store the index */
4623 SCIP_CALL( SCIPintarrayExtend(intarray, arraygrowinit, arraygrowfac, idx, idx) );
4624 assert(idx >= intarray->firstidx);
4625 assert(idx < intarray->firstidx + intarray->valssize);
4626
4627 /* set the array value of the index */
4628 intarray->vals[idx - intarray->firstidx] = val;
4629
4630 /* update min/maxusedidx */
4631 intarray->minusedidx = MIN(intarray->minusedidx, idx);
4632 intarray->maxusedidx = MAX(intarray->maxusedidx, idx);
4633 }
4634 else if( idx >= intarray->firstidx && idx < intarray->firstidx + intarray->valssize )
4635 {
4636 /* set the array value of the index to zero */
4637 intarray->vals[idx - intarray->firstidx] = 0;
4638
4639 /* check, if we can tighten the min/maxusedidx */
4640 if( idx == intarray->minusedidx )
4641 {
4642 assert(intarray->maxusedidx >= 0);
4643 assert(intarray->maxusedidx < intarray->firstidx + intarray->valssize);
4644 do
4645 {
4646 intarray->minusedidx++;
4647 }
4648 while( intarray->minusedidx <= intarray->maxusedidx
4649 && intarray->vals[intarray->minusedidx - intarray->firstidx] == 0 );
4650 if( intarray->minusedidx > intarray->maxusedidx )
4651 {
4652 intarray->minusedidx = INT_MAX;
4653 intarray->maxusedidx = INT_MIN;
4654 }
4655 }
4656 else if( idx == intarray->maxusedidx )
4657 {
4658 assert(intarray->minusedidx >= 0);
4659 assert(intarray->minusedidx < intarray->maxusedidx);
4660 assert(intarray->maxusedidx < intarray->firstidx + intarray->valssize);
4661 do
4662 {
4663 intarray->maxusedidx--;
4664 assert(intarray->minusedidx <= intarray->maxusedidx);
4665 }
4666 while( intarray->vals[intarray->maxusedidx - intarray->firstidx] == 0 );
4667 }
4668 }
4669
4670 return SCIP_OKAY;
4671 }
4672
4673 /** increases value of entry in dynamic array */
SCIPintarrayIncVal(SCIP_INTARRAY * intarray,int arraygrowinit,SCIP_Real arraygrowfac,int idx,int incval)4674 SCIP_RETCODE SCIPintarrayIncVal(
4675 SCIP_INTARRAY* intarray, /**< dynamic int array */
4676 int arraygrowinit, /**< initial size of array */
4677 SCIP_Real arraygrowfac, /**< growing factor of array */
4678 int idx, /**< array index to increase value for */
4679 int incval /**< value to increase array index */
4680 )
4681 {
4682 return SCIPintarraySetVal(intarray, arraygrowinit, arraygrowfac, idx, SCIPintarrayGetVal(intarray, idx) + incval);
4683 }
4684
4685 /** returns the minimal index of all stored non-zero elements */
SCIPintarrayGetMinIdx(SCIP_INTARRAY * intarray)4686 int SCIPintarrayGetMinIdx(
4687 SCIP_INTARRAY* intarray /**< dynamic int array */
4688 )
4689 {
4690 assert(intarray != NULL);
4691
4692 return intarray->minusedidx;
4693 }
4694
4695 /** returns the maximal index of all stored non-zero elements */
SCIPintarrayGetMaxIdx(SCIP_INTARRAY * intarray)4696 int SCIPintarrayGetMaxIdx(
4697 SCIP_INTARRAY* intarray /**< dynamic int array */
4698 )
4699 {
4700 assert(intarray != NULL);
4701
4702 return intarray->maxusedidx;
4703 }
4704
4705
4706 /** creates a dynamic array of bool values */
SCIPboolarrayCreate(SCIP_BOOLARRAY ** boolarray,BMS_BLKMEM * blkmem)4707 SCIP_RETCODE SCIPboolarrayCreate(
4708 SCIP_BOOLARRAY** boolarray, /**< pointer to store the bool array */
4709 BMS_BLKMEM* blkmem /**< block memory */
4710 )
4711 {
4712 assert(boolarray != NULL);
4713 assert(blkmem != NULL);
4714
4715 SCIP_ALLOC( BMSallocBlockMemory(blkmem, boolarray) );
4716 (*boolarray)->blkmem = blkmem;
4717 (*boolarray)->vals = NULL;
4718 (*boolarray)->valssize = 0;
4719 (*boolarray)->firstidx = -1;
4720 (*boolarray)->minusedidx = INT_MAX;
4721 (*boolarray)->maxusedidx = INT_MIN;
4722
4723 return SCIP_OKAY;
4724 }
4725
4726 /** creates a copy of a dynamic array of bool values */
SCIPboolarrayCopy(SCIP_BOOLARRAY ** boolarray,BMS_BLKMEM * blkmem,SCIP_BOOLARRAY * sourceboolarray)4727 SCIP_RETCODE SCIPboolarrayCopy(
4728 SCIP_BOOLARRAY** boolarray, /**< pointer to store the copied bool array */
4729 BMS_BLKMEM* blkmem, /**< block memory */
4730 SCIP_BOOLARRAY* sourceboolarray /**< dynamic bool array to copy */
4731 )
4732 {
4733 assert(boolarray != NULL);
4734 assert(sourceboolarray != NULL);
4735
4736 SCIP_CALL( SCIPboolarrayCreate(boolarray, blkmem) );
4737 if( sourceboolarray->valssize > 0 )
4738 {
4739 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*boolarray)->vals, sourceboolarray->vals, \
4740 sourceboolarray->valssize) );
4741 }
4742 (*boolarray)->valssize = sourceboolarray->valssize;
4743 (*boolarray)->firstidx = sourceboolarray->firstidx;
4744 (*boolarray)->minusedidx = sourceboolarray->minusedidx;
4745 (*boolarray)->maxusedidx = sourceboolarray->maxusedidx;
4746
4747 return SCIP_OKAY;
4748 }
4749
4750 /** frees a dynamic array of bool values */
SCIPboolarrayFree(SCIP_BOOLARRAY ** boolarray)4751 SCIP_RETCODE SCIPboolarrayFree(
4752 SCIP_BOOLARRAY** boolarray /**< pointer to the bool array */
4753 )
4754 {
4755 assert(boolarray != NULL);
4756 assert(*boolarray != NULL);
4757
4758 BMSfreeBlockMemoryArrayNull((*boolarray)->blkmem, &(*boolarray)->vals, (*boolarray)->valssize);
4759 BMSfreeBlockMemory((*boolarray)->blkmem, boolarray);
4760
4761 return SCIP_OKAY;
4762 }
4763
4764 /** extends dynamic array to be able to store indices from minidx to maxidx */
SCIPboolarrayExtend(SCIP_BOOLARRAY * boolarray,int arraygrowinit,SCIP_Real arraygrowfac,int minidx,int maxidx)4765 SCIP_RETCODE SCIPboolarrayExtend(
4766 SCIP_BOOLARRAY* boolarray, /**< dynamic bool array */
4767 int arraygrowinit, /**< initial size of array */
4768 SCIP_Real arraygrowfac, /**< growing factor of array */
4769 int minidx, /**< smallest index to allocate storage for */
4770 int maxidx /**< largest index to allocate storage for */
4771 )
4772 {
4773 int nused;
4774 int nfree;
4775 int newfirstidx;
4776 int i;
4777
4778 assert(boolarray != NULL);
4779 assert(boolarray->minusedidx == INT_MAX || boolarray->firstidx >= 0);
4780 assert(boolarray->maxusedidx == INT_MIN || boolarray->firstidx >= 0);
4781 assert(boolarray->minusedidx == INT_MAX || boolarray->minusedidx >= boolarray->firstidx);
4782 assert(boolarray->maxusedidx == INT_MIN || boolarray->maxusedidx < boolarray->firstidx + boolarray->valssize);
4783 assert(0 <= minidx);
4784 assert(minidx <= maxidx);
4785
4786 minidx = MIN(minidx, boolarray->minusedidx);
4787 maxidx = MAX(maxidx, boolarray->maxusedidx);
4788 assert(0 <= minidx);
4789 assert(minidx <= maxidx);
4790
4791 SCIPdebugMessage("extending boolarray %p (firstidx=%d, size=%d, range=[%d,%d]) to range [%d,%d]\n",
4792 (void*)boolarray, boolarray->firstidx, boolarray->valssize, boolarray->minusedidx, boolarray->maxusedidx, minidx, maxidx);
4793
4794 /* check, whether we have to allocate additional memory, or shift the array */
4795 nused = maxidx - minidx + 1;
4796 if( nused > boolarray->valssize )
4797 {
4798 SCIP_Bool* newvals;
4799 int newvalssize;
4800
4801 /* allocate new memory storage */
4802 newvalssize = calcGrowSize(arraygrowinit, arraygrowfac, nused);
4803 SCIP_ALLOC( BMSallocBlockMemoryArray(boolarray->blkmem, &newvals, newvalssize) );
4804 nfree = newvalssize - nused;
4805 newfirstidx = minidx - nfree/2;
4806 newfirstidx = MAX(newfirstidx, 0);
4807 assert(newfirstidx <= minidx);
4808 assert(maxidx < newfirstidx + newvalssize);
4809
4810 /* initialize memory array by copying old values and setting new values to zero */
4811 if( boolarray->firstidx != -1 )
4812 {
4813 for( i = 0; i < boolarray->minusedidx - newfirstidx; ++i )
4814 newvals[i] = FALSE;
4815
4816 /* check for possible overflow or negative value */
4817 assert(boolarray->maxusedidx - boolarray->minusedidx + 1 > 0);
4818
4819 BMScopyMemoryArray(&newvals[boolarray->minusedidx - newfirstidx],
4820 &boolarray->vals[boolarray->minusedidx - boolarray->firstidx],
4821 boolarray->maxusedidx - boolarray->minusedidx + 1); /*lint !e866 !e776*/
4822 for( i = boolarray->maxusedidx - newfirstidx + 1; i < newvalssize; ++i )
4823 newvals[i] = FALSE;
4824 }
4825 else
4826 {
4827 for( i = 0; i < newvalssize; ++i )
4828 newvals[i] = FALSE;
4829 }
4830
4831 /* free old memory storage, and set the new array parameters */
4832 BMSfreeBlockMemoryArrayNull(boolarray->blkmem, &boolarray->vals, boolarray->valssize);
4833 boolarray->vals = newvals;
4834 boolarray->valssize = newvalssize;
4835 boolarray->firstidx = newfirstidx;
4836 }
4837 else if( boolarray->firstidx == -1 )
4838 {
4839 /* a sufficiently large memory storage exists, but it was cleared */
4840 nfree = boolarray->valssize - nused;
4841 assert(nfree >= 0);
4842 boolarray->firstidx = minidx - nfree/2;
4843 assert(boolarray->firstidx <= minidx);
4844 assert(maxidx < boolarray->firstidx + boolarray->valssize);
4845 #ifndef NDEBUG
4846 for( i = 0; i < boolarray->valssize; ++i )
4847 assert(boolarray->vals[i] == FALSE);
4848 #endif
4849 }
4850 else if( minidx < boolarray->firstidx )
4851 {
4852 /* a sufficiently large memory storage exists, but it has to be shifted to the right */
4853 nfree = boolarray->valssize - nused;
4854 assert(nfree >= 0);
4855 newfirstidx = minidx - nfree/2;
4856 newfirstidx = MAX(newfirstidx, 0);
4857 assert(newfirstidx <= minidx);
4858 assert(maxidx < newfirstidx + boolarray->valssize);
4859
4860 if( boolarray->minusedidx <= boolarray->maxusedidx )
4861 {
4862 int shift;
4863
4864 assert(boolarray->firstidx <= boolarray->minusedidx);
4865 assert(boolarray->maxusedidx < boolarray->firstidx + boolarray->valssize);
4866
4867 /* shift used part of array to the right */
4868 shift = boolarray->firstidx - newfirstidx;
4869 assert(shift > 0);
4870 for( i = boolarray->maxusedidx - boolarray->firstidx; i >= boolarray->minusedidx - boolarray->firstidx; --i )
4871 {
4872 assert(0 <= i + shift && i + shift < boolarray->valssize);
4873 boolarray->vals[i + shift] = boolarray->vals[i];
4874 }
4875 /* clear the formerly used head of the array */
4876 for( i = 0; i < shift; ++i )
4877 boolarray->vals[boolarray->minusedidx - boolarray->firstidx + i] = FALSE;
4878 }
4879 boolarray->firstidx = newfirstidx;
4880 }
4881 else if( maxidx >= boolarray->firstidx + boolarray->valssize )
4882 {
4883 /* a sufficiently large memory storage exists, but it has to be shifted to the left */
4884 nfree = boolarray->valssize - nused;
4885 assert(nfree >= 0);
4886 newfirstidx = minidx - nfree/2;
4887 newfirstidx = MAX(newfirstidx, 0);
4888 assert(newfirstidx <= minidx);
4889 assert(maxidx < newfirstidx + boolarray->valssize);
4890
4891 if( boolarray->minusedidx <= boolarray->maxusedidx )
4892 {
4893 int shift;
4894
4895 assert(boolarray->firstidx <= boolarray->minusedidx);
4896 assert(boolarray->maxusedidx < boolarray->firstidx + boolarray->valssize);
4897
4898 /* shift used part of array to the left */
4899 shift = newfirstidx - boolarray->firstidx;
4900 assert(shift > 0);
4901
4902 assert(0 <= boolarray->minusedidx - boolarray->firstidx - shift);
4903 assert(boolarray->maxusedidx - boolarray->firstidx - shift < boolarray->valssize);
4904 BMSmoveMemoryArray(&(boolarray->vals[boolarray->minusedidx - boolarray->firstidx - shift]),
4905 &(boolarray->vals[boolarray->minusedidx - boolarray->firstidx]),
4906 boolarray->maxusedidx - boolarray->minusedidx + 1); /*lint !e866*/
4907
4908 /* clear the formerly used tail of the array */
4909 for( i = 0; i < shift; ++i )
4910 boolarray->vals[boolarray->maxusedidx - boolarray->firstidx - i] = FALSE;
4911 }
4912 boolarray->firstidx = newfirstidx;
4913 }
4914
4915 assert(minidx >= boolarray->firstidx);
4916 assert(maxidx < boolarray->firstidx + boolarray->valssize);
4917
4918 return SCIP_OKAY;
4919 }
4920
4921 /** clears a dynamic bool array */
SCIPboolarrayClear(SCIP_BOOLARRAY * boolarray)4922 SCIP_RETCODE SCIPboolarrayClear(
4923 SCIP_BOOLARRAY* boolarray /**< dynamic bool array */
4924 )
4925 {
4926 assert(boolarray != NULL);
4927
4928 SCIPdebugMessage("clearing boolarray %p (firstidx=%d, size=%d, range=[%d,%d])\n",
4929 (void*)boolarray, boolarray->firstidx, boolarray->valssize, boolarray->minusedidx, boolarray->maxusedidx);
4930
4931 if( boolarray->minusedidx <= boolarray->maxusedidx )
4932 {
4933 assert(boolarray->firstidx <= boolarray->minusedidx);
4934 assert(boolarray->maxusedidx < boolarray->firstidx + boolarray->valssize);
4935 assert(boolarray->firstidx != -1);
4936 assert(boolarray->valssize > 0);
4937
4938 /* clear the used part of array */
4939 BMSclearMemoryArray(&boolarray->vals[boolarray->minusedidx - boolarray->firstidx],
4940 boolarray->maxusedidx - boolarray->minusedidx + 1); /*lint !e866*/
4941
4942 /* mark the array cleared */
4943 boolarray->minusedidx = INT_MAX;
4944 boolarray->maxusedidx = INT_MIN;
4945 }
4946 assert(boolarray->minusedidx == INT_MAX);
4947 assert(boolarray->maxusedidx == INT_MIN);
4948
4949 return SCIP_OKAY;
4950 }
4951
4952 /** gets value of entry in dynamic array */
SCIPboolarrayGetVal(SCIP_BOOLARRAY * boolarray,int idx)4953 SCIP_Bool SCIPboolarrayGetVal(
4954 SCIP_BOOLARRAY* boolarray, /**< dynamic bool array */
4955 int idx /**< array index to get value for */
4956 )
4957 {
4958 assert(boolarray != NULL);
4959 assert(idx >= 0);
4960
4961 if( idx < boolarray->minusedidx || idx > boolarray->maxusedidx )
4962 return FALSE;
4963 else
4964 {
4965 assert(boolarray->vals != NULL);
4966 assert(idx - boolarray->firstidx >= 0);
4967 assert(idx - boolarray->firstidx < boolarray->valssize);
4968
4969 return boolarray->vals[idx - boolarray->firstidx];
4970 }
4971 }
4972
4973 /** sets value of entry in dynamic array */
SCIPboolarraySetVal(SCIP_BOOLARRAY * boolarray,int arraygrowinit,SCIP_Real arraygrowfac,int idx,SCIP_Bool val)4974 SCIP_RETCODE SCIPboolarraySetVal(
4975 SCIP_BOOLARRAY* boolarray, /**< dynamic bool array */
4976 int arraygrowinit, /**< initial size of array */
4977 SCIP_Real arraygrowfac, /**< growing factor of array */
4978 int idx, /**< array index to set value for */
4979 SCIP_Bool val /**< value to set array index to */
4980 )
4981 {
4982 assert(boolarray != NULL);
4983 assert(idx >= 0);
4984
4985 SCIPdebugMessage("setting boolarray %p (firstidx=%d, size=%d, range=[%d,%d]) index %d to %u\n",
4986 (void*)boolarray, boolarray->firstidx, boolarray->valssize, boolarray->minusedidx, boolarray->maxusedidx, idx, val);
4987
4988 if( val != FALSE )
4989 {
4990 /* extend array to be able to store the index */
4991 SCIP_CALL( SCIPboolarrayExtend(boolarray, arraygrowinit, arraygrowfac, idx, idx) );
4992 assert(idx >= boolarray->firstidx);
4993 assert(idx < boolarray->firstidx + boolarray->valssize);
4994
4995 /* set the array value of the index */
4996 boolarray->vals[idx - boolarray->firstidx] = val;
4997
4998 /* update min/maxusedidx */
4999 boolarray->minusedidx = MIN(boolarray->minusedidx, idx);
5000 boolarray->maxusedidx = MAX(boolarray->maxusedidx, idx);
5001 }
5002 else if( idx >= boolarray->firstidx && idx < boolarray->firstidx + boolarray->valssize )
5003 {
5004 /* set the array value of the index to zero */
5005 boolarray->vals[idx - boolarray->firstidx] = FALSE;
5006
5007 /* check, if we can tighten the min/maxusedidx */
5008 if( idx == boolarray->minusedidx )
5009 {
5010 assert(boolarray->maxusedidx >= 0);
5011 assert(boolarray->maxusedidx < boolarray->firstidx + boolarray->valssize);
5012 do
5013 {
5014 boolarray->minusedidx++;
5015 }
5016 while( boolarray->minusedidx <= boolarray->maxusedidx
5017 && boolarray->vals[boolarray->minusedidx - boolarray->firstidx] == FALSE );
5018 if( boolarray->minusedidx > boolarray->maxusedidx )
5019 {
5020 boolarray->minusedidx = INT_MAX;
5021 boolarray->maxusedidx = INT_MIN;
5022 }
5023 }
5024 else if( idx == boolarray->maxusedidx )
5025 {
5026 assert(boolarray->minusedidx >= 0);
5027 assert(boolarray->minusedidx < boolarray->maxusedidx);
5028 assert(boolarray->maxusedidx < boolarray->firstidx + boolarray->valssize);
5029 do
5030 {
5031 boolarray->maxusedidx--;
5032 assert(boolarray->minusedidx <= boolarray->maxusedidx);
5033 }
5034 while( boolarray->vals[boolarray->maxusedidx - boolarray->firstidx] == FALSE );
5035 }
5036 }
5037
5038 return SCIP_OKAY;
5039 }
5040
5041 /** returns the minimal index of all stored non-zero elements */
SCIPboolarrayGetMinIdx(SCIP_BOOLARRAY * boolarray)5042 int SCIPboolarrayGetMinIdx(
5043 SCIP_BOOLARRAY* boolarray /**< dynamic bool array */
5044 )
5045 {
5046 assert(boolarray != NULL);
5047
5048 return boolarray->minusedidx;
5049 }
5050
5051 /** returns the maximal index of all stored non-zero elements */
SCIPboolarrayGetMaxIdx(SCIP_BOOLARRAY * boolarray)5052 int SCIPboolarrayGetMaxIdx(
5053 SCIP_BOOLARRAY* boolarray /**< dynamic bool array */
5054 )
5055 {
5056 assert(boolarray != NULL);
5057
5058 return boolarray->maxusedidx;
5059 }
5060
5061
5062 /** creates a dynamic array of pointer values */
SCIPptrarrayCreate(SCIP_PTRARRAY ** ptrarray,BMS_BLKMEM * blkmem)5063 SCIP_RETCODE SCIPptrarrayCreate(
5064 SCIP_PTRARRAY** ptrarray, /**< pointer to store the ptr array */
5065 BMS_BLKMEM* blkmem /**< block memory */
5066 )
5067 {
5068 assert(ptrarray != NULL);
5069 assert(blkmem != NULL);
5070
5071 SCIP_ALLOC( BMSallocBlockMemory(blkmem, ptrarray) );
5072 (*ptrarray)->blkmem = blkmem;
5073 (*ptrarray)->vals = NULL;
5074 (*ptrarray)->valssize = 0;
5075 (*ptrarray)->firstidx = -1;
5076 (*ptrarray)->minusedidx = INT_MAX;
5077 (*ptrarray)->maxusedidx = INT_MIN;
5078
5079 return SCIP_OKAY;
5080 }
5081
5082 /** creates a copy of a dynamic array of pointer values */
SCIPptrarrayCopy(SCIP_PTRARRAY ** ptrarray,BMS_BLKMEM * blkmem,SCIP_PTRARRAY * sourceptrarray)5083 SCIP_RETCODE SCIPptrarrayCopy(
5084 SCIP_PTRARRAY** ptrarray, /**< pointer to store the copied ptr array */
5085 BMS_BLKMEM* blkmem, /**< block memory */
5086 SCIP_PTRARRAY* sourceptrarray /**< dynamic ptr array to copy */
5087 )
5088 {
5089 assert(ptrarray != NULL);
5090 assert(sourceptrarray != NULL);
5091
5092 SCIP_CALL( SCIPptrarrayCreate(ptrarray, blkmem) );
5093 if( sourceptrarray->valssize > 0 )
5094 {
5095 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*ptrarray)->vals, sourceptrarray->vals, sourceptrarray->valssize) );
5096 }
5097 (*ptrarray)->valssize = sourceptrarray->valssize;
5098 (*ptrarray)->firstidx = sourceptrarray->firstidx;
5099 (*ptrarray)->minusedidx = sourceptrarray->minusedidx;
5100 (*ptrarray)->maxusedidx = sourceptrarray->maxusedidx;
5101
5102 return SCIP_OKAY;
5103 }
5104
5105 /** frees a dynamic array of pointer values */
SCIPptrarrayFree(SCIP_PTRARRAY ** ptrarray)5106 SCIP_RETCODE SCIPptrarrayFree(
5107 SCIP_PTRARRAY** ptrarray /**< pointer to the ptr array */
5108 )
5109 {
5110 assert(ptrarray != NULL);
5111 assert(*ptrarray != NULL);
5112
5113 BMSfreeBlockMemoryArrayNull((*ptrarray)->blkmem, &(*ptrarray)->vals, (*ptrarray)->valssize);
5114 BMSfreeBlockMemory((*ptrarray)->blkmem, ptrarray);
5115
5116 return SCIP_OKAY;
5117 }
5118
5119 /** extends dynamic array to be able to store indices from minidx to maxidx */
SCIPptrarrayExtend(SCIP_PTRARRAY * ptrarray,int arraygrowinit,SCIP_Real arraygrowfac,int minidx,int maxidx)5120 SCIP_RETCODE SCIPptrarrayExtend(
5121 SCIP_PTRARRAY* ptrarray, /**< dynamic ptr array */
5122 int arraygrowinit, /**< initial size of array */
5123 SCIP_Real arraygrowfac, /**< growing factor of array */
5124 int minidx, /**< smallest index to allocate storage for */
5125 int maxidx /**< largest index to allocate storage for */
5126 )
5127 {
5128 int nused;
5129 int nfree;
5130 int newfirstidx;
5131 int i;
5132
5133 assert(ptrarray != NULL);
5134 assert(ptrarray->minusedidx == INT_MAX || ptrarray->firstidx >= 0);
5135 assert(ptrarray->maxusedidx == INT_MIN || ptrarray->firstidx >= 0);
5136 assert(ptrarray->minusedidx == INT_MAX || ptrarray->minusedidx >= ptrarray->firstidx);
5137 assert(ptrarray->maxusedidx == INT_MIN || ptrarray->maxusedidx < ptrarray->firstidx + ptrarray->valssize);
5138 assert(0 <= minidx);
5139 assert(minidx <= maxidx);
5140
5141 minidx = MIN(minidx, ptrarray->minusedidx);
5142 maxidx = MAX(maxidx, ptrarray->maxusedidx);
5143 assert(0 <= minidx);
5144 assert(minidx <= maxidx);
5145
5146 SCIPdebugMessage("extending ptrarray %p (firstidx=%d, size=%d, range=[%d,%d]) to range [%d,%d]\n",
5147 (void*)ptrarray, ptrarray->firstidx, ptrarray->valssize, ptrarray->minusedidx, ptrarray->maxusedidx, minidx, maxidx);
5148
5149 /* check, whether we have to allocate additional memory, or shift the array */
5150 nused = maxidx - minidx + 1;
5151 if( nused > ptrarray->valssize )
5152 {
5153 void** newvals;
5154 int newvalssize;
5155
5156 /* allocate new memory storage */
5157 newvalssize = calcGrowSize(arraygrowinit, arraygrowfac, nused);
5158 SCIP_ALLOC( BMSallocBlockMemoryArray(ptrarray->blkmem, &newvals, newvalssize) );
5159 nfree = newvalssize - nused;
5160 newfirstidx = minidx - nfree/2;
5161 newfirstidx = MAX(newfirstidx, 0);
5162 assert(newfirstidx <= minidx);
5163 assert(maxidx < newfirstidx + newvalssize);
5164
5165 /* initialize memory array by copying old values and setting new values to zero */
5166 if( ptrarray->firstidx != -1 )
5167 {
5168 for( i = 0; i < ptrarray->minusedidx - newfirstidx; ++i )
5169 newvals[i] = NULL;
5170
5171 /* check for possible overflow or negative value */
5172 assert(ptrarray->maxusedidx - ptrarray->minusedidx + 1 > 0);
5173
5174 BMScopyMemoryArray(&newvals[ptrarray->minusedidx - newfirstidx],
5175 &(ptrarray->vals[ptrarray->minusedidx - ptrarray->firstidx]),
5176 ptrarray->maxusedidx - ptrarray->minusedidx + 1); /*lint !e866 !e776*/
5177 for( i = ptrarray->maxusedidx - newfirstidx + 1; i < newvalssize; ++i )
5178 newvals[i] = NULL;
5179 }
5180 else
5181 {
5182 for( i = 0; i < newvalssize; ++i )
5183 newvals[i] = NULL;
5184 }
5185
5186 /* free old memory storage, and set the new array parameters */
5187 BMSfreeBlockMemoryArrayNull(ptrarray->blkmem, &ptrarray->vals, ptrarray->valssize);
5188 ptrarray->vals = newvals;
5189 ptrarray->valssize = newvalssize;
5190 ptrarray->firstidx = newfirstidx;
5191 }
5192 else if( ptrarray->firstidx == -1 )
5193 {
5194 /* a sufficiently large memory storage exists, but it was cleared */
5195 nfree = ptrarray->valssize - nused;
5196 assert(nfree >= 0);
5197 ptrarray->firstidx = minidx - nfree/2;
5198 assert(ptrarray->firstidx <= minidx);
5199 assert(maxidx < ptrarray->firstidx + ptrarray->valssize);
5200 #ifndef NDEBUG
5201 for( i = 0; i < ptrarray->valssize; ++i )
5202 assert(ptrarray->vals[i] == NULL);
5203 #endif
5204 }
5205 else if( minidx < ptrarray->firstidx )
5206 {
5207 /* a sufficiently large memory storage exists, but it has to be shifted to the right */
5208 nfree = ptrarray->valssize - nused;
5209 assert(nfree >= 0);
5210 newfirstidx = minidx - nfree/2;
5211 newfirstidx = MAX(newfirstidx, 0);
5212 assert(newfirstidx <= minidx);
5213 assert(maxidx < newfirstidx + ptrarray->valssize);
5214
5215 if( ptrarray->minusedidx <= ptrarray->maxusedidx )
5216 {
5217 int shift;
5218
5219 assert(ptrarray->firstidx <= ptrarray->minusedidx);
5220 assert(ptrarray->maxusedidx < ptrarray->firstidx + ptrarray->valssize);
5221
5222 /* shift used part of array to the right */
5223 shift = ptrarray->firstidx - newfirstidx;
5224 assert(shift > 0);
5225 for( i = ptrarray->maxusedidx - ptrarray->firstidx; i >= ptrarray->minusedidx - ptrarray->firstidx; --i )
5226 {
5227 assert(0 <= i + shift && i + shift < ptrarray->valssize);
5228 ptrarray->vals[i + shift] = ptrarray->vals[i];
5229 }
5230 /* clear the formerly used head of the array */
5231 for( i = 0; i < shift; ++i )
5232 ptrarray->vals[ptrarray->minusedidx - ptrarray->firstidx + i] = NULL;
5233 }
5234 ptrarray->firstidx = newfirstidx;
5235 }
5236 else if( maxidx >= ptrarray->firstidx + ptrarray->valssize )
5237 {
5238 /* a sufficiently large memory storage exists, but it has to be shifted to the left */
5239 nfree = ptrarray->valssize - nused;
5240 assert(nfree >= 0);
5241 newfirstidx = minidx - nfree/2;
5242 newfirstidx = MAX(newfirstidx, 0);
5243 assert(newfirstidx <= minidx);
5244 assert(maxidx < newfirstidx + ptrarray->valssize);
5245
5246 if( ptrarray->minusedidx <= ptrarray->maxusedidx )
5247 {
5248 int shift;
5249
5250 assert(ptrarray->firstidx <= ptrarray->minusedidx);
5251 assert(ptrarray->maxusedidx < ptrarray->firstidx + ptrarray->valssize);
5252
5253 /* shift used part of array to the left */
5254 shift = newfirstidx - ptrarray->firstidx;
5255 assert(shift > 0);
5256 for( i = ptrarray->minusedidx - ptrarray->firstidx; i <= ptrarray->maxusedidx - ptrarray->firstidx; ++i )
5257 {
5258 assert(0 <= i - shift && i - shift < ptrarray->valssize);
5259 ptrarray->vals[i - shift] = ptrarray->vals[i];
5260 }
5261 /* clear the formerly used tail of the array */
5262 for( i = 0; i < shift; ++i )
5263 ptrarray->vals[ptrarray->maxusedidx - ptrarray->firstidx - i] = NULL;
5264 }
5265 ptrarray->firstidx = newfirstidx;
5266 }
5267
5268 assert(minidx >= ptrarray->firstidx);
5269 assert(maxidx < ptrarray->firstidx + ptrarray->valssize);
5270
5271 return SCIP_OKAY;
5272 }
5273
5274 /** clears a dynamic pointer array */
SCIPptrarrayClear(SCIP_PTRARRAY * ptrarray)5275 SCIP_RETCODE SCIPptrarrayClear(
5276 SCIP_PTRARRAY* ptrarray /**< dynamic ptr array */
5277 )
5278 {
5279 assert(ptrarray != NULL);
5280
5281 SCIPdebugMessage("clearing ptrarray %p (firstidx=%d, size=%d, range=[%d,%d])\n",
5282 (void*)ptrarray, ptrarray->firstidx, ptrarray->valssize, ptrarray->minusedidx, ptrarray->maxusedidx);
5283
5284 if( ptrarray->minusedidx <= ptrarray->maxusedidx )
5285 {
5286 assert(ptrarray->firstidx <= ptrarray->minusedidx);
5287 assert(ptrarray->maxusedidx < ptrarray->firstidx + ptrarray->valssize);
5288 assert(ptrarray->firstidx != -1);
5289 assert(ptrarray->valssize > 0);
5290
5291 /* clear the used part of array */
5292 BMSclearMemoryArray(&ptrarray->vals[ptrarray->minusedidx - ptrarray->firstidx],
5293 ptrarray->maxusedidx - ptrarray->minusedidx + 1); /*lint !e866*/
5294
5295 /* mark the array cleared */
5296 ptrarray->minusedidx = INT_MAX;
5297 ptrarray->maxusedidx = INT_MIN;
5298 }
5299 assert(ptrarray->minusedidx == INT_MAX);
5300 assert(ptrarray->maxusedidx == INT_MIN);
5301
5302 return SCIP_OKAY;
5303 }
5304
5305 /** gets value of entry in dynamic array */
SCIPptrarrayGetVal(SCIP_PTRARRAY * ptrarray,int idx)5306 void* SCIPptrarrayGetVal(
5307 SCIP_PTRARRAY* ptrarray, /**< dynamic ptr array */
5308 int idx /**< array index to get value for */
5309 )
5310 {
5311 assert(ptrarray != NULL);
5312 assert(idx >= 0);
5313
5314 if( idx < ptrarray->minusedidx || idx > ptrarray->maxusedidx )
5315 return NULL;
5316 else
5317 {
5318 assert(ptrarray->vals != NULL);
5319 assert(idx - ptrarray->firstidx >= 0);
5320 assert(idx - ptrarray->firstidx < ptrarray->valssize);
5321
5322 return ptrarray->vals[idx - ptrarray->firstidx];
5323 }
5324 }
5325
5326 /** sets value of entry in dynamic array */
SCIPptrarraySetVal(SCIP_PTRARRAY * ptrarray,int arraygrowinit,SCIP_Real arraygrowfac,int idx,void * val)5327 SCIP_RETCODE SCIPptrarraySetVal(
5328 SCIP_PTRARRAY* ptrarray, /**< dynamic ptr array */
5329 int arraygrowinit, /**< initial size of array */
5330 SCIP_Real arraygrowfac, /**< growing factor of array */
5331 int idx, /**< array index to set value for */
5332 void* val /**< value to set array index to */
5333 )
5334 {
5335 assert(ptrarray != NULL);
5336 assert(idx >= 0);
5337
5338 SCIPdebugMessage("setting ptrarray %p (firstidx=%d, size=%d, range=[%d,%d]) index %d to %p\n",
5339 (void*)ptrarray, ptrarray->firstidx, ptrarray->valssize, ptrarray->minusedidx, ptrarray->maxusedidx, idx, val);
5340
5341 if( val != NULL )
5342 {
5343 /* extend array to be able to store the index */
5344 SCIP_CALL( SCIPptrarrayExtend(ptrarray, arraygrowinit, arraygrowfac, idx, idx) );
5345 assert(idx >= ptrarray->firstidx);
5346 assert(idx < ptrarray->firstidx + ptrarray->valssize);
5347
5348 /* set the array value of the index */
5349 ptrarray->vals[idx - ptrarray->firstidx] = val;
5350
5351 /* update min/maxusedidx */
5352 ptrarray->minusedidx = MIN(ptrarray->minusedidx, idx);
5353 ptrarray->maxusedidx = MAX(ptrarray->maxusedidx, idx);
5354 }
5355 else if( idx >= ptrarray->firstidx && idx < ptrarray->firstidx + ptrarray->valssize )
5356 {
5357 /* set the array value of the index to zero */
5358 ptrarray->vals[idx - ptrarray->firstidx] = NULL;
5359
5360 /* check, if we can tighten the min/maxusedidx */
5361 if( idx == ptrarray->minusedidx )
5362 {
5363 assert(ptrarray->maxusedidx >= 0);
5364 assert(ptrarray->maxusedidx < ptrarray->firstidx + ptrarray->valssize);
5365 do
5366 {
5367 ptrarray->minusedidx++;
5368 }
5369 while( ptrarray->minusedidx <= ptrarray->maxusedidx
5370 && ptrarray->vals[ptrarray->minusedidx - ptrarray->firstidx] == NULL );
5371 if( ptrarray->minusedidx > ptrarray->maxusedidx )
5372 {
5373 ptrarray->minusedidx = INT_MAX;
5374 ptrarray->maxusedidx = INT_MIN;
5375 }
5376 }
5377 else if( idx == ptrarray->maxusedidx )
5378 {
5379 assert(ptrarray->minusedidx >= 0);
5380 assert(ptrarray->minusedidx < ptrarray->maxusedidx);
5381 assert(ptrarray->maxusedidx < ptrarray->firstidx + ptrarray->valssize);
5382 do
5383 {
5384 ptrarray->maxusedidx--;
5385 assert(ptrarray->minusedidx <= ptrarray->maxusedidx);
5386 }
5387 while( ptrarray->vals[ptrarray->maxusedidx - ptrarray->firstidx] == NULL );
5388 }
5389 }
5390
5391 return SCIP_OKAY;
5392 }
5393
5394 /** returns the minimal index of all stored non-zero elements */
SCIPptrarrayGetMinIdx(SCIP_PTRARRAY * ptrarray)5395 int SCIPptrarrayGetMinIdx(
5396 SCIP_PTRARRAY* ptrarray /**< dynamic ptr array */
5397 )
5398 {
5399 assert(ptrarray != NULL);
5400
5401 return ptrarray->minusedidx;
5402 }
5403
5404 /** returns the maximal index of all stored non-zero elements */
SCIPptrarrayGetMaxIdx(SCIP_PTRARRAY * ptrarray)5405 int SCIPptrarrayGetMaxIdx(
5406 SCIP_PTRARRAY* ptrarray /**< dynamic ptr array */
5407 )
5408 {
5409 assert(ptrarray != NULL);
5410
5411 return ptrarray->maxusedidx;
5412 }
5413
5414
5415 /*
5416 * Sorting algorithms
5417 */
5418
5419 /** default comparer for integers */
SCIP_DECL_SORTPTRCOMP(SCIPsortCompInt)5420 SCIP_DECL_SORTPTRCOMP(SCIPsortCompInt)
5421 {
5422 int value1;
5423 int value2;
5424
5425 value1 = (int)(size_t)elem1;
5426 value2 = (int)(size_t)elem2;
5427
5428 if( value1 < value2 )
5429 return -1;
5430
5431 if( value2 < value1 )
5432 return 1;
5433
5434 return 0;
5435 }
5436
5437 /* first all upwards-sorting methods */
5438
5439 /** sort an indexed element set in non-decreasing order, resulting in a permutation index array */
SCIPsort(int * perm,SCIP_DECL_SORTINDCOMP ((* indcomp)),void * dataptr,int len)5440 void SCIPsort(
5441 int* perm, /**< pointer to store the resulting permutation */
5442 SCIP_DECL_SORTINDCOMP((*indcomp)), /**< data element comparator */
5443 void* dataptr, /**< pointer to data field that is given to the external compare method */
5444 int len /**< number of elements to be sorted (valid index range) */
5445 )
5446 {
5447 int pos;
5448
5449 assert(indcomp != NULL);
5450 assert(len == 0 || perm != NULL);
5451
5452 /* create identity permutation */
5453 for( pos = 0; pos < len; ++pos )
5454 perm[pos] = pos;
5455
5456 SCIPsortInd(perm, indcomp, dataptr, len);
5457 }
5458
5459 /* SCIPsortInd(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5460 #define SORTTPL_NAMEEXT Ind
5461 #define SORTTPL_KEYTYPE int
5462 #define SORTTPL_INDCOMP
5463 #include "scip/sorttpl.c" /*lint !e451*/
5464
5465
5466 /* SCIPsortPtr(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5467 #define SORTTPL_NAMEEXT Ptr
5468 #define SORTTPL_KEYTYPE void*
5469 #define SORTTPL_PTRCOMP
5470 #include "scip/sorttpl.c" /*lint !e451*/
5471
5472
5473 /* SCIPsortPtrPtr(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5474 #define SORTTPL_NAMEEXT PtrPtr
5475 #define SORTTPL_KEYTYPE void*
5476 #define SORTTPL_FIELD1TYPE void*
5477 #define SORTTPL_PTRCOMP
5478 #include "scip/sorttpl.c" /*lint !e451*/
5479
5480
5481 /* SCIPsortPtrReal(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5482 #define SORTTPL_NAMEEXT PtrReal
5483 #define SORTTPL_KEYTYPE void*
5484 #define SORTTPL_FIELD1TYPE SCIP_Real
5485 #define SORTTPL_PTRCOMP
5486 #include "scip/sorttpl.c" /*lint !e451*/
5487
5488
5489 /* SCIPsortPtrInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5490 #define SORTTPL_NAMEEXT PtrInt
5491 #define SORTTPL_KEYTYPE void*
5492 #define SORTTPL_FIELD1TYPE int
5493 #define SORTTPL_PTRCOMP
5494 #include "scip/sorttpl.c" /*lint !e451*/
5495
5496
5497 /* SCIPsortPtrBool(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5498 #define SORTTPL_NAMEEXT PtrBool
5499 #define SORTTPL_KEYTYPE void*
5500 #define SORTTPL_FIELD1TYPE SCIP_Bool
5501 #define SORTTPL_PTRCOMP
5502 #include "scip/sorttpl.c" /*lint !e451*/
5503
5504
5505 /* SCIPsortPtrIntInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5506 #define SORTTPL_NAMEEXT PtrIntInt
5507 #define SORTTPL_KEYTYPE void*
5508 #define SORTTPL_FIELD1TYPE int
5509 #define SORTTPL_FIELD2TYPE int
5510 #define SORTTPL_PTRCOMP
5511 #include "scip/sorttpl.c" /*lint !e451*/
5512
5513
5514 /* SCIPsortPtrRealInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5515 #define SORTTPL_NAMEEXT PtrRealInt
5516 #define SORTTPL_KEYTYPE void*
5517 #define SORTTPL_FIELD1TYPE SCIP_Real
5518 #define SORTTPL_FIELD2TYPE int
5519 #define SORTTPL_PTRCOMP
5520 #include "scip/sorttpl.c" /*lint !e451*/
5521
5522 /* SCIPsortPtrRealRealInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5523 #define SORTTPL_NAMEEXT PtrRealRealInt
5524 #define SORTTPL_KEYTYPE void*
5525 #define SORTTPL_FIELD1TYPE SCIP_Real
5526 #define SORTTPL_FIELD2TYPE SCIP_Real
5527 #define SORTTPL_FIELD3TYPE int
5528 #define SORTTPL_PTRCOMP
5529 #include "scip/sorttpl.c" /*lint !e451*/
5530
5531 /* SCIPsortPtrRealRealBoolBool(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5532 #define SORTTPL_NAMEEXT PtrRealRealBoolBool
5533 #define SORTTPL_KEYTYPE void*
5534 #define SORTTPL_FIELD1TYPE SCIP_Real
5535 #define SORTTPL_FIELD2TYPE SCIP_Real
5536 #define SORTTPL_FIELD3TYPE SCIP_Bool
5537 #define SORTTPL_FIELD4TYPE SCIP_Bool
5538 #define SORTTPL_PTRCOMP
5539 #include "scip/sorttpl.c" /*lint !e451*/
5540
5541 /* SCIPsortPtrRealRealIntBool(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5542 #define SORTTPL_NAMEEXT PtrRealRealIntBool
5543 #define SORTTPL_KEYTYPE void*
5544 #define SORTTPL_FIELD1TYPE SCIP_Real
5545 #define SORTTPL_FIELD2TYPE SCIP_Real
5546 #define SORTTPL_FIELD3TYPE int
5547 #define SORTTPL_FIELD4TYPE SCIP_Bool
5548 #define SORTTPL_PTRCOMP
5549 #include "scip/sorttpl.c" /*lint !e451*/
5550
5551 /* SCIPsortPtrRealBool(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5552 #define SORTTPL_NAMEEXT PtrRealBool
5553 #define SORTTPL_KEYTYPE void*
5554 #define SORTTPL_FIELD1TYPE SCIP_Real
5555 #define SORTTPL_FIELD2TYPE SCIP_Bool
5556 #define SORTTPL_PTRCOMP
5557 #include "scip/sorttpl.c" /*lint !e451*/
5558
5559
5560 /* SCIPsortPtrPtrInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5561 #define SORTTPL_NAMEEXT PtrPtrInt
5562 #define SORTTPL_KEYTYPE void*
5563 #define SORTTPL_FIELD1TYPE void*
5564 #define SORTTPL_FIELD2TYPE int
5565 #define SORTTPL_PTRCOMP
5566 #include "scip/sorttpl.c" /*lint !e451*/
5567
5568
5569 /* SCIPsortPtrPtrReal(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5570 #define SORTTPL_NAMEEXT PtrPtrReal
5571 #define SORTTPL_KEYTYPE void*
5572 #define SORTTPL_FIELD1TYPE void*
5573 #define SORTTPL_FIELD2TYPE SCIP_Real
5574 #define SORTTPL_PTRCOMP
5575 #include "scip/sorttpl.c" /*lint !e451*/
5576
5577
5578 /* SCIPsortPtrRealIntInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5579 #define SORTTPL_NAMEEXT PtrRealIntInt
5580 #define SORTTPL_KEYTYPE void*
5581 #define SORTTPL_FIELD1TYPE SCIP_Real
5582 #define SORTTPL_FIELD2TYPE int
5583 #define SORTTPL_FIELD3TYPE int
5584 #define SORTTPL_PTRCOMP
5585 #include "scip/sorttpl.c" /*lint !e451*/
5586
5587
5588 /* SCIPsortPtrPtrIntInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5589 #define SORTTPL_NAMEEXT PtrPtrIntInt
5590 #define SORTTPL_KEYTYPE void*
5591 #define SORTTPL_FIELD1TYPE void*
5592 #define SORTTPL_FIELD2TYPE int
5593 #define SORTTPL_FIELD3TYPE int
5594 #define SORTTPL_PTRCOMP
5595 #include "scip/sorttpl.c" /*lint !e451*/
5596
5597
5598 /* SCIPsortPtrPtrRealInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5599 #define SORTTPL_NAMEEXT PtrPtrRealInt
5600 #define SORTTPL_KEYTYPE void*
5601 #define SORTTPL_FIELD1TYPE void*
5602 #define SORTTPL_FIELD2TYPE SCIP_Real
5603 #define SORTTPL_FIELD3TYPE int
5604 #define SORTTPL_PTRCOMP
5605 #include "scip/sorttpl.c" /*lint !e451*/
5606
5607
5608 /* SCIPsortPtrPtrRealBool(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5609 #define SORTTPL_NAMEEXT PtrPtrRealBool
5610 #define SORTTPL_KEYTYPE void*
5611 #define SORTTPL_FIELD1TYPE void*
5612 #define SORTTPL_FIELD2TYPE SCIP_Real
5613 #define SORTTPL_FIELD3TYPE SCIP_Bool
5614 #define SORTTPL_PTRCOMP
5615 #include "scip/sorttpl.c" /*lint !e451*/
5616
5617
5618 /* SCIPsortPtrPtrLongInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5619 #define SORTTPL_NAMEEXT PtrPtrLongInt
5620 #define SORTTPL_KEYTYPE void*
5621 #define SORTTPL_FIELD1TYPE void*
5622 #define SORTTPL_FIELD2TYPE SCIP_Longint
5623 #define SORTTPL_FIELD3TYPE int
5624 #define SORTTPL_PTRCOMP
5625 #include "scip/sorttpl.c" /*lint !e451*/
5626
5627
5628 /* SCIPsortPtrPtrLongIntInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5629 #define SORTTPL_NAMEEXT PtrPtrLongIntInt
5630 #define SORTTPL_KEYTYPE void*
5631 #define SORTTPL_FIELD1TYPE void*
5632 #define SORTTPL_FIELD2TYPE SCIP_Longint
5633 #define SORTTPL_FIELD3TYPE int
5634 #define SORTTPL_FIELD4TYPE int
5635 #define SORTTPL_PTRCOMP
5636 #include "scip/sorttpl.c" /*lint !e451*/
5637
5638
5639 /* SCIPsortReal(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5640 #define SORTTPL_NAMEEXT Real
5641 #define SORTTPL_KEYTYPE SCIP_Real
5642 #include "scip/sorttpl.c" /*lint !e451*/
5643
5644
5645 /* SCIPsortRealBoolPtr(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5646 #define SORTTPL_NAMEEXT RealBoolPtr
5647 #define SORTTPL_KEYTYPE SCIP_Real
5648 #define SORTTPL_FIELD1TYPE SCIP_Bool
5649 #define SORTTPL_FIELD2TYPE void*
5650 #include "scip/sorttpl.c" /*lint !e451*/
5651
5652
5653 /* SCIPsortRealPtr(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5654 #define SORTTPL_NAMEEXT RealPtr
5655 #define SORTTPL_KEYTYPE SCIP_Real
5656 #define SORTTPL_FIELD1TYPE void*
5657 #include "scip/sorttpl.c" /*lint !e451*/
5658
5659
5660 /* SCIPsortRealInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5661 #define SORTTPL_NAMEEXT RealInt
5662 #define SORTTPL_KEYTYPE SCIP_Real
5663 #define SORTTPL_FIELD1TYPE int
5664 #include "scip/sorttpl.c" /*lint !e451*/
5665
5666
5667 /* SCIPsortRealIntInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5668 #define SORTTPL_NAMEEXT RealIntInt
5669 #define SORTTPL_KEYTYPE SCIP_Real
5670 #define SORTTPL_FIELD1TYPE int
5671 #define SORTTPL_FIELD2TYPE int
5672 #include "scip/sorttpl.c" /*lint !e451*/
5673
5674
5675 /* SCIPsortRealIntLong(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5676 #define SORTTPL_NAMEEXT RealIntLong
5677 #define SORTTPL_KEYTYPE SCIP_Real
5678 #define SORTTPL_FIELD1TYPE int
5679 #define SORTTPL_FIELD2TYPE SCIP_Longint
5680 #include "scip/sorttpl.c" /*lint !e451*/
5681
5682
5683 /* SCIPsortRealIntPtr(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5684 #define SORTTPL_NAMEEXT RealIntPtr
5685 #define SORTTPL_KEYTYPE SCIP_Real
5686 #define SORTTPL_FIELD1TYPE int
5687 #define SORTTPL_FIELD2TYPE void*
5688 #include "scip/sorttpl.c" /*lint !e451*/
5689
5690
5691 /* SCIPsortRealRealPtr(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5692 #define SORTTPL_NAMEEXT RealRealPtr
5693 #define SORTTPL_KEYTYPE SCIP_Real
5694 #define SORTTPL_FIELD1TYPE SCIP_Real
5695 #define SORTTPL_FIELD2TYPE void*
5696 #include "scip/sorttpl.c" /*lint !e451*/
5697
5698
5699 /* SCIPsortRealLongRealInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5700 #define SORTTPL_NAMEEXT RealLongRealInt
5701 #define SORTTPL_KEYTYPE SCIP_Real
5702 #define SORTTPL_FIELD1TYPE SCIP_Longint
5703 #define SORTTPL_FIELD2TYPE SCIP_Real
5704 #define SORTTPL_FIELD3TYPE int
5705 #include "scip/sorttpl.c" /*lint !e451*/
5706
5707 /* SCIPsortRealRealIntInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5708 #define SORTTPL_NAMEEXT RealRealIntInt
5709 #define SORTTPL_KEYTYPE SCIP_Real
5710 #define SORTTPL_FIELD1TYPE SCIP_Real
5711 #define SORTTPL_FIELD2TYPE int
5712 #define SORTTPL_FIELD3TYPE int
5713 #include "scip/sorttpl.c" /*lint !e451*/
5714
5715
5716 /* SCIPsortRealRealRealInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5717 #define SORTTPL_NAMEEXT RealRealRealInt
5718 #define SORTTPL_KEYTYPE SCIP_Real
5719 #define SORTTPL_FIELD1TYPE SCIP_Real
5720 #define SORTTPL_FIELD2TYPE SCIP_Real
5721 #define SORTTPL_FIELD3TYPE int
5722 #include "scip/sorttpl.c" /*lint !e451*/
5723
5724
5725 /* SCIPsortRealRealRealPtr(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5726 #define SORTTPL_NAMEEXT RealRealRealPtr
5727 #define SORTTPL_KEYTYPE SCIP_Real
5728 #define SORTTPL_FIELD1TYPE SCIP_Real
5729 #define SORTTPL_FIELD2TYPE SCIP_Real
5730 #define SORTTPL_FIELD3TYPE void*
5731 #include "scip/sorttpl.c" /*lint !e451*/
5732
5733
5734 /* SCIPsortRealPtrPtrInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5735 #define SORTTPL_NAMEEXT RealPtrPtrInt
5736 #define SORTTPL_KEYTYPE SCIP_Real
5737 #define SORTTPL_FIELD1TYPE void*
5738 #define SORTTPL_FIELD2TYPE void*
5739 #define SORTTPL_FIELD3TYPE int
5740 #include "scip/sorttpl.c" /*lint !e451*/
5741
5742
5743 /* SCIPsortRealPtrPtrIntInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5744 #define SORTTPL_NAMEEXT RealPtrPtrIntInt
5745 #define SORTTPL_KEYTYPE SCIP_Real
5746 #define SORTTPL_FIELD1TYPE void*
5747 #define SORTTPL_FIELD2TYPE void*
5748 #define SORTTPL_FIELD3TYPE int
5749 #define SORTTPL_FIELD4TYPE int
5750 #include "scip/sorttpl.c" /*lint !e451*/
5751
5752
5753 /* SCIPsortRealRealRealBoolPtr(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5754 #define SORTTPL_NAMEEXT RealRealRealBoolPtr
5755 #define SORTTPL_KEYTYPE SCIP_Real
5756 #define SORTTPL_FIELD1TYPE SCIP_Real
5757 #define SORTTPL_FIELD2TYPE SCIP_Real
5758 #define SORTTPL_FIELD3TYPE SCIP_Bool
5759 #define SORTTPL_FIELD4TYPE void*
5760 #include "scip/sorttpl.c" /*lint !e451*/
5761
5762
5763 /* SCIPsortRealRealRealBoolBoolPtr(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5764 #define SORTTPL_NAMEEXT RealRealRealBoolBoolPtr
5765 #define SORTTPL_KEYTYPE SCIP_Real
5766 #define SORTTPL_FIELD1TYPE SCIP_Real
5767 #define SORTTPL_FIELD2TYPE SCIP_Real
5768 #define SORTTPL_FIELD3TYPE SCIP_Bool
5769 #define SORTTPL_FIELD4TYPE SCIP_Bool
5770 #define SORTTPL_FIELD5TYPE void*
5771 #include "scip/sorttpl.c" /*lint !e451*/
5772
5773
5774 /* SCIPsortInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5775 #define SORTTPL_NAMEEXT Int
5776 #define SORTTPL_KEYTYPE int
5777 #include "scip/sorttpl.c" /*lint !e451*/
5778
5779
5780 /* SCIPsortIntInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5781 #define SORTTPL_NAMEEXT IntInt
5782 #define SORTTPL_KEYTYPE int
5783 #define SORTTPL_FIELD1TYPE int
5784 #include "scip/sorttpl.c" /*lint !e451*/
5785
5786
5787 /* SCIPsortIntReal(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5788 #define SORTTPL_NAMEEXT IntReal
5789 #define SORTTPL_KEYTYPE int
5790 #define SORTTPL_FIELD1TYPE SCIP_Real
5791 #include "scip/sorttpl.c" /*lint !e451*/
5792
5793
5794 /* SCIPsortIntPtr(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5795 #define SORTTPL_NAMEEXT IntPtr
5796 #define SORTTPL_KEYTYPE int
5797 #define SORTTPL_FIELD1TYPE void*
5798 #include "scip/sorttpl.c" /*lint !e451*/
5799
5800
5801 /* SCIPsortIntIntInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5802 #define SORTTPL_NAMEEXT IntIntInt
5803 #define SORTTPL_KEYTYPE int
5804 #define SORTTPL_FIELD1TYPE int
5805 #define SORTTPL_FIELD2TYPE int
5806 #include "scip/sorttpl.c" /*lint !e451*/
5807
5808
5809 /* SCIPsortIntIntLong(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5810 #define SORTTPL_NAMEEXT IntIntLong
5811 #define SORTTPL_KEYTYPE int
5812 #define SORTTPL_FIELD1TYPE int
5813 #define SORTTPL_FIELD2TYPE SCIP_Longint
5814 #include "scip/sorttpl.c" /*lint !e451*/
5815
5816 /* SCIPsortIntRealLong(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5817 #define SORTTPL_NAMEEXT IntRealLong
5818 #define SORTTPL_KEYTYPE int
5819 #define SORTTPL_FIELD1TYPE SCIP_Real
5820 #define SORTTPL_FIELD2TYPE SCIP_Longint
5821 #include "scip/sorttpl.c" /*lint !e451*/
5822
5823
5824 /* SCIPsortIntIntPtr(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5825 #define SORTTPL_NAMEEXT IntIntPtr
5826 #define SORTTPL_KEYTYPE int
5827 #define SORTTPL_FIELD1TYPE int
5828 #define SORTTPL_FIELD2TYPE void*
5829 #include "scip/sorttpl.c" /*lint !e451*/
5830
5831
5832 /* SCIPsortIntIntReal(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5833 #define SORTTPL_NAMEEXT IntIntReal
5834 #define SORTTPL_KEYTYPE int
5835 #define SORTTPL_FIELD1TYPE int
5836 #define SORTTPL_FIELD2TYPE SCIP_Real
5837 #include "scip/sorttpl.c" /*lint !e451*/
5838
5839
5840 /* SCIPsortIntPtrReal(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5841 #define SORTTPL_NAMEEXT IntPtrReal
5842 #define SORTTPL_KEYTYPE int
5843 #define SORTTPL_FIELD1TYPE void*
5844 #define SORTTPL_FIELD2TYPE SCIP_Real
5845 #include "scip/sorttpl.c" /*lint !e451*/
5846
5847
5848 /* SCIPsortIntIntIntPtr(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5849 #define SORTTPL_NAMEEXT IntIntIntPtr
5850 #define SORTTPL_KEYTYPE int
5851 #define SORTTPL_FIELD1TYPE int
5852 #define SORTTPL_FIELD2TYPE int
5853 #define SORTTPL_FIELD3TYPE void*
5854 #include "scip/sorttpl.c" /*lint !e451*/
5855
5856 /* SCIPsortIntIntIntReal(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5857 #define SORTTPL_NAMEEXT IntIntIntReal
5858 #define SORTTPL_KEYTYPE int
5859 #define SORTTPL_FIELD1TYPE int
5860 #define SORTTPL_FIELD2TYPE int
5861 #define SORTTPL_FIELD3TYPE SCIP_Real
5862 #include "scip/sorttpl.c" /*lint !e451*/
5863
5864 /* SCIPsortIntPtrIntReal(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5865 #define SORTTPL_NAMEEXT IntPtrIntReal
5866 #define SORTTPL_KEYTYPE int
5867 #define SORTTPL_FIELD1TYPE void*
5868 #define SORTTPL_FIELD2TYPE int
5869 #define SORTTPL_FIELD3TYPE SCIP_Real
5870 #include "scip/sorttpl.c" /*lint !e451*/
5871
5872
5873 /* SCIPsortLong(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5874 #define SORTTPL_NAMEEXT Long
5875 #define SORTTPL_KEYTYPE SCIP_Longint
5876 #include "scip/sorttpl.c" /*lint !e451*/
5877
5878
5879 /* SCIPsortLongPtr(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5880 #define SORTTPL_NAMEEXT LongPtr
5881 #define SORTTPL_KEYTYPE SCIP_Longint
5882 #define SORTTPL_FIELD1TYPE void*
5883 #include "scip/sorttpl.c" /*lint !e451*/
5884
5885
5886 /* SCIPsortLongPtrInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5887 #define SORTTPL_NAMEEXT LongPtrInt
5888 #define SORTTPL_KEYTYPE SCIP_Longint
5889 #define SORTTPL_FIELD1TYPE void*
5890 #define SORTTPL_FIELD2TYPE int
5891 #include "scip/sorttpl.c" /*lint !e451*/
5892
5893
5894 /* SCIPsortLongPtrRealBool(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5895 #define SORTTPL_NAMEEXT LongPtrRealBool
5896 #define SORTTPL_KEYTYPE SCIP_Longint
5897 #define SORTTPL_FIELD1TYPE void*
5898 #define SORTTPL_FIELD2TYPE SCIP_Real
5899 #define SORTTPL_FIELD3TYPE SCIP_Bool
5900 #include "scip/sorttpl.c" /*lint !e451*/
5901
5902
5903 /* SCIPsortLongPtrRealRealBool(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5904 #define SORTTPL_NAMEEXT LongPtrRealRealBool
5905 #define SORTTPL_KEYTYPE SCIP_Longint
5906 #define SORTTPL_FIELD1TYPE void*
5907 #define SORTTPL_FIELD2TYPE SCIP_Real
5908 #define SORTTPL_FIELD3TYPE SCIP_Real
5909 #define SORTTPL_FIELD4TYPE SCIP_Bool
5910 #include "scip/sorttpl.c" /*lint !e451*/
5911
5912
5913 /* SCIPsortLongPtrRealRealIntBool(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5914 #define SORTTPL_NAMEEXT LongPtrRealRealIntBool
5915 #define SORTTPL_KEYTYPE SCIP_Longint
5916 #define SORTTPL_FIELD1TYPE void*
5917 #define SORTTPL_FIELD2TYPE SCIP_Real
5918 #define SORTTPL_FIELD3TYPE SCIP_Real
5919 #define SORTTPL_FIELD4TYPE int
5920 #define SORTTPL_FIELD5TYPE SCIP_Bool
5921 #include "scip/sorttpl.c" /*lint !e451*/
5922
5923
5924 /* SCIPsortLongPtrPtrInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5925 #define SORTTPL_NAMEEXT LongPtrPtrInt
5926 #define SORTTPL_KEYTYPE SCIP_Longint
5927 #define SORTTPL_FIELD1TYPE void*
5928 #define SORTTPL_FIELD2TYPE void*
5929 #define SORTTPL_FIELD3TYPE int
5930 #include "scip/sorttpl.c" /*lint !e451*/
5931
5932
5933 /* SCIPsortLongPtrPtrIntInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5934 #define SORTTPL_NAMEEXT LongPtrPtrIntInt
5935 #define SORTTPL_KEYTYPE SCIP_Longint
5936 #define SORTTPL_FIELD1TYPE void*
5937 #define SORTTPL_FIELD2TYPE void*
5938 #define SORTTPL_FIELD3TYPE int
5939 #define SORTTPL_FIELD4TYPE int
5940 #include "scip/sorttpl.c" /*lint !e451*/
5941
5942
5943 /* SCIPsortLongPtrPtrBoolInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5944 #define SORTTPL_NAMEEXT LongPtrPtrBoolInt
5945 #define SORTTPL_KEYTYPE SCIP_Longint
5946 #define SORTTPL_FIELD1TYPE void*
5947 #define SORTTPL_FIELD2TYPE void*
5948 #define SORTTPL_FIELD3TYPE SCIP_Bool
5949 #define SORTTPL_FIELD4TYPE int
5950 #include "scip/sorttpl.c" /*lint !e451*/
5951
5952
5953 /* SCIPsortPtrIntIntBoolBool(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5954 #define SORTTPL_NAMEEXT PtrIntIntBoolBool
5955 #define SORTTPL_KEYTYPE void*
5956 #define SORTTPL_FIELD1TYPE int
5957 #define SORTTPL_FIELD2TYPE int
5958 #define SORTTPL_FIELD3TYPE SCIP_Bool
5959 #define SORTTPL_FIELD4TYPE SCIP_Bool
5960 #define SORTTPL_PTRCOMP
5961 #include "scip/sorttpl.c" /*lint !e451*/
5962
5963
5964 /* SCIPsortIntPtrIntIntBoolBool(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
5965 #define SORTTPL_NAMEEXT IntPtrIntIntBoolBool
5966 #define SORTTPL_KEYTYPE int
5967 #define SORTTPL_FIELD1TYPE void*
5968 #define SORTTPL_FIELD2TYPE int
5969 #define SORTTPL_FIELD3TYPE int
5970 #define SORTTPL_FIELD4TYPE SCIP_Bool
5971 #define SORTTPL_FIELD5TYPE SCIP_Bool
5972 #include "scip/sorttpl.c" /*lint !e451*/
5973
5974
5975 /* now all downwards-sorting methods */
5976
5977
5978 /** sort an indexed element set in non-increasing order, resulting in a permutation index array */
SCIPsortDown(int * perm,SCIP_DECL_SORTINDCOMP ((* indcomp)),void * dataptr,int len)5979 void SCIPsortDown(
5980 int* perm, /**< pointer to store the resulting permutation */
5981 SCIP_DECL_SORTINDCOMP((*indcomp)), /**< data element comparator */
5982 void* dataptr, /**< pointer to data field that is given to the external compare method */
5983 int len /**< number of elements to be sorted (valid index range) */
5984 )
5985 {
5986 int pos;
5987
5988 assert(indcomp != NULL);
5989 assert(len == 0 || perm != NULL);
5990
5991 /* create identity permutation */
5992 for( pos = 0; pos < len; ++pos )
5993 perm[pos] = pos;
5994
5995 SCIPsortDownInd(perm, indcomp, dataptr, len);
5996 }
5997
5998
5999 /* SCIPsortDownInd(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6000 #define SORTTPL_NAMEEXT DownInd
6001 #define SORTTPL_KEYTYPE int
6002 #define SORTTPL_INDCOMP
6003 #define SORTTPL_BACKWARDS
6004 #include "scip/sorttpl.c" /*lint !e451*/
6005
6006
6007 /* SCIPsortDownPtr(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6008 #define SORTTPL_NAMEEXT DownPtr
6009 #define SORTTPL_KEYTYPE void*
6010 #define SORTTPL_PTRCOMP
6011 #define SORTTPL_BACKWARDS
6012 #include "scip/sorttpl.c" /*lint !e451*/
6013
6014
6015 /* SCIPsortDownPtrPtr(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6016 #define SORTTPL_NAMEEXT DownPtrPtr
6017 #define SORTTPL_KEYTYPE void*
6018 #define SORTTPL_FIELD1TYPE void*
6019 #define SORTTPL_PTRCOMP
6020 #define SORTTPL_BACKWARDS
6021 #include "scip/sorttpl.c" /*lint !e451*/
6022
6023
6024 /* SCIPsortDownPtrReal(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6025 #define SORTTPL_NAMEEXT DownPtrReal
6026 #define SORTTPL_KEYTYPE void*
6027 #define SORTTPL_FIELD1TYPE SCIP_Real
6028 #define SORTTPL_PTRCOMP
6029 #define SORTTPL_BACKWARDS
6030 #include "scip/sorttpl.c" /*lint !e451*/
6031
6032
6033 /* SCIPsortDownPtrInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6034 #define SORTTPL_NAMEEXT DownPtrInt
6035 #define SORTTPL_KEYTYPE void*
6036 #define SORTTPL_FIELD1TYPE int
6037 #define SORTTPL_PTRCOMP
6038 #define SORTTPL_BACKWARDS
6039 #include "scip/sorttpl.c" /*lint !e451*/
6040
6041 /* SCIPsortDownPtrBool(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6042 #define SORTTPL_NAMEEXT DownPtrBool
6043 #define SORTTPL_KEYTYPE void*
6044 #define SORTTPL_FIELD1TYPE SCIP_Bool
6045 #define SORTTPL_PTRCOMP
6046 #define SORTTPL_BACKWARDS
6047 #include "scip/sorttpl.c" /*lint !e451*/
6048
6049 /* SCIPsortDownPtrIntInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6050 #define SORTTPL_NAMEEXT DownPtrIntInt
6051 #define SORTTPL_KEYTYPE void*
6052 #define SORTTPL_FIELD1TYPE int
6053 #define SORTTPL_FIELD2TYPE int
6054 #define SORTTPL_PTRCOMP
6055 #define SORTTPL_BACKWARDS
6056 #include "scip/sorttpl.c" /*lint !e451*/
6057
6058
6059 /* SCIPsortDownPtrRealInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6060 #define SORTTPL_NAMEEXT DownPtrRealInt
6061 #define SORTTPL_KEYTYPE void*
6062 #define SORTTPL_FIELD1TYPE SCIP_Real
6063 #define SORTTPL_FIELD2TYPE int
6064 #define SORTTPL_PTRCOMP
6065 #define SORTTPL_BACKWARDS
6066 #include "scip/sorttpl.c" /*lint !e451*/
6067
6068
6069 /* SCIPsortDownPtrRealBool(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6070 #define SORTTPL_NAMEEXT DownPtrRealBool
6071 #define SORTTPL_KEYTYPE void*
6072 #define SORTTPL_FIELD1TYPE SCIP_Real
6073 #define SORTTPL_FIELD2TYPE SCIP_Bool
6074 #define SORTTPL_PTRCOMP
6075 #define SORTTPL_BACKWARDS
6076 #include "scip/sorttpl.c" /*lint !e451*/
6077
6078
6079 /* SCIPsortDownPtrPtrInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6080 #define SORTTPL_NAMEEXT DownPtrPtrInt
6081 #define SORTTPL_KEYTYPE void*
6082 #define SORTTPL_FIELD1TYPE void*
6083 #define SORTTPL_FIELD2TYPE int
6084 #define SORTTPL_PTRCOMP
6085 #define SORTTPL_BACKWARDS
6086 #include "scip/sorttpl.c" /*lint !e451*/
6087
6088
6089 /* SCIPsortDownPtrPtrReal(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6090 #define SORTTPL_NAMEEXT DownPtrPtrReal
6091 #define SORTTPL_KEYTYPE void*
6092 #define SORTTPL_FIELD1TYPE void*
6093 #define SORTTPL_FIELD2TYPE SCIP_Real
6094 #define SORTTPL_PTRCOMP
6095 #define SORTTPL_BACKWARDS
6096 #include "scip/sorttpl.c" /*lint !e451*/
6097
6098
6099 /* SCIPsortDownPtrRealIntInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6100 #define SORTTPL_NAMEEXT DownPtrRealIntInt
6101 #define SORTTPL_KEYTYPE void*
6102 #define SORTTPL_FIELD1TYPE SCIP_Real
6103 #define SORTTPL_FIELD2TYPE int
6104 #define SORTTPL_FIELD3TYPE int
6105 #define SORTTPL_PTRCOMP
6106 #define SORTTPL_BACKWARDS
6107 #include "scip/sorttpl.c" /*lint !e451*/
6108
6109
6110 /* SCIPsortDownPtrPtrIntInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6111 #define SORTTPL_NAMEEXT DownPtrPtrIntInt
6112 #define SORTTPL_KEYTYPE void*
6113 #define SORTTPL_FIELD1TYPE void*
6114 #define SORTTPL_FIELD2TYPE int
6115 #define SORTTPL_FIELD3TYPE int
6116 #define SORTTPL_PTRCOMP
6117 #define SORTTPL_BACKWARDS
6118 #include "scip/sorttpl.c" /*lint !e451*/
6119
6120
6121 /* SCIPsortDownPtrPtrRealInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6122 #define SORTTPL_NAMEEXT DownPtrPtrRealInt
6123 #define SORTTPL_KEYTYPE void*
6124 #define SORTTPL_FIELD1TYPE void*
6125 #define SORTTPL_FIELD2TYPE SCIP_Real
6126 #define SORTTPL_FIELD3TYPE int
6127 #define SORTTPL_PTRCOMP
6128 #define SORTTPL_BACKWARDS
6129 #include "scip/sorttpl.c" /*lint !e451*/
6130
6131
6132 /* SCIPsortDownPtrPtrRealBool(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6133 #define SORTTPL_NAMEEXT DownPtrPtrRealBool
6134 #define SORTTPL_KEYTYPE void*
6135 #define SORTTPL_FIELD1TYPE void*
6136 #define SORTTPL_FIELD2TYPE SCIP_Real
6137 #define SORTTPL_FIELD3TYPE SCIP_Bool
6138 #define SORTTPL_PTRCOMP
6139 #define SORTTPL_BACKWARDS
6140 #include "scip/sorttpl.c" /*lint !e451*/
6141
6142
6143 /* SCIPsortDownPtrPtrLongInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6144 #define SORTTPL_NAMEEXT DownPtrPtrLongInt
6145 #define SORTTPL_KEYTYPE void*
6146 #define SORTTPL_FIELD1TYPE void*
6147 #define SORTTPL_FIELD2TYPE SCIP_Longint
6148 #define SORTTPL_FIELD3TYPE int
6149 #define SORTTPL_PTRCOMP
6150 #define SORTTPL_BACKWARDS
6151 #include "scip/sorttpl.c" /*lint !e451*/
6152
6153
6154 /* SCIPsortDownPtrPtrLongIntInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6155 #define SORTTPL_NAMEEXT DownPtrPtrLongIntInt
6156 #define SORTTPL_KEYTYPE void*
6157 #define SORTTPL_FIELD1TYPE void*
6158 #define SORTTPL_FIELD2TYPE SCIP_Longint
6159 #define SORTTPL_FIELD3TYPE int
6160 #define SORTTPL_FIELD4TYPE int
6161 #define SORTTPL_PTRCOMP
6162 #define SORTTPL_BACKWARDS
6163 #include "scip/sorttpl.c" /*lint !e451*/
6164
6165
6166 /* SCIPsortDownReal(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6167 #define SORTTPL_NAMEEXT DownReal
6168 #define SORTTPL_KEYTYPE SCIP_Real
6169 #define SORTTPL_BACKWARDS
6170 #include "scip/sorttpl.c" /*lint !e451*/
6171
6172
6173 /* SCIPsortDownRealBoolPtr(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6174 #define SORTTPL_NAMEEXT DownRealBoolPtr
6175 #define SORTTPL_KEYTYPE SCIP_Real
6176 #define SORTTPL_FIELD1TYPE SCIP_Bool
6177 #define SORTTPL_FIELD2TYPE void*
6178 #define SORTTPL_BACKWARDS
6179 #include "scip/sorttpl.c" /*lint !e451*/
6180
6181
6182 /* SCIPsortDownRealPtr(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6183 #define SORTTPL_NAMEEXT DownRealPtr
6184 #define SORTTPL_KEYTYPE SCIP_Real
6185 #define SORTTPL_FIELD1TYPE void*
6186 #define SORTTPL_BACKWARDS
6187 #include "scip/sorttpl.c" /*lint !e451*/
6188
6189
6190 /* SCIPsortDownRealInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6191 #define SORTTPL_NAMEEXT DownRealInt
6192 #define SORTTPL_KEYTYPE SCIP_Real
6193 #define SORTTPL_FIELD1TYPE int
6194 #define SORTTPL_BACKWARDS
6195 #include "scip/sorttpl.c" /*lint !e451*/
6196
6197 /* SCIPsortDownRealIntInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6198 #define SORTTPL_NAMEEXT DownRealIntInt
6199 #define SORTTPL_KEYTYPE SCIP_Real
6200 #define SORTTPL_FIELD1TYPE int
6201 #define SORTTPL_FIELD2TYPE int
6202 #define SORTTPL_BACKWARDS
6203 #include "scip/sorttpl.c" /*lint !e451*/
6204
6205 /* SCIPsortDownRealIntLong(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6206 #define SORTTPL_NAMEEXT DownRealIntLong
6207 #define SORTTPL_KEYTYPE SCIP_Real
6208 #define SORTTPL_FIELD1TYPE int
6209 #define SORTTPL_FIELD2TYPE SCIP_Longint
6210 #define SORTTPL_BACKWARDS
6211 #include "scip/sorttpl.c" /*lint !e451*/
6212
6213
6214 /* SCIPsortDownRealIntPtr(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6215 #define SORTTPL_NAMEEXT DownRealIntPtr
6216 #define SORTTPL_KEYTYPE SCIP_Real
6217 #define SORTTPL_FIELD1TYPE int
6218 #define SORTTPL_FIELD2TYPE void*
6219 #define SORTTPL_BACKWARDS
6220 #include "scip/sorttpl.c" /*lint !e451*/
6221
6222
6223 /* SCIPsortDownRealPtrPtr(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6224 #define SORTTPL_NAMEEXT DownRealPtrPtr
6225 #define SORTTPL_KEYTYPE SCIP_Real
6226 #define SORTTPL_FIELD1TYPE void*
6227 #define SORTTPL_FIELD2TYPE void*
6228 #define SORTTPL_BACKWARDS
6229 #include "scip/sorttpl.c" /*lint !e451*/
6230
6231 /* SCIPsortDownRealRealInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6232 #define SORTTPL_NAMEEXT DownRealRealInt
6233 #define SORTTPL_KEYTYPE SCIP_Real
6234 #define SORTTPL_FIELD1TYPE SCIP_Real
6235 #define SORTTPL_FIELD2TYPE int
6236 #define SORTTPL_BACKWARDS
6237 #include "scip/sorttpl.c" /*lint !e451*/
6238
6239 /* SCIPsortDownRealRealPtr(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6240 #define SORTTPL_NAMEEXT DownRealRealPtr
6241 #define SORTTPL_KEYTYPE SCIP_Real
6242 #define SORTTPL_FIELD1TYPE SCIP_Real
6243 #define SORTTPL_FIELD2TYPE void*
6244 #define SORTTPL_BACKWARDS
6245 #include "scip/sorttpl.c" /*lint !e451*/
6246
6247 /* SCIPsortDownRealRealPtrPtr(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6248 #define SORTTPL_NAMEEXT DownRealRealPtrPtr
6249 #define SORTTPL_KEYTYPE SCIP_Real
6250 #define SORTTPL_FIELD1TYPE SCIP_Real
6251 #define SORTTPL_FIELD2TYPE void*
6252 #define SORTTPL_FIELD3TYPE void*
6253 #define SORTTPL_BACKWARDS
6254 #include "scip/sorttpl.c" /*lint !e451*/
6255
6256
6257 /* SCIPsortDownRealLongRealInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6258 #define SORTTPL_NAMEEXT DownRealLongRealInt
6259 #define SORTTPL_KEYTYPE SCIP_Real
6260 #define SORTTPL_FIELD1TYPE SCIP_Longint
6261 #define SORTTPL_FIELD2TYPE SCIP_Real
6262 #define SORTTPL_FIELD3TYPE int
6263 #define SORTTPL_BACKWARDS
6264 #include "scip/sorttpl.c" /*lint !e451*/
6265
6266
6267 /* SCIPsortDownRealRealIntInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6268 #define SORTTPL_NAMEEXT DownRealRealIntInt
6269 #define SORTTPL_KEYTYPE SCIP_Real
6270 #define SORTTPL_FIELD1TYPE SCIP_Real
6271 #define SORTTPL_FIELD2TYPE int
6272 #define SORTTPL_FIELD3TYPE int
6273 #define SORTTPL_BACKWARDS
6274 #include "scip/sorttpl.c" /*lint !e451*/
6275
6276
6277 /* SCIPsortDownRealRealRealInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6278 #define SORTTPL_NAMEEXT DownRealRealRealInt
6279 #define SORTTPL_KEYTYPE SCIP_Real
6280 #define SORTTPL_FIELD1TYPE SCIP_Real
6281 #define SORTTPL_FIELD2TYPE SCIP_Real
6282 #define SORTTPL_FIELD3TYPE int
6283 #define SORTTPL_BACKWARDS
6284 #include "scip/sorttpl.c" /*lint !e451*/
6285
6286
6287 /* SCIPsortDownRealRealRealPtr(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6288 #define SORTTPL_NAMEEXT DownRealRealRealPtr
6289 #define SORTTPL_KEYTYPE SCIP_Real
6290 #define SORTTPL_FIELD1TYPE SCIP_Real
6291 #define SORTTPL_FIELD2TYPE SCIP_Real
6292 #define SORTTPL_FIELD3TYPE void*
6293 #define SORTTPL_BACKWARDS
6294 #include "scip/sorttpl.c" /*lint !e451*/
6295
6296
6297 /* SCIPsortDownRealPtrPtrInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6298 #define SORTTPL_NAMEEXT DownRealPtrPtrInt
6299 #define SORTTPL_KEYTYPE SCIP_Real
6300 #define SORTTPL_FIELD1TYPE void*
6301 #define SORTTPL_FIELD2TYPE void*
6302 #define SORTTPL_FIELD3TYPE int
6303 #define SORTTPL_BACKWARDS
6304 #include "scip/sorttpl.c" /*lint !e451*/
6305
6306 /* SCIPsortDownRealPtrPtrIntInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6307 #define SORTTPL_NAMEEXT DownRealPtrPtrIntInt
6308 #define SORTTPL_KEYTYPE SCIP_Real
6309 #define SORTTPL_FIELD1TYPE void*
6310 #define SORTTPL_FIELD2TYPE void*
6311 #define SORTTPL_FIELD3TYPE int
6312 #define SORTTPL_FIELD4TYPE int
6313 #define SORTTPL_BACKWARDS
6314 #include "scip/sorttpl.c" /*lint !e451*/
6315
6316
6317 /* SCIPsortDownRealRealRealBoolPtr(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6318 #define SORTTPL_NAMEEXT DownRealRealRealBoolPtr
6319 #define SORTTPL_KEYTYPE SCIP_Real
6320 #define SORTTPL_FIELD1TYPE SCIP_Real
6321 #define SORTTPL_FIELD2TYPE SCIP_Real
6322 #define SORTTPL_FIELD3TYPE SCIP_Bool
6323 #define SORTTPL_FIELD4TYPE void*
6324 #define SORTTPL_BACKWARDS
6325 #include "scip/sorttpl.c" /*lint !e451*/
6326
6327
6328 /* SCIPsortDownRealRealRealBoolBoolPtr(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6329 #define SORTTPL_NAMEEXT DownRealRealRealBoolBoolPtr
6330 #define SORTTPL_KEYTYPE SCIP_Real
6331 #define SORTTPL_FIELD1TYPE SCIP_Real
6332 #define SORTTPL_FIELD2TYPE SCIP_Real
6333 #define SORTTPL_FIELD3TYPE SCIP_Bool
6334 #define SORTTPL_FIELD4TYPE SCIP_Bool
6335 #define SORTTPL_FIELD5TYPE void*
6336 #include "scip/sorttpl.c" /*lint !e451*/
6337
6338
6339 /* SCIPsortDownInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6340 #define SORTTPL_NAMEEXT DownInt
6341 #define SORTTPL_KEYTYPE int
6342 #define SORTTPL_BACKWARDS
6343 #include "scip/sorttpl.c" /*lint !e451*/
6344
6345
6346 /* SCIPsortDownIntInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6347 #define SORTTPL_NAMEEXT DownIntInt
6348 #define SORTTPL_KEYTYPE int
6349 #define SORTTPL_FIELD1TYPE int
6350 #define SORTTPL_BACKWARDS
6351 #include "scip/sorttpl.c" /*lint !e451*/
6352
6353
6354 /* SCIPsortDownIntIntReal(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6355 #define SORTTPL_NAMEEXT DownIntIntReal
6356 #define SORTTPL_KEYTYPE int
6357 #define SORTTPL_FIELD1TYPE int
6358 #define SORTTPL_FIELD2TYPE SCIP_Real
6359 #define SORTTPL_BACKWARDS
6360 #include "scip/sorttpl.c" /*lint !e451*/
6361
6362
6363 /* SCIPsortDownIntReal(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6364 #define SORTTPL_NAMEEXT DownIntReal
6365 #define SORTTPL_KEYTYPE int
6366 #define SORTTPL_FIELD1TYPE SCIP_Real
6367 #define SORTTPL_BACKWARDS
6368 #include "scip/sorttpl.c" /*lint !e451*/
6369
6370
6371 /* SCIPsortDownIntPtr(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6372 #define SORTTPL_NAMEEXT DownIntPtr
6373 #define SORTTPL_KEYTYPE int
6374 #define SORTTPL_FIELD1TYPE void*
6375 #define SORTTPL_BACKWARDS
6376 #include "scip/sorttpl.c" /*lint !e451*/
6377
6378
6379 /* SCIPsortDownIntIntInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6380 #define SORTTPL_NAMEEXT DownIntIntInt
6381 #define SORTTPL_KEYTYPE int
6382 #define SORTTPL_FIELD1TYPE int
6383 #define SORTTPL_FIELD2TYPE int
6384 #define SORTTPL_BACKWARDS
6385 #include "scip/sorttpl.c" /*lint !e451*/
6386
6387
6388 /* SCIPsortDownIntIntLong(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6389 #define SORTTPL_NAMEEXT DownIntIntLong
6390 #define SORTTPL_KEYTYPE int
6391 #define SORTTPL_FIELD1TYPE int
6392 #define SORTTPL_FIELD2TYPE SCIP_Longint
6393 #define SORTTPL_BACKWARDS
6394 #include "scip/sorttpl.c" /*lint !e451*/
6395
6396
6397 /* SCIPsortDownIntIntPtr(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6398 #define SORTTPL_NAMEEXT DownIntIntPtr
6399 #define SORTTPL_KEYTYPE int
6400 #define SORTTPL_FIELD1TYPE int
6401 #define SORTTPL_FIELD2TYPE void*
6402 #define SORTTPL_BACKWARDS
6403 #include "scip/sorttpl.c" /*lint !e451*/
6404
6405
6406 /* SCIPsortDownIntIntIntPtr(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6407 #define SORTTPL_NAMEEXT DownIntIntIntPtr
6408 #define SORTTPL_KEYTYPE int
6409 #define SORTTPL_FIELD1TYPE int
6410 #define SORTTPL_FIELD2TYPE int
6411 #define SORTTPL_FIELD3TYPE void*
6412 #define SORTTPL_BACKWARDS
6413 #include "scip/sorttpl.c" /*lint !e451*/
6414
6415
6416 /* SCIPsortDownIntPtrIntReal(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6417 #define SORTTPL_NAMEEXT DownIntPtrIntReal
6418 #define SORTTPL_KEYTYPE int
6419 #define SORTTPL_FIELD1TYPE void*
6420 #define SORTTPL_FIELD2TYPE int
6421 #define SORTTPL_FIELD3TYPE SCIP_Real
6422 #define SORTTPL_BACKWARDS
6423 #include "scip/sorttpl.c" /*lint !e451*/
6424
6425
6426 /* SCIPsortDownLong(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6427 #define SORTTPL_NAMEEXT DownLong
6428 #define SORTTPL_KEYTYPE SCIP_Longint
6429 #define SORTTPL_BACKWARDS
6430 #include "scip/sorttpl.c" /*lint !e451*/
6431
6432
6433 /* SCIPsortDownLongPtr(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6434 #define SORTTPL_NAMEEXT DownLongPtr
6435 #define SORTTPL_KEYTYPE SCIP_Longint
6436 #define SORTTPL_FIELD1TYPE void*
6437 #define SORTTPL_BACKWARDS
6438 #include "scip/sorttpl.c" /*lint !e451*/
6439
6440
6441 /* SCIPsortDownLongPtrInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6442 #define SORTTPL_NAMEEXT DownLongPtrInt
6443 #define SORTTPL_KEYTYPE SCIP_Longint
6444 #define SORTTPL_FIELD1TYPE void*
6445 #define SORTTPL_FIELD2TYPE int
6446 #define SORTTPL_BACKWARDS
6447 #include "scip/sorttpl.c" /*lint !e451*/
6448
6449
6450 /* SCIPsortDownLongPtrRealBool(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6451 #define SORTTPL_NAMEEXT DownLongPtrRealBool
6452 #define SORTTPL_KEYTYPE SCIP_Longint
6453 #define SORTTPL_FIELD1TYPE void*
6454 #define SORTTPL_FIELD2TYPE SCIP_Real
6455 #define SORTTPL_FIELD3TYPE SCIP_Bool
6456 #define SORTTPL_BACKWARDS
6457 #include "scip/sorttpl.c" /*lint !e451*/
6458
6459
6460 /* SCIPsortDownLongPtrRealRealBool(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6461 #define SORTTPL_NAMEEXT DownLongPtrRealRealBool
6462 #define SORTTPL_KEYTYPE SCIP_Longint
6463 #define SORTTPL_FIELD1TYPE void*
6464 #define SORTTPL_FIELD2TYPE SCIP_Real
6465 #define SORTTPL_FIELD3TYPE SCIP_Real
6466 #define SORTTPL_FIELD4TYPE SCIP_Bool
6467 #define SORTTPL_BACKWARDS
6468 #include "scip/sorttpl.c" /*lint !e451*/
6469
6470
6471 /* SCIPsortLongPtrRealRealIntBool(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6472 #define SORTTPL_NAMEEXT DownLongPtrRealRealIntBool
6473 #define SORTTPL_KEYTYPE SCIP_Longint
6474 #define SORTTPL_FIELD1TYPE void*
6475 #define SORTTPL_FIELD2TYPE SCIP_Real
6476 #define SORTTPL_FIELD3TYPE SCIP_Real
6477 #define SORTTPL_FIELD4TYPE int
6478 #define SORTTPL_FIELD5TYPE SCIP_Bool
6479 #define SORTTPL_BACKWARDS
6480 #include "scip/sorttpl.c" /*lint !e451*/
6481
6482
6483 /* SCIPsortDownLongPtrPtrInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6484 #define SORTTPL_NAMEEXT DownLongPtrPtrInt
6485 #define SORTTPL_KEYTYPE SCIP_Longint
6486 #define SORTTPL_FIELD1TYPE void*
6487 #define SORTTPL_FIELD2TYPE void*
6488 #define SORTTPL_FIELD3TYPE int
6489 #define SORTTPL_BACKWARDS
6490 #include "scip/sorttpl.c" /*lint !e451*/
6491
6492
6493 /* SCIPsortDownLongPtrPtrIntInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6494 #define SORTTPL_NAMEEXT DownLongPtrPtrIntInt
6495 #define SORTTPL_KEYTYPE SCIP_Longint
6496 #define SORTTPL_FIELD1TYPE void*
6497 #define SORTTPL_FIELD2TYPE void*
6498 #define SORTTPL_FIELD3TYPE int
6499 #define SORTTPL_FIELD4TYPE int
6500 #define SORTTPL_BACKWARDS
6501 #include "scip/sorttpl.c" /*lint !e451*/
6502
6503
6504 /* SCIPsortDownLongPtrPtrBoolInt(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6505 #define SORTTPL_NAMEEXT DownLongPtrPtrBoolInt
6506 #define SORTTPL_KEYTYPE SCIP_Longint
6507 #define SORTTPL_FIELD1TYPE void*
6508 #define SORTTPL_FIELD2TYPE void*
6509 #define SORTTPL_FIELD3TYPE SCIP_Bool
6510 #define SORTTPL_FIELD4TYPE int
6511 #define SORTTPL_BACKWARDS
6512 #include "scip/sorttpl.c" /*lint !e451*/
6513
6514
6515 /* SCIPsortDownPtrIntIntBoolBool(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6516 #define SORTTPL_NAMEEXT DownPtrIntIntBoolBool
6517 #define SORTTPL_KEYTYPE void*
6518 #define SORTTPL_FIELD1TYPE int
6519 #define SORTTPL_FIELD2TYPE int
6520 #define SORTTPL_FIELD3TYPE SCIP_Bool
6521 #define SORTTPL_FIELD4TYPE SCIP_Bool
6522 #define SORTTPL_PTRCOMP
6523 #define SORTTPL_BACKWARDS
6524 #include "scip/sorttpl.c" /*lint !e451*/
6525
6526
6527 /* SCIPsortDownIntPtrIntIntBoolBool(), SCIPsortedvecInsert...(), SCIPsortedvecDelPos...(), SCIPsortedvecFind...() via sort template */
6528 #define SORTTPL_NAMEEXT DownIntPtrIntIntBoolBool
6529 #define SORTTPL_KEYTYPE int
6530 #define SORTTPL_FIELD1TYPE void*
6531 #define SORTTPL_FIELD2TYPE int
6532 #define SORTTPL_FIELD3TYPE int
6533 #define SORTTPL_FIELD4TYPE SCIP_Bool
6534 #define SORTTPL_FIELD5TYPE SCIP_Bool
6535 #define SORTTPL_BACKWARDS
6536 #include "scip/sorttpl.c" /*lint !e451*/
6537
6538 /*
6539 * Resulting activity
6540 */
6541
6542 /** create a resource activity */
SCIPactivityCreate(SCIP_RESOURCEACTIVITY ** activity,SCIP_VAR * var,int duration,int demand)6543 SCIP_RETCODE SCIPactivityCreate(
6544 SCIP_RESOURCEACTIVITY** activity, /**< pointer to store the resource activity */
6545 SCIP_VAR* var, /**< start time variable of the activity */
6546 int duration, /**< duration of the activity */
6547 int demand /**< demand of the activity */
6548 )
6549 {
6550 assert(activity != NULL);
6551
6552 SCIP_ALLOC( BMSallocMemory(activity) );
6553
6554 (*activity)->var = var;
6555 (*activity)->duration = duration;
6556 (*activity)->demand = demand;
6557
6558 return SCIP_OKAY;
6559 }
6560
6561 /** frees a resource activity */
SCIPactivityFree(SCIP_RESOURCEACTIVITY ** activity)6562 void SCIPactivityFree(
6563 SCIP_RESOURCEACTIVITY** activity /**< pointer to the resource activity */
6564 )
6565 {
6566 assert(activity != NULL);
6567 assert(*activity != NULL);
6568
6569 BMSfreeMemory(activity);
6570 }
6571
6572 /* some simple variable functions implemented as defines */
6573
6574 #ifndef NDEBUG
6575
6576 /* In debug mode, the following methods are implemented as function calls to ensure
6577 * type validity.
6578 * In optimized mode, the methods are implemented as defines to improve performance.
6579 * However, we want to have them in the library anyways, so we have to undef the defines.
6580 */
6581
6582 #undef SCIPactivityGetVar
6583 #undef SCIPactivityGetDuration
6584 #undef SCIPactivityGetDemand
6585 #undef SCIPactivityGetEnergy
6586
6587 /** returns the start time variable of the resource activity */
SCIPactivityGetVar(SCIP_RESOURCEACTIVITY * activity)6588 SCIP_VAR* SCIPactivityGetVar(
6589 SCIP_RESOURCEACTIVITY* activity /**< resource activity */
6590 )
6591 {
6592 assert(activity != NULL);
6593
6594 return activity->var;
6595 }
6596
6597 /** returns the duration of the resource activity */
SCIPactivityGetDuration(SCIP_RESOURCEACTIVITY * activity)6598 int SCIPactivityGetDuration(
6599 SCIP_RESOURCEACTIVITY* activity /**< resource activity */
6600 )
6601 {
6602 assert(activity != NULL);
6603
6604 return activity->duration;
6605 }
6606
6607 /** returns the demand of the resource activity */
SCIPactivityGetDemand(SCIP_RESOURCEACTIVITY * activity)6608 int SCIPactivityGetDemand(
6609 SCIP_RESOURCEACTIVITY* activity /**< resource activity */
6610 )
6611 {
6612 assert(activity != NULL);
6613
6614 return activity->demand;
6615 }
6616
6617 /** returns the energy of the resource activity */
SCIPactivityGetEnergy(SCIP_RESOURCEACTIVITY * activity)6618 int SCIPactivityGetEnergy(
6619 SCIP_RESOURCEACTIVITY* activity /**< resource activity */
6620 )
6621 {
6622 assert(activity != NULL);
6623
6624 return activity->duration * activity->demand ;
6625 }
6626
6627 #endif
6628
6629 /*
6630 * Resource Profile
6631 */
6632
6633 /** helper method to create a profile */
6634 static
doProfileCreate(SCIP_PROFILE ** profile,int capacity)6635 SCIP_RETCODE doProfileCreate(
6636 SCIP_PROFILE** profile, /**< pointer to store the resource profile */
6637 int capacity /**< resource capacity */
6638 )
6639 {
6640 SCIP_ALLOC( BMSallocMemory(profile) );
6641 BMSclearMemory(*profile);
6642
6643 (*profile)->arraysize = 10;
6644 SCIP_ALLOC( BMSallocMemoryArray(&(*profile)->timepoints, (*profile)->arraysize) );
6645 SCIP_ALLOC( BMSallocMemoryArray(&(*profile)->loads, (*profile)->arraysize) );
6646
6647 /* setup resource profile for use */
6648 (*profile)->ntimepoints = 1;
6649 (*profile)->timepoints[0] = 0;
6650 (*profile)->loads[0] = 0;
6651 (*profile)->capacity = capacity;
6652
6653 return SCIP_OKAY;
6654 }
6655
6656 /** creates resource profile */
SCIPprofileCreate(SCIP_PROFILE ** profile,int capacity)6657 SCIP_RETCODE SCIPprofileCreate(
6658 SCIP_PROFILE** profile, /**< pointer to store the resource profile */
6659 int capacity /**< resource capacity */
6660 )
6661 {
6662 assert(profile != NULL);
6663 assert(capacity > 0);
6664
6665 SCIP_CALL_FINALLY( doProfileCreate(profile, capacity), SCIPprofileFree(profile) );
6666
6667 return SCIP_OKAY;
6668 }
6669
6670 /** frees given resource profile */
SCIPprofileFree(SCIP_PROFILE ** profile)6671 void SCIPprofileFree(
6672 SCIP_PROFILE** profile /**< pointer to the resource profile */
6673 )
6674 {
6675 assert(profile != NULL);
6676
6677 /* free resource profile */
6678 if( *profile != NULL )
6679 {
6680 BMSfreeMemoryArrayNull(&(*profile)->loads);
6681 BMSfreeMemoryArrayNull(&(*profile)->timepoints);
6682 BMSfreeMemory(profile);
6683 }
6684 }
6685
6686 /** output of the given resource profile */
SCIPprofilePrint(SCIP_PROFILE * profile,SCIP_MESSAGEHDLR * messagehdlr,FILE * file)6687 void SCIPprofilePrint(
6688 SCIP_PROFILE* profile, /**< resource profile to output */
6689 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
6690 FILE* file /**< output file (or NULL for standard output) */
6691 )
6692 {
6693 int t;
6694
6695 SCIPmessageFPrintInfo(messagehdlr, file, "Profile <%p> (capacity %d) --> ", (void*)profile, profile->capacity);
6696
6697 for( t = 0; t < profile->ntimepoints; ++t )
6698 {
6699 if( t == 0 )
6700 SCIPmessageFPrintInfo(messagehdlr, file, "%d:(%d,%d)", t, profile->timepoints[t], profile->loads[t]);
6701 else
6702 SCIPmessageFPrintInfo(messagehdlr, file, ", %d:(%d,%d)", t, profile->timepoints[t], profile->loads[t]);
6703 }
6704
6705 SCIPmessageFPrintInfo(messagehdlr, file,"\n");
6706 }
6707
6708 /** returns the capacity of the resource profile */
SCIPprofileGetCapacity(SCIP_PROFILE * profile)6709 int SCIPprofileGetCapacity(
6710 SCIP_PROFILE* profile /**< resource profile to use */
6711 )
6712 {
6713 assert(profile != NULL);
6714
6715 return profile->capacity;
6716 }
6717
6718 /** returns the number time points of the resource profile */
SCIPprofileGetNTimepoints(SCIP_PROFILE * profile)6719 int SCIPprofileGetNTimepoints(
6720 SCIP_PROFILE* profile /**< resource profile to use */
6721 )
6722 {
6723 assert(profile != NULL);
6724
6725 return profile->ntimepoints;
6726 }
6727
6728 /** returns the time points of the resource profile */
SCIPprofileGetTimepoints(SCIP_PROFILE * profile)6729 int* SCIPprofileGetTimepoints(
6730 SCIP_PROFILE* profile /**< resource profile to use */
6731 )
6732 {
6733 assert(profile != NULL);
6734
6735 return profile->timepoints;
6736 }
6737
6738 /** returns the loads of the resource profile */
SCIPprofileGetLoads(SCIP_PROFILE * profile)6739 int* SCIPprofileGetLoads(
6740 SCIP_PROFILE* profile /**< resource profile to use */
6741 )
6742 {
6743 assert(profile != NULL);
6744
6745 return profile->loads;
6746 }
6747
6748 /** returns the time point for given position of the resource profile */
SCIPprofileGetTime(SCIP_PROFILE * profile,int pos)6749 int SCIPprofileGetTime(
6750 SCIP_PROFILE* profile, /**< resource profile to use */
6751 int pos /**< position */
6752 )
6753 {
6754 assert(profile != NULL);
6755 assert(pos >= 0 && pos < profile->ntimepoints);
6756
6757 return profile->timepoints[pos];
6758 }
6759
6760 /** returns the loads of the resource profile at the given position */
SCIPprofileGetLoad(SCIP_PROFILE * profile,int pos)6761 int SCIPprofileGetLoad(
6762 SCIP_PROFILE* profile, /**< resource profile */
6763 int pos /**< position */
6764 )
6765 {
6766 assert(profile != NULL);
6767 assert(pos >= 0 && pos < profile->ntimepoints);
6768
6769 return profile->loads[pos];
6770 }
6771
6772 /** returns if the given time point exists in the resource profile and stores the position of the given time point if it
6773 * exists; otherwise the position of the next smaller existing time point is stored
6774 */
SCIPprofileFindLeft(SCIP_PROFILE * profile,int timepoint,int * pos)6775 SCIP_Bool SCIPprofileFindLeft(
6776 SCIP_PROFILE* profile, /**< resource profile to search */
6777 int timepoint, /**< time point to search for */
6778 int* pos /**< pointer to store the position */
6779 )
6780 {
6781 assert(profile != NULL);
6782 assert(timepoint >= 0);
6783 assert(profile->ntimepoints > 0);
6784 assert(profile->timepoints[0] == 0);
6785
6786 /* find the position of time point in the time points array via binary search */
6787 if( SCIPsortedvecFindInt(profile->timepoints, timepoint, profile->ntimepoints, pos) )
6788 return TRUE;
6789
6790 assert(*pos > 0);
6791 (*pos)--;
6792
6793 return FALSE;
6794 }
6795
6796 /* ensures that resource profile arrays is big enough */
6797 static
ensureProfileSize(SCIP_PROFILE * profile,int neededsize)6798 SCIP_RETCODE ensureProfileSize(
6799 SCIP_PROFILE* profile, /**< resource profile to insert the time point */
6800 int neededsize /**< needed size */
6801 )
6802 {
6803 assert(profile->arraysize > 0);
6804
6805 /* check whether the arrays are big enough */
6806 if( neededsize <= profile->arraysize )
6807 return SCIP_OKAY;
6808
6809 profile->arraysize *= 2;
6810
6811 SCIP_ALLOC( BMSreallocMemoryArray(&profile->timepoints, profile->arraysize) );
6812 SCIP_ALLOC( BMSreallocMemoryArray(&profile->loads, profile->arraysize) );
6813
6814 return SCIP_OKAY;
6815 }
6816
6817 /** inserts the given time point into the resource profile if it this time point does not exists yet; returns its
6818 * position in the time point array
6819 */
6820 static
profileInsertTimepoint(SCIP_PROFILE * profile,int timepoint,int * pos)6821 SCIP_RETCODE profileInsertTimepoint(
6822 SCIP_PROFILE* profile, /**< resource profile to insert the time point */
6823 int timepoint, /**< time point to insert */
6824 int* pos /**< pointer to store the insert position */
6825 )
6826 {
6827 assert(profile != NULL);
6828 assert(timepoint >= 0);
6829 assert(profile->arraysize >= profile->ntimepoints);
6830
6831 /* get the position of the given time point in the resource profile array if it exists; otherwise the position of the
6832 * next smaller existing time point
6833 */
6834 if( !SCIPprofileFindLeft(profile, timepoint, pos) )
6835 {
6836 assert(*pos >= 0 && *pos < profile->ntimepoints);
6837 assert(timepoint >= profile->timepoints[*pos]);
6838
6839 /* ensure that the arrays are big enough */
6840 SCIP_CALL( ensureProfileSize(profile, profile->ntimepoints + 1) );
6841 assert(profile->arraysize > profile->ntimepoints);
6842
6843 /* insert new time point into the (sorted) resource profile */
6844 SCIPsortedvecInsertIntInt(profile->timepoints, profile->loads, timepoint, profile->loads[*pos],
6845 &profile->ntimepoints, pos);
6846 }
6847
6848 #ifndef NDEBUG
6849 /* check if the time points are sorted */
6850 {
6851 int i;
6852 for( i = 1; i < profile->ntimepoints; ++i )
6853 assert(profile->timepoints[i-1] < profile->timepoints[i]);
6854 }
6855 #endif
6856
6857 return SCIP_OKAY;
6858 }
6859
6860 /** updates the resource profile due to inserting of a core */
6861 static
profileUpdate(SCIP_PROFILE * profile,int left,int right,int demand,int * pos,SCIP_Bool * infeasible)6862 SCIP_RETCODE profileUpdate(
6863 SCIP_PROFILE* profile, /**< resource profile to update */
6864 int left, /**< left side of core interval */
6865 int right, /**< right side of core interval */
6866 int demand, /**< demand of the core */
6867 int* pos, /**< pointer to store the first position were it gets infeasible */
6868 SCIP_Bool* infeasible /**< pointer to store if the update is infeasible */
6869 )
6870 {
6871 int startpos;
6872 int endpos;
6873 int i;
6874
6875 assert(profile != NULL);
6876 assert(profile->arraysize >= profile->ntimepoints);
6877 assert(left >= 0);
6878 assert(left < right);
6879 assert(infeasible != NULL);
6880
6881 (*infeasible) = FALSE;
6882 (*pos) = -1;
6883
6884 /* get position of the starttime in profile */
6885 SCIP_CALL( profileInsertTimepoint(profile, left, &startpos) );
6886 assert(profile->timepoints[startpos] == left);
6887
6888 /* get position of the endtime in profile */
6889 SCIP_CALL( profileInsertTimepoint(profile, right, &endpos) );
6890 assert(profile->timepoints[endpos] == right);
6891
6892 assert(startpos < endpos);
6893 assert(profile->arraysize >= profile->ntimepoints);
6894
6895 /* remove/add the given demand from the core */
6896 for( i = startpos; i < endpos; ++i )
6897 {
6898 profile->loads[i] += demand;
6899
6900 /* check if the core fits */
6901 if( profile->loads[i] > profile->capacity )
6902 {
6903 SCIPdebugMessage("core insertion detected infeasibility (pos %d)\n", i);
6904
6905 (*infeasible) = TRUE;
6906 (*pos) = i;
6907
6908 /* remove the partly inserted core since it does fit completely */
6909 for( ; i >= startpos; --i ) /*lint !e445*/
6910 profile->loads[i] -= demand;
6911
6912 break;
6913 }
6914 }
6915
6916 return SCIP_OKAY;
6917 }
6918
6919 /** insert a core into resource profile; if the core is non-empty the resource profile will be updated otherwise nothing
6920 * happens
6921 */
SCIPprofileInsertCore(SCIP_PROFILE * profile,int left,int right,int demand,int * pos,SCIP_Bool * infeasible)6922 SCIP_RETCODE SCIPprofileInsertCore(
6923 SCIP_PROFILE* profile, /**< resource profile */
6924 int left, /**< left side of the core */
6925 int right, /**< right side of the core */
6926 int demand, /**< demand of the core */
6927 int* pos, /**< pointer to store the first position were it gets infeasible */
6928 SCIP_Bool* infeasible /**< pointer to store if the core does not fit due to capacity */
6929 )
6930 {
6931 assert(profile != NULL);
6932 assert(left < right);
6933 assert(demand >= 0);
6934 assert(infeasible != NULL);
6935
6936 (*infeasible) = FALSE;
6937 (*pos) = -1;
6938
6939 /* insert core into the resource profile */
6940 SCIPdebugMessage("insert core [%d,%d] with demand %d\n", left, right, demand);
6941
6942 if( demand > 0 )
6943 {
6944 /* try to insert core into the resource profile */
6945 SCIP_CALL( profileUpdate(profile, left, right, demand, pos, infeasible) );
6946 }
6947
6948 return SCIP_OKAY;
6949 }
6950
6951 /** subtracts the demand from the resource profile during core time */
SCIPprofileDeleteCore(SCIP_PROFILE * profile,int left,int right,int demand)6952 SCIP_RETCODE SCIPprofileDeleteCore(
6953 SCIP_PROFILE* profile, /**< resource profile to use */
6954 int left, /**< left side of the core */
6955 int right, /**< right side of the core */
6956 int demand /**< demand of the core */
6957 )
6958 {
6959 SCIP_Bool infeasible;
6960 int pos;
6961
6962 assert(left < right);
6963 #ifndef NDEBUG
6964 {
6965 /* check if the left and right time points of the core correspond to a time point in the resource profile; this
6966 * should be the case since we added the core before to the resource profile
6967 */
6968 assert(SCIPprofileFindLeft(profile, left, &pos));
6969 assert(SCIPprofileFindLeft(profile, right, &pos));
6970 }
6971 #endif
6972
6973 /* remove the core from the resource profile */
6974 SCIPdebugMessage("delete core [%d,%d] with demand %d\n", left, right, demand);
6975
6976 SCIP_CALL( profileUpdate(profile, left, right, -demand, &pos, &infeasible) );
6977 assert(!infeasible);
6978
6979 return SCIP_OKAY; /*lint !e438*/
6980 }
6981
6982 /** returns TRUE if the core (given by its demand and during) can be inserted at the given time point; otherwise FALSE */
6983 static
profileFindFeasibleStart(SCIP_PROFILE * profile,int pos,int lst,int duration,int demand,SCIP_Bool * infeasible)6984 int profileFindFeasibleStart(
6985 SCIP_PROFILE* profile, /**< resource profile to use */
6986 int pos, /**< pointer to store the position in the profile to start the serch */
6987 int lst, /**< latest start time */
6988 int duration, /**< duration of the core */
6989 int demand, /**< demand of the core */
6990 SCIP_Bool* infeasible /**< pointer store if the corer cannot be inserted */
6991 )
6992 {
6993 int remainingduration;
6994 int startpos;
6995
6996 assert(profile != NULL);
6997 assert(pos >= 0);
6998 assert(pos < profile->ntimepoints);
6999 assert(duration > 0);
7000 assert(demand > 0);
7001 assert(profile->loads[profile->ntimepoints-1] == 0);
7002
7003 remainingduration = duration;
7004 startpos = pos;
7005 (*infeasible) = FALSE;
7006
7007 if( profile->timepoints[startpos] > lst )
7008 {
7009 (*infeasible) = TRUE;
7010 return pos;
7011 }
7012
7013 while( pos < profile->ntimepoints - 1 )
7014 {
7015 if( profile->loads[pos] + demand > profile->capacity )
7016 {
7017 SCIPdebugMessage("profile <%p>: core does not fit at time point %d (pos %d)\n", (void*)profile, profile->timepoints[pos], pos);
7018 startpos = pos + 1;
7019 remainingduration = duration;
7020
7021 if( profile->timepoints[startpos] > lst )
7022 {
7023 (*infeasible) = TRUE;
7024 return pos;
7025 }
7026 }
7027 else
7028 remainingduration -= profile->timepoints[pos+1] - profile->timepoints[pos];
7029
7030 if( remainingduration <= 0 )
7031 break;
7032
7033 pos++;
7034 }
7035
7036 return startpos;
7037 }
7038
7039 /** return the earliest possible starting point within the time interval [lb,ub] for a given core (given by its demand
7040 * and duration)
7041 */
SCIPprofileGetEarliestFeasibleStart(SCIP_PROFILE * profile,int est,int lst,int duration,int demand,SCIP_Bool * infeasible)7042 int SCIPprofileGetEarliestFeasibleStart(
7043 SCIP_PROFILE* profile, /**< resource profile to use */
7044 int est, /**< earliest starting time of the given core */
7045 int lst, /**< latest starting time of the given core */
7046 int duration, /**< duration of the core */
7047 int demand, /**< demand of the core */
7048 SCIP_Bool* infeasible /**< pointer store if the corer cannot be inserted */
7049 )
7050 {
7051 SCIP_Bool found;
7052 int pos;
7053
7054 assert(profile != NULL);
7055 assert(est >= 0);
7056 assert(est <= lst);
7057 assert(duration >= 0);
7058 assert(demand >= 0);
7059 assert(infeasible != NULL);
7060 assert(profile->ntimepoints > 0);
7061 assert(profile->loads[profile->ntimepoints-1] == 0);
7062
7063 SCIPdebugMessage("profile <%p>: find earliest start time (demad %d, duration %d) [%d,%d]\n", (void*)profile, demand, duration, est, lst);
7064
7065 if( duration == 0 || demand == 0 )
7066 {
7067 *infeasible = FALSE;
7068 return est;
7069 }
7070
7071 found = SCIPprofileFindLeft(profile, est, &pos);
7072 SCIPdebugMessage("profile <%p>: earliest start time does %s exist as time point (pos %d)\n", (void*)profile, found ? "" : "not", pos);
7073
7074 /* if the position is the last time point in the profile, the core can be inserted at its earliest start time */
7075 if( pos == profile->ntimepoints - 1 )
7076 {
7077 (*infeasible) = FALSE;
7078 return est;
7079 }
7080
7081 if( found )
7082 {
7083 /* if the start time matches a time point in the profile we can just search */
7084 assert(profile->timepoints[pos] == est);
7085 pos = profileFindFeasibleStart(profile, pos, lst, duration, demand, infeasible);
7086
7087 assert(pos < profile->ntimepoints);
7088 est = profile->timepoints[pos];
7089 }
7090 else if( profile->loads[pos] + demand > profile->capacity )
7091 {
7092 /* if the the time point left to the start time has not enough free capacity we can just search the profile
7093 * starting from the next time point
7094 */
7095 assert(profile->timepoints[pos] <= est);
7096 pos = profileFindFeasibleStart(profile, pos+1, lst, duration, demand, infeasible);
7097
7098 assert(pos < profile->ntimepoints);
7099 est = profile->timepoints[pos];
7100 }
7101 else
7102 {
7103 int remainingduration;
7104
7105 /* check if the core can be placed at its earliest start time */
7106
7107 assert(pos < profile->ntimepoints - 1);
7108
7109 remainingduration = duration - (profile->timepoints[pos+1] - est);
7110 SCIPdebugMessage("remaining duration %d\n", remainingduration);
7111
7112 if( remainingduration <= 0 )
7113 (*infeasible) = FALSE;
7114 else
7115 {
7116 pos = profileFindFeasibleStart(profile, pos+1, profile->timepoints[pos+1], remainingduration, demand, infeasible);
7117 SCIPdebugMessage("remaining duration can%s be processed\n", *infeasible ? "not" : "");
7118
7119 if( *infeasible )
7120 {
7121 pos = profileFindFeasibleStart(profile, pos+1, lst, duration, demand, infeasible);
7122
7123 assert(pos < profile->ntimepoints);
7124 est = profile->timepoints[pos];
7125 }
7126 }
7127 }
7128
7129 return est;
7130 }
7131
7132 /** returns TRUE if the core (given by its demand and during) can be inserted at the given time point; otherwise FALSE */
7133 static
profileFindDownFeasibleStart(SCIP_PROFILE * profile,int pos,int ect,int duration,int demand,SCIP_Bool * infeasible)7134 int profileFindDownFeasibleStart(
7135 SCIP_PROFILE* profile, /**< resource profile to use */
7136 int pos, /**< pointer to store the position in the profile to start the search */
7137 int ect, /**< earliest completion time */
7138 int duration, /**< duration of the core */
7139 int demand, /**< demand of the core */
7140 SCIP_Bool* infeasible /**< pointer store if the corer cannot be inserted */
7141 )
7142 {
7143 int remainingduration;
7144 int endpos;
7145
7146 assert(profile != NULL);
7147 assert(pos >= 0);
7148 assert(pos < profile->ntimepoints);
7149 assert(duration > 0);
7150 assert(demand > 0);
7151 assert(profile->ntimepoints > 0);
7152 assert(profile->loads[profile->ntimepoints-1] == 0);
7153
7154 remainingduration = duration;
7155 endpos = pos;
7156 (*infeasible) = TRUE;
7157
7158 if( profile->timepoints[endpos] < ect - duration )
7159 return pos;
7160
7161 while( pos > 0 )
7162 {
7163 if( profile->loads[pos-1] + demand > profile->capacity )
7164 {
7165 SCIPdebugMessage("profile <%p>: core does not fit at time point %d (pos %d)\n", (void*)profile, profile->timepoints[pos-1], pos-1);
7166
7167 endpos = pos - 1;
7168 remainingduration = duration;
7169
7170 if( profile->timepoints[endpos] < ect - duration )
7171 return pos;
7172 }
7173 else
7174 remainingduration -= profile->timepoints[pos] - profile->timepoints[pos-1];
7175
7176 if( remainingduration <= 0 )
7177 {
7178 *infeasible = FALSE;
7179 break;
7180 }
7181
7182 pos--;
7183 }
7184
7185 return endpos;
7186 }
7187
7188 /** return the latest possible starting point within the time interval [lb,ub] for a given core (given by its demand and
7189 * duration)
7190 */
SCIPprofileGetLatestFeasibleStart(SCIP_PROFILE * profile,int est,int lst,int duration,int demand,SCIP_Bool * infeasible)7191 int SCIPprofileGetLatestFeasibleStart(
7192 SCIP_PROFILE* profile, /**< resource profile to use */
7193 int est, /**< earliest possible start point */
7194 int lst, /**< latest possible start point */
7195 int duration, /**< duration of the core */
7196 int demand, /**< demand of the core */
7197 SCIP_Bool* infeasible /**< pointer store if the core cannot be inserted */
7198 )
7199 {
7200 SCIP_Bool found;
7201 int ect;
7202 int lct;
7203 int pos;
7204
7205 assert(profile != NULL);
7206 assert(est >= 0);
7207 assert(est <= lst);
7208 assert(duration >= 0);
7209 assert(demand >= 0);
7210 assert(infeasible != NULL);
7211 assert(profile->ntimepoints > 0);
7212 assert(profile->loads[profile->ntimepoints-1] == 0);
7213
7214 if( duration == 0 || demand == 0 )
7215 {
7216 *infeasible = FALSE;
7217 return lst;
7218 }
7219
7220 ect = est + duration;
7221 lct = lst + duration;
7222
7223 found = SCIPprofileFindLeft(profile, lct, &pos);
7224 SCIPdebugMessage("profile <%p>: latest completion time %d does %s exist as time point (pos %d)\n", (void*)profile, lct, found ? "" : "not", pos);
7225
7226 if( found )
7227 {
7228 /* if the start time matches a time point in the profile we can just search */
7229 assert(profile->timepoints[pos] == lct);
7230 pos = profileFindDownFeasibleStart(profile, pos, ect, duration, demand, infeasible);
7231
7232 assert(pos < profile->ntimepoints && pos >= 0);
7233 lct = profile->timepoints[pos];
7234 }
7235 else if( profile->loads[pos] + demand > profile->capacity )
7236 {
7237 /* if the time point left to the start time has not enough free capacity we can just search the profile starting
7238 * from the next time point
7239 */
7240 assert(profile->timepoints[pos] < lct);
7241 pos = profileFindDownFeasibleStart(profile, pos, ect, duration, demand, infeasible);
7242
7243 assert(pos < profile->ntimepoints && pos >= 0);
7244 lct = profile->timepoints[pos];
7245 }
7246 else
7247 {
7248 int remainingduration;
7249
7250 /* check if the core can be placed at its latest start time */
7251 assert(profile->timepoints[pos] < lct);
7252
7253 remainingduration = duration - (lct - profile->timepoints[pos]);
7254
7255 if( remainingduration <= 0 )
7256 (*infeasible) = FALSE;
7257 else
7258 {
7259 pos = profileFindDownFeasibleStart(profile, pos, profile->timepoints[pos], remainingduration, demand, infeasible);
7260
7261 if( *infeasible )
7262 {
7263 pos = profileFindDownFeasibleStart(profile, pos, ect, duration, demand, infeasible);
7264
7265 assert(pos < profile->ntimepoints && pos >= 0);
7266 lct = profile->timepoints[pos];
7267 }
7268 }
7269 }
7270
7271 return lct - duration;
7272 }
7273
7274 /*
7275 * Directed graph
7276 */
7277
7278 /** creates directed graph structure */
SCIPdigraphCreate(SCIP_DIGRAPH ** digraph,BMS_BLKMEM * blkmem,int nnodes)7279 SCIP_RETCODE SCIPdigraphCreate(
7280 SCIP_DIGRAPH** digraph, /**< pointer to store the created directed graph */
7281 BMS_BLKMEM* blkmem, /**< block memory to store the data */
7282 int nnodes /**< number of nodes */
7283 )
7284 {
7285 assert(digraph != NULL);
7286 assert(blkmem != NULL);
7287 assert(nnodes > 0);
7288
7289 /* allocate memory for the graph and the arrays storing arcs and data */
7290 SCIP_ALLOC( BMSallocBlockMemory(blkmem, digraph) );
7291 SCIP_ALLOC( BMSallocClearBlockMemoryArray(blkmem, &(*digraph)->successors, nnodes) );
7292 SCIP_ALLOC( BMSallocClearBlockMemoryArray(blkmem, &(*digraph)->arcdata, nnodes) );
7293 SCIP_ALLOC( BMSallocClearBlockMemoryArray(blkmem, &(*digraph)->successorssize, nnodes) );
7294 SCIP_ALLOC( BMSallocClearBlockMemoryArray(blkmem, &(*digraph)->nsuccessors, nnodes) );
7295 SCIP_ALLOC( BMSallocClearBlockMemoryArray(blkmem, &(*digraph)->nodedata, nnodes) );
7296
7297 /* store number of nodes */
7298 (*digraph)->nnodes = nnodes;
7299
7300 /* at the beginning, no components are stored */
7301 (*digraph)->blkmem = blkmem;
7302 (*digraph)->ncomponents = 0;
7303 (*digraph)->componentstartsize = 0;
7304 (*digraph)->components = NULL;
7305 (*digraph)->componentstarts = NULL;
7306
7307 /* all nodes are initially considered as non-articulation points */
7308 (*digraph)->narticulations = -1;
7309 (*digraph)->articulations = NULL;
7310 (*digraph)->articulationscheck = FALSE;
7311
7312 return SCIP_OKAY;
7313 }
7314
7315 /** resize directed graph structure */
SCIPdigraphResize(SCIP_DIGRAPH * digraph,int nnodes)7316 SCIP_RETCODE SCIPdigraphResize(
7317 SCIP_DIGRAPH* digraph, /**< directed graph */
7318 int nnodes /**< new number of nodes */
7319 )
7320 {
7321 int n;
7322 assert(digraph != NULL);
7323 assert(digraph->blkmem != NULL);
7324
7325 /* check if the digraph has already a proper size */
7326 if( nnodes <= digraph->nnodes )
7327 return SCIP_OKAY;
7328
7329 /* reallocate memory for increasing the arrays storing arcs and data */
7330 SCIP_ALLOC( BMSreallocBlockMemoryArray(digraph->blkmem, &digraph->successors, digraph->nnodes, nnodes) );
7331 SCIP_ALLOC( BMSreallocBlockMemoryArray(digraph->blkmem, &digraph->arcdata, digraph->nnodes, nnodes) );
7332 SCIP_ALLOC( BMSreallocBlockMemoryArray(digraph->blkmem, &digraph->successorssize, digraph->nnodes, nnodes) );
7333 SCIP_ALLOC( BMSreallocBlockMemoryArray(digraph->blkmem, &digraph->nsuccessors, digraph->nnodes, nnodes) );
7334 SCIP_ALLOC( BMSreallocBlockMemoryArray(digraph->blkmem, &digraph->nodedata, digraph->nnodes, nnodes) );
7335
7336 /* initialize the new node data structures */
7337 for( n = digraph->nnodes; n < nnodes; ++n )
7338 {
7339 digraph->nodedata[n] = NULL;
7340 digraph->arcdata[n] = NULL;
7341 digraph->successors[n] = NULL;
7342 digraph->successorssize[n] = 0;
7343 digraph->nsuccessors[n] = 0;
7344 }
7345
7346 /* store the new number of nodes */
7347 digraph->nnodes = nnodes;
7348
7349 return SCIP_OKAY;
7350 }
7351
7352 /** copies directed graph structure
7353 *
7354 * @note The data in nodedata is copied verbatim. This possibly has to be adapted by the user.
7355 */
SCIPdigraphCopy(SCIP_DIGRAPH ** targetdigraph,SCIP_DIGRAPH * sourcedigraph,BMS_BLKMEM * targetblkmem)7356 SCIP_RETCODE SCIPdigraphCopy(
7357 SCIP_DIGRAPH** targetdigraph, /**< pointer to store the copied directed graph */
7358 SCIP_DIGRAPH* sourcedigraph, /**< source directed graph */
7359 BMS_BLKMEM* targetblkmem /**< block memory to store the target block memory, or NULL to use the same
7360 * the same block memory as used for the \p sourcedigraph */
7361 )
7362 {
7363 int ncomponents;
7364 int nnodes;
7365 int i;
7366 SCIP_Bool articulationscheck;
7367
7368 assert(sourcedigraph != NULL);
7369 assert(targetdigraph != NULL);
7370
7371 /* use the source digraph block memory if not specified otherwise */
7372 if( targetblkmem == NULL )
7373 targetblkmem = sourcedigraph->blkmem;
7374
7375 assert(targetblkmem != NULL);
7376
7377 SCIP_ALLOC( BMSallocBlockMemory(targetblkmem, targetdigraph) );
7378
7379 nnodes = sourcedigraph->nnodes;
7380 ncomponents = sourcedigraph->ncomponents;
7381 articulationscheck = sourcedigraph->articulationscheck;
7382 (*targetdigraph)->nnodes = nnodes;
7383 (*targetdigraph)->ncomponents = ncomponents;
7384 (*targetdigraph)->blkmem = targetblkmem;
7385
7386 /* copy arcs and data */
7387 SCIP_ALLOC( BMSallocClearBlockMemoryArray(targetblkmem, &(*targetdigraph)->successors, nnodes) );
7388 SCIP_ALLOC( BMSallocClearBlockMemoryArray(targetblkmem, &(*targetdigraph)->arcdata, nnodes) );
7389 SCIP_ALLOC( BMSallocClearBlockMemoryArray(targetblkmem, &(*targetdigraph)->nodedata, nnodes) );
7390
7391 /* copy lists of successors and arc data */
7392 for( i = 0; i < nnodes; ++i )
7393 {
7394 if( sourcedigraph->nsuccessors[i] > 0 )
7395 {
7396 assert(sourcedigraph->successors[i] != NULL);
7397 assert(sourcedigraph->arcdata[i] != NULL);
7398
7399 SCIP_ALLOC( BMSduplicateBlockMemoryArray(targetblkmem, &((*targetdigraph)->successors[i]),
7400 sourcedigraph->successors[i], sourcedigraph->nsuccessors[i]) ); /*lint !e866*/
7401 SCIP_ALLOC( BMSduplicateBlockMemoryArray(targetblkmem, &((*targetdigraph)->arcdata[i]),
7402 sourcedigraph->arcdata[i], sourcedigraph->nsuccessors[i]) ); /*lint !e866*/
7403 }
7404 /* copy node data - careful if these are pointers to some information -> need to be copied by hand */
7405 (*targetdigraph)->nodedata[i] = sourcedigraph->nodedata[i];
7406 }
7407
7408 /* use nsuccessors as size to save memory */
7409 SCIP_ALLOC( BMSduplicateBlockMemoryArray(targetblkmem, &(*targetdigraph)->successorssize, sourcedigraph->nsuccessors, nnodes) );
7410 SCIP_ALLOC( BMSduplicateBlockMemoryArray(targetblkmem, &(*targetdigraph)->nsuccessors, sourcedigraph->nsuccessors, nnodes) );
7411
7412 /* copy component data */
7413 if( ncomponents > 0 )
7414 {
7415 SCIP_ALLOC( BMSduplicateBlockMemoryArray(targetblkmem, &(*targetdigraph)->components, sourcedigraph->components,
7416 sourcedigraph->componentstarts[ncomponents]) );
7417 SCIP_ALLOC( BMSduplicateBlockMemoryArray(targetblkmem, &(*targetdigraph)->componentstarts,
7418 sourcedigraph->componentstarts,ncomponents + 1) ); /*lint !e776*/
7419 (*targetdigraph)->componentstartsize = ncomponents + 1;
7420 }
7421 else
7422 {
7423 (*targetdigraph)->components = NULL;
7424 (*targetdigraph)->componentstarts = NULL;
7425 (*targetdigraph)->componentstartsize = 0;
7426 }
7427
7428 /* copy the articulation point information if it has been computed and is up-to-date */
7429 if( articulationscheck )
7430 {
7431 SCIP_ALLOC( BMSduplicateBlockMemoryArray(targetblkmem, &(*targetdigraph)->articulations, sourcedigraph->articulations, sourcedigraph->narticulations) );
7432 (*targetdigraph)->narticulations = sourcedigraph->narticulations;
7433 (*targetdigraph)->articulationscheck = TRUE;
7434 }
7435 else
7436 {
7437 (*targetdigraph)->narticulations = -1;
7438 (*targetdigraph)->articulations = NULL;
7439 (*targetdigraph)->articulationscheck = FALSE;
7440 }
7441
7442 return SCIP_OKAY;
7443 }
7444
7445 /** sets the sizes of the successor lists for the nodes in a directed graph and allocates memory for the lists */
SCIPdigraphSetSizes(SCIP_DIGRAPH * digraph,int * sizes)7446 SCIP_RETCODE SCIPdigraphSetSizes(
7447 SCIP_DIGRAPH* digraph, /**< directed graph */
7448 int* sizes /**< sizes of the successor lists */
7449 )
7450 {
7451 int i;
7452 BMS_BLKMEM* blkmem;
7453
7454 assert(digraph != NULL);
7455 assert(digraph->nnodes > 0);
7456 blkmem = digraph->blkmem;
7457
7458 for( i = 0; i < digraph->nnodes; ++i )
7459 {
7460 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &digraph->successors[i], sizes[i]) ); /*lint !e866*/
7461 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &digraph->arcdata[i], sizes[i]) ); /*lint !e866*/
7462 digraph->successorssize[i] = sizes[i];
7463 digraph->nsuccessors[i] = 0;
7464 }
7465
7466 return SCIP_OKAY;
7467 }
7468
7469 /** frees given directed graph structure */
SCIPdigraphFree(SCIP_DIGRAPH ** digraph)7470 void SCIPdigraphFree(
7471 SCIP_DIGRAPH** digraph /**< pointer to the directed graph */
7472 )
7473 {
7474 int i;
7475 BMS_BLKMEM* blkmem;
7476 SCIP_DIGRAPH* digraphptr;
7477
7478 assert(digraph != NULL);
7479 assert(*digraph != NULL);
7480 assert((*digraph)->blkmem != NULL);
7481
7482 blkmem = (*digraph)->blkmem;
7483 digraphptr = *digraph;
7484
7485 /* free arrays storing the successor nodes and arc data */
7486 for( i = digraphptr->nnodes - 1; i >= 0; --i )
7487 {
7488 BMSfreeBlockMemoryArrayNull(blkmem, &digraphptr->successors[i], digraphptr->successorssize[i]);
7489 BMSfreeBlockMemoryArrayNull(blkmem, &digraphptr->arcdata[i], digraphptr->successorssize[i]);
7490 }
7491
7492 /* free components structure */
7493 SCIPdigraphFreeComponents(digraphptr);
7494 assert(digraphptr->ncomponents == 0);
7495 assert(digraphptr->componentstartsize == 0);
7496 assert(digraphptr->components == NULL);
7497 assert(digraphptr->componentstarts == NULL);
7498
7499 /* free the articulation points structure if it has been computed*/
7500 if( digraphptr->articulationscheck )
7501 BMSfreeBlockMemoryArray(blkmem, &digraphptr->articulations, digraphptr->narticulations);
7502
7503 /* free directed graph data structure */
7504 BMSfreeBlockMemoryArray(blkmem, &digraphptr->nodedata, digraphptr->nnodes);
7505 BMSfreeBlockMemoryArray(blkmem, &digraphptr->successorssize, digraphptr->nnodes);
7506 BMSfreeBlockMemoryArray(blkmem, &digraphptr->nsuccessors, digraphptr->nnodes);
7507 BMSfreeBlockMemoryArray(blkmem, &digraphptr->successors, digraphptr->nnodes);
7508 BMSfreeBlockMemoryArray(blkmem, &digraphptr->arcdata, digraphptr->nnodes);
7509
7510 BMSfreeBlockMemory(blkmem, digraph);
7511 }
7512
7513 #define STARTSUCCESSORSSIZE 5
7514
7515 /** ensures that successors array of one node in a directed graph is big enough */
7516 static
ensureSuccessorsSize(SCIP_DIGRAPH * digraph,int idx,int newsize)7517 SCIP_RETCODE ensureSuccessorsSize(
7518 SCIP_DIGRAPH* digraph, /**< directed graph */
7519 int idx, /**< index for which the size is ensured */
7520 int newsize /**< needed size */
7521 )
7522 {
7523 BMS_BLKMEM* blkmem;
7524
7525 assert(digraph != NULL);
7526 assert(digraph->blkmem != NULL);
7527 assert(idx >= 0);
7528 assert(idx < digraph->nnodes);
7529 assert(newsize > 0);
7530 assert(digraph->successorssize[idx] == 0 || digraph->successors[idx] != NULL);
7531 assert(digraph->successorssize[idx] == 0 || digraph->arcdata[idx] != NULL);
7532
7533 blkmem = digraph->blkmem;
7534
7535 /* check whether array is big enough, and realloc, if needed */
7536 if( newsize > digraph->successorssize[idx] )
7537 {
7538 if( digraph->successors[idx] == NULL )
7539 {
7540 assert(digraph->arcdata[idx] == NULL);
7541 digraph->successorssize[idx] = STARTSUCCESSORSSIZE;
7542 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &digraph->successors[idx], digraph->successorssize[idx]) ); /*lint !e866*/
7543 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &digraph->arcdata[idx], digraph->successorssize[idx]) ); /*lint !e866*/
7544 }
7545 else
7546 {
7547 newsize = MAX(newsize, 2 * digraph->successorssize[idx]);
7548 assert(digraph->arcdata[idx] != NULL);
7549 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &digraph->successors[idx], digraph->successorssize[idx], newsize) ); /*lint !e866*/
7550 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &digraph->arcdata[idx], digraph->successorssize[idx], newsize) ); /*lint !e866*/
7551 digraph->successorssize[idx] = newsize;
7552 }
7553 }
7554
7555 assert(newsize <= digraph->successorssize[idx]);
7556
7557 return SCIP_OKAY;
7558 }
7559
7560 /** add (directed) arc and a related data to the directed graph structure
7561 *
7562 * @note if the arc is already contained, it is added a second time
7563 */
SCIPdigraphAddArc(SCIP_DIGRAPH * digraph,int startnode,int endnode,void * data)7564 SCIP_RETCODE SCIPdigraphAddArc(
7565 SCIP_DIGRAPH* digraph, /**< directed graph */
7566 int startnode, /**< start node of the arc */
7567 int endnode, /**< start node of the arc */
7568 void* data /**< data that should be stored for the arc; or NULL */
7569 )
7570 {
7571 assert(digraph != NULL);
7572 assert(startnode >= 0);
7573 assert(endnode >= 0);
7574 assert(startnode < digraph->nnodes);
7575 assert(endnode < digraph->nnodes);
7576
7577 SCIP_CALL( ensureSuccessorsSize(digraph, startnode, digraph->nsuccessors[startnode] + 1) );
7578
7579 /* add arc */
7580 digraph->successors[startnode][digraph->nsuccessors[startnode]] = endnode;
7581 digraph->arcdata[startnode][digraph->nsuccessors[startnode]] = data;
7582 digraph->nsuccessors[startnode]++;
7583
7584 /* the articulation points are not up-to-date */
7585 digraph->articulationscheck = FALSE;
7586
7587 return SCIP_OKAY;
7588 }
7589
7590 /** add (directed) arc to the directed graph structure, if it is not contained, yet
7591 *
7592 * @note if there already exists an arc from startnode to endnode, the new arc is not added,
7593 * even if its data is different
7594 */
SCIPdigraphAddArcSafe(SCIP_DIGRAPH * digraph,int startnode,int endnode,void * data)7595 SCIP_RETCODE SCIPdigraphAddArcSafe(
7596 SCIP_DIGRAPH* digraph, /**< directed graph */
7597 int startnode, /**< start node of the arc */
7598 int endnode, /**< start node of the arc */
7599 void* data /**< data that should be stored for the arc; or NULL */
7600 )
7601 {
7602 int nsuccessors;
7603 int i;
7604
7605 assert(digraph != NULL);
7606 assert(startnode >= 0);
7607 assert(endnode >= 0);
7608 assert(startnode < digraph->nnodes);
7609 assert(endnode < digraph->nnodes);
7610
7611 nsuccessors = digraph->nsuccessors[startnode];
7612
7613 /* search for the arc in existing arcs */
7614 for( i = 0; i < nsuccessors; ++i )
7615 if( digraph->successors[startnode][i] == endnode )
7616 return SCIP_OKAY;
7617
7618 SCIP_CALL( ensureSuccessorsSize(digraph, startnode, nsuccessors + 1) );
7619
7620 /* add arc */
7621 digraph->successors[startnode][nsuccessors] = endnode;
7622 digraph->arcdata[startnode][nsuccessors] = data;
7623 ++(digraph->nsuccessors[startnode]);
7624
7625 /* the articulation points are not up-to-date */
7626 digraph->articulationscheck = FALSE;
7627
7628 return SCIP_OKAY;
7629 }
7630
7631 /** sets the number of successors to a given value */
SCIPdigraphSetNSuccessors(SCIP_DIGRAPH * digraph,int node,int nsuccessors)7632 SCIP_RETCODE SCIPdigraphSetNSuccessors(
7633 SCIP_DIGRAPH* digraph, /**< directed graph */
7634 int node, /**< node for which the number of successors has to be changed */
7635 int nsuccessors /**< new number of successors */
7636 )
7637 {
7638 assert(digraph != NULL);
7639 assert(node >= 0);
7640 assert(node < digraph->nnodes);
7641
7642 digraph->nsuccessors[node] = nsuccessors;
7643
7644 return SCIP_OKAY;
7645 }
7646
7647 /** returns the number of nodes of the given digraph */
SCIPdigraphGetNNodes(SCIP_DIGRAPH * digraph)7648 int SCIPdigraphGetNNodes(
7649 SCIP_DIGRAPH* digraph /**< directed graph */
7650 )
7651 {
7652 assert(digraph != NULL);
7653
7654 return digraph->nnodes;
7655 }
7656
7657 /** returns the node data, or NULL if no data exist */
SCIPdigraphGetNodeData(SCIP_DIGRAPH * digraph,int node)7658 void* SCIPdigraphGetNodeData(
7659 SCIP_DIGRAPH* digraph, /**< directed graph */
7660 int node /**< node for which the node data is returned */
7661 )
7662 {
7663 assert(digraph != NULL);
7664 assert(node >= 0);
7665 assert(node < digraph->nnodes);
7666
7667 return digraph->nodedata[node];
7668 }
7669
7670 /** sets the node data
7671 *
7672 * @note The old user pointer is not freed. This has to be done by the user
7673 */
SCIPdigraphSetNodeData(SCIP_DIGRAPH * digraph,void * dataptr,int node)7674 void SCIPdigraphSetNodeData(
7675 SCIP_DIGRAPH* digraph, /**< directed graph */
7676 void* dataptr, /**< user node data pointer, or NULL */
7677 int node /**< node for which the node data is returned */
7678 )
7679 {
7680 assert(digraph != NULL);
7681 assert(node >= 0);
7682 assert(node < digraph->nnodes);
7683
7684 digraph->nodedata[node] = dataptr;
7685 }
7686
7687 /** returns the total number of arcs in the given digraph */
SCIPdigraphGetNArcs(SCIP_DIGRAPH * digraph)7688 int SCIPdigraphGetNArcs(
7689 SCIP_DIGRAPH* digraph /**< directed graph */
7690 )
7691 {
7692 int i;
7693 int narcs;
7694
7695 assert(digraph != NULL);
7696
7697 /* count number of arcs */
7698 narcs = 0;
7699 for( i = 0; i < digraph->nnodes; ++i )
7700 narcs += digraph->nsuccessors[i];
7701
7702 return narcs;
7703 }
7704
7705 /** returns the number of successor nodes of the given node */
SCIPdigraphGetNSuccessors(SCIP_DIGRAPH * digraph,int node)7706 int SCIPdigraphGetNSuccessors(
7707 SCIP_DIGRAPH* digraph, /**< directed graph */
7708 int node /**< node for which the number of outgoing arcs is returned */
7709 )
7710 {
7711 assert(digraph != NULL);
7712 assert(node >= 0);
7713 assert(node < digraph->nnodes);
7714 assert(digraph->nsuccessors[node] >= 0);
7715 assert(digraph->nsuccessors[node] <= digraph->successorssize[node]);
7716
7717 return digraph->nsuccessors[node];
7718 }
7719
7720 /** returns the array of indices of the successor nodes; this array must not be changed from outside */
SCIPdigraphGetSuccessors(SCIP_DIGRAPH * digraph,int node)7721 int* SCIPdigraphGetSuccessors(
7722 SCIP_DIGRAPH* digraph, /**< directed graph */
7723 int node /**< node for which the array of outgoing arcs is returned */
7724 )
7725 {
7726 assert(digraph != NULL);
7727 assert(node >= 0);
7728 assert(node < digraph->nnodes);
7729 assert(digraph->nsuccessors[node] >= 0);
7730 assert(digraph->nsuccessors[node] <= digraph->successorssize[node]);
7731 assert((digraph->nsuccessors[node] == 0) || (digraph->successors[node] != NULL));
7732
7733 return digraph->successors[node];
7734 }
7735
7736 /** returns the array of data corresponding to the arcs originating at the given node, or NULL if no data exist; this
7737 * array must not be changed from outside
7738 */
SCIPdigraphGetSuccessorsData(SCIP_DIGRAPH * digraph,int node)7739 void** SCIPdigraphGetSuccessorsData(
7740 SCIP_DIGRAPH* digraph, /**< directed graph */
7741 int node /**< node for which the data corresponding to the outgoing arcs is returned */
7742 )
7743 {
7744 assert(digraph != NULL);
7745 assert(node >= 0);
7746 assert(node < digraph->nnodes);
7747 assert(digraph->nsuccessors[node] >= 0);
7748 assert(digraph->nsuccessors[node] <= digraph->successorssize[node]);
7749 assert(digraph->arcdata != NULL);
7750
7751 return digraph->arcdata[node];
7752 }
7753
7754 /** performs depth-first-search in the given directed graph from the given start node */
7755 static
depthFirstSearch(SCIP_DIGRAPH * digraph,int startnode,SCIP_Bool * visited,int * dfsstack,int * stackadjvisited,int * dfsnodes,int * ndfsnodes)7756 void depthFirstSearch(
7757 SCIP_DIGRAPH* digraph, /**< directed graph */
7758 int startnode, /**< node to start the depth-first-search */
7759 SCIP_Bool* visited, /**< array to store for each node, whether it was already visited */
7760 int* dfsstack, /**< array of size number of nodes to store the stack;
7761 * only needed for performance reasons */
7762 int* stackadjvisited, /**< array of size number of nodes to store the number of adjacent nodes already visited
7763 * for each node on the stack; only needed for performance reasons */
7764 int* dfsnodes, /**< array of nodes that can be reached starting at startnode, in reverse dfs order */
7765 int* ndfsnodes /**< pointer to store number of nodes that can be reached starting at startnode */
7766 )
7767 {
7768 int stackidx;
7769
7770 assert(digraph != NULL);
7771 assert(startnode >= 0);
7772 assert(startnode < digraph->nnodes);
7773 assert(visited != NULL);
7774 assert(visited[startnode] == FALSE);
7775 assert(dfsstack != NULL);
7776 assert(dfsnodes != NULL);
7777 assert(ndfsnodes != NULL);
7778
7779 /* put start node on the stack */
7780 dfsstack[0] = startnode;
7781 stackadjvisited[0] = 0;
7782 stackidx = 0;
7783
7784 while( stackidx >= 0 )
7785 {
7786 int currnode;
7787 int sadv;
7788
7789 /* get next node from stack */
7790 currnode = dfsstack[stackidx];
7791
7792 sadv = stackadjvisited[stackidx];
7793 assert( 0 <= sadv && sadv <= digraph->nsuccessors[currnode] );
7794
7795 /* mark current node as visited */
7796 assert( visited[currnode] == (sadv > 0) );
7797 visited[currnode] = TRUE;
7798
7799 /* iterate through the successor list until we reach unhandled node */
7800 while( sadv < digraph->nsuccessors[currnode] && visited[digraph->successors[currnode][sadv]] )
7801 ++sadv;
7802
7803 /* the current node was completely handled, remove it from stack */
7804 if( sadv == digraph->nsuccessors[currnode] )
7805 {
7806 --stackidx;
7807
7808 /* store node in the sorted nodes array */
7809 dfsnodes[(*ndfsnodes)++] = currnode;
7810 }
7811 /* handle next unhandled successor node */
7812 else
7813 {
7814 assert( ! visited[digraph->successors[currnode][sadv]] );
7815
7816 /* store current stackadjvisted index */
7817 stackadjvisited[stackidx] = sadv + 1;
7818
7819 /* put the successor node onto the stack */
7820 ++stackidx;
7821 dfsstack[stackidx] = digraph->successors[currnode][sadv];
7822 stackadjvisited[stackidx] = 0;
7823 assert( stackidx < digraph->nnodes );
7824 }
7825 }
7826 }
7827
7828 /** checks for articulation points in a given directed graph through a recursive depth-first-search.
7829 * starts from a given start node and keeps track of the nodes' discovery time in search for back edges.
7830 *
7831 * @note an articulation point is a node whose removal disconnects a connected graph or increases
7832 * the number of connected components in a disconnected graph
7833 */
7834 static
findArticulationPointsUtil(SCIP_DIGRAPH * digraph,int startnode,SCIP_Bool * visited,int * tdisc,int * mindisc,int * parent,SCIP_Bool * articulationflag,int time)7835 void findArticulationPointsUtil(
7836 SCIP_DIGRAPH* digraph, /**< directed graph */
7837 int startnode, /**< node to start the depth-first-search */
7838 SCIP_Bool* visited, /**< array to store for each node, whether it was already visited */
7839 int* tdisc, /**< array of size number of nodes to store each node's discovery time */
7840 int* mindisc, /**< array of size number of nodes to store the discovery time of the earliest discovered vertex
7841 * to which startnode (or any node in the subtree rooted at it) is having a back edge */
7842 int* parent, /**< array to store the parent of each node in the DFS tree */
7843 SCIP_Bool* articulationflag, /**< array to mark whether a node is identified as an articulation point */
7844 int time /**< current discovery time in the DFS */
7845 )
7846 {
7847 int n;
7848 int nchildren = 0;
7849 int nsucc;
7850 int* succnodes;
7851
7852 assert(digraph != NULL);
7853 assert(startnode >= 0);
7854 assert(startnode < digraph->nnodes);
7855 assert(visited != NULL);
7856 assert(visited[startnode] == FALSE);
7857 assert(tdisc != NULL);
7858 assert(mindisc != NULL);
7859 assert(parent != NULL);
7860 assert(articulationflag != NULL);
7861 assert(time >= 0);
7862
7863 nsucc = (int) SCIPdigraphGetNSuccessors(digraph, startnode);
7864 succnodes = (int*) SCIPdigraphGetSuccessors(digraph, startnode);
7865 visited[startnode] = TRUE;
7866 tdisc[startnode] = time + 1;
7867 mindisc[startnode] = time + 1;
7868
7869 /* process all the adjacent nodes to startnode */
7870 for( n = 0; n < nsucc; ++n)
7871 {
7872 if( !visited[succnodes[n]] )
7873 {
7874 parent[succnodes[n]] = startnode;
7875 ++nchildren;
7876 findArticulationPointsUtil(digraph, succnodes[n], visited, tdisc, mindisc, parent, articulationflag, time + 1);
7877 /* updated the mindisc of startnode when the DFS concludes for node n*/
7878 mindisc[startnode] = MIN(mindisc[startnode], mindisc[succnodes[n]]);
7879
7880 /* the root is an articulation point if it has more than 2 children*/
7881 if( parent[startnode] == -1 && nchildren > 1 )
7882 articulationflag[startnode] = TRUE;
7883 /* a vertex startnode is an articulation point if it is not the root and
7884 * there is no back edge from the subtree rooted at child n to any of the ancestors of startnode */
7885 if( parent[startnode] > -1 && mindisc[succnodes[n]] >= tdisc[startnode] )
7886 articulationflag[startnode] = TRUE;
7887 }
7888 else
7889 {
7890 if( parent[startnode] != succnodes[n] )
7891 mindisc[startnode] = MIN(mindisc[startnode], tdisc[succnodes[n]]);
7892 }
7893 }
7894
7895 if( articulationflag[startnode] )
7896 ++digraph->narticulations;
7897 }
7898
7899 /** identifies the articulation points in a given directed graph
7900 * uses the helper recursive function findArticulationPointsUtil
7901 */
SCIPdigraphGetArticulationPoints(SCIP_DIGRAPH * digraph,int ** articulations,int * narticulations)7902 SCIP_RETCODE SCIPdigraphGetArticulationPoints(
7903 SCIP_DIGRAPH* digraph, /**< directed graph */
7904 int** articulations, /**< array to store the sorted node indices of the computed articulation points, or NULL */
7905 int* narticulations /**< number of the computed articulation points, or NULL */
7906 )
7907 {
7908 SCIP_RETCODE retcode = SCIP_OKAY;
7909 BMS_BLKMEM* blkmem;
7910 SCIP_Bool* visited = NULL;
7911 SCIP_Bool* articulationflag = NULL;
7912 int* tdisc = NULL;
7913 int* mindisc = NULL;
7914 int* parent = NULL;
7915 int n;
7916 int articulationidx = 0;
7917 int time = 0;
7918
7919 assert(digraph != NULL);
7920 assert(digraph->nnodes > 0);
7921
7922 /* Only perform the computation if the articulation points are NOT up-to-date */
7923 if( !digraph->articulationscheck )
7924 {
7925 SCIP_ALLOC_TERMINATE( retcode, BMSallocMemoryArray(&visited, digraph->nnodes), TERMINATE );
7926 SCIP_ALLOC_TERMINATE( retcode, BMSallocMemoryArray(&tdisc, digraph->nnodes), TERMINATE );
7927 SCIP_ALLOC_TERMINATE( retcode, BMSallocMemoryArray(&mindisc, digraph->nnodes), TERMINATE );
7928 SCIP_ALLOC_TERMINATE( retcode, BMSallocMemoryArray(&parent, digraph->nnodes), TERMINATE );
7929 SCIP_ALLOC_TERMINATE( retcode, BMSallocMemoryArray(&articulationflag, digraph->nnodes), TERMINATE );
7930
7931 assert(digraph->blkmem != NULL);
7932 blkmem = digraph->blkmem;
7933
7934 if( digraph->narticulations >= 0 ) /* case: articulations have already been computed but not up-to-date */
7935 BMSfreeBlockMemoryArray(blkmem, &digraph->articulations, digraph->narticulations);
7936
7937 /* Initialize the no. of articulation points ahead of the recursive computation */
7938 digraph->narticulations = 0;
7939
7940 for( n = 0; n < digraph->nnodes; ++n )
7941 {
7942 visited[n] = FALSE;
7943 parent[n] = -1;
7944 articulationflag[n] = FALSE;
7945 }
7946
7947 /* the function is called on every unvisited node in the graph to cover the disconnected graph case */
7948 for( n = 0; n < digraph->nnodes; ++n )
7949 {
7950 if( !visited[n] )
7951 findArticulationPointsUtil(digraph, n, visited, tdisc, mindisc, parent, articulationflag, time);
7952 }
7953
7954 /* allocation of the block memory for the node indices of the articulation points*/
7955 SCIP_ALLOC_TERMINATE( retcode, BMSallocBlockMemoryArray(blkmem, &digraph->articulations, digraph->narticulations), TERMINATE );
7956
7957 for( n = 0; n < digraph->nnodes; ++n )
7958 {
7959 if( articulationflag[n] )
7960 {
7961 digraph->articulations[articulationidx] = n;
7962 ++articulationidx;
7963 }
7964 }
7965 }
7966
7967 if( articulations != NULL )
7968 (*articulations) = digraph->articulations;
7969 if( narticulations != NULL )
7970 (*narticulations) = digraph->narticulations;
7971
7972 /* the articulation points are now up-to-date */
7973 digraph->articulationscheck = TRUE;
7974
7975 /* cppcheck-suppress unusedLabel */
7976 TERMINATE:
7977 BMSfreeMemoryArrayNull(&articulationflag);
7978 BMSfreeMemoryArrayNull(&parent);
7979 BMSfreeMemoryArrayNull(&mindisc);
7980 BMSfreeMemoryArrayNull(&tdisc);
7981 BMSfreeMemoryArrayNull(&visited);
7982
7983 return retcode;
7984 }
7985
7986 /** Compute undirected connected components on the given graph.
7987 *
7988 * @note For each arc, its reverse is added, so the graph does not need to be the directed representation of an
7989 * undirected graph.
7990 */
SCIPdigraphComputeUndirectedComponents(SCIP_DIGRAPH * digraph,int minsize,int * components,int * ncomponents)7991 SCIP_RETCODE SCIPdigraphComputeUndirectedComponents(
7992 SCIP_DIGRAPH* digraph, /**< directed graph */
7993 int minsize, /**< all components with less nodes are ignored */
7994 int* components, /**< array with as many slots as there are nodes in the directed graph
7995 * to store for each node the component to which it belongs
7996 * (components are numbered 0 to ncomponents - 1); or NULL, if components
7997 * are accessed one-by-one using SCIPdigraphGetComponent() */
7998 int* ncomponents /**< pointer to store the number of components; or NULL, if the
7999 * number of components is accessed by SCIPdigraphGetNComponents() */
8000 )
8001 {
8002 BMS_BLKMEM* blkmem;
8003 SCIP_Bool* visited;
8004 int* ndirectedsuccessors;
8005 int* stackadjvisited;
8006 int* dfsstack;
8007 int ndfsnodes;
8008 int compstart;
8009 int v;
8010 int i;
8011 int j;
8012
8013 SCIP_RETCODE retcode = SCIP_OKAY;
8014
8015 assert(digraph != NULL);
8016 assert(digraph->nnodes > 0);
8017 assert(digraph->blkmem != NULL);
8018
8019 blkmem = digraph->blkmem;
8020
8021 /* first free the old components */
8022 if( digraph->ncomponents > 0 )
8023 {
8024 SCIPdigraphFreeComponents(digraph);
8025 }
8026
8027 digraph->ncomponents = 0;
8028 digraph->componentstartsize = 10;
8029
8030 /* storage to hold components is stored in block memory */
8031 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &digraph->components, digraph->nnodes) );
8032 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &digraph->componentstarts, digraph->componentstartsize) );
8033
8034 /* allocate temporary arrays */
8035 SCIP_ALLOC_TERMINATE( retcode, BMSallocClearMemoryArray(&visited, digraph->nnodes), TERMINATE );
8036 SCIP_ALLOC_TERMINATE( retcode, BMSallocMemoryArray(&dfsstack, digraph->nnodes), TERMINATE );
8037 SCIP_ALLOC_TERMINATE( retcode, BMSallocMemoryArray(&stackadjvisited, digraph->nnodes), TERMINATE );
8038 SCIP_ALLOC_TERMINATE( retcode, BMSallocMemoryArray(&ndirectedsuccessors, digraph->nnodes), TERMINATE );
8039
8040 digraph->componentstarts[0] = 0;
8041
8042 /* store the number of directed arcs per node */
8043 BMScopyMemoryArray(ndirectedsuccessors, digraph->nsuccessors, digraph->nnodes);
8044
8045 /* add reverse arcs to the graph */
8046 for( i = digraph->nnodes - 1; i >= 0; --i )
8047 {
8048 for( j = 0; j < ndirectedsuccessors[i]; ++j )
8049 {
8050 SCIP_CALL_TERMINATE( retcode, SCIPdigraphAddArc(digraph, digraph->successors[i][j], i, NULL), TERMINATE );
8051 }
8052 }
8053
8054 for( v = 0; v < digraph->nnodes; ++v )
8055 {
8056 if( visited[v] )
8057 continue;
8058
8059 compstart = digraph->componentstarts[digraph->ncomponents];
8060 ndfsnodes = 0;
8061 depthFirstSearch(digraph, v, visited, dfsstack, stackadjvisited,
8062 &digraph->components[compstart], &ndfsnodes);
8063
8064 /* forget about this component if it is too small */
8065 if( ndfsnodes >= minsize )
8066 {
8067 digraph->ncomponents++;
8068
8069 /* enlarge componentstartsize array, if needed */
8070 if( digraph->ncomponents >= digraph->componentstartsize )
8071 {
8072 int newsize;
8073
8074 newsize = 2 * digraph->componentstartsize;
8075 assert(digraph->ncomponents < newsize);
8076
8077 SCIP_ALLOC_TERMINATE( retcode, BMSreallocBlockMemoryArray(blkmem, &digraph->componentstarts, digraph->componentstartsize, newsize), TERMINATE );
8078 digraph->componentstartsize = newsize;
8079 }
8080 digraph->componentstarts[digraph->ncomponents] = compstart + ndfsnodes;
8081
8082 /* store component number for contained nodes if array was given */
8083 if( components != NULL )
8084 {
8085 for( i = digraph->componentstarts[digraph->ncomponents] - 1; i >= compstart; --i )
8086 {
8087 components[digraph->components[i]] = digraph->ncomponents - 1;
8088 }
8089 }
8090 }
8091 }
8092
8093 /* restore the number of directed arcs per node */
8094 BMScopyMemoryArray(digraph->nsuccessors, ndirectedsuccessors, digraph->nnodes);
8095 BMSclearMemoryArray(visited, digraph->nnodes);
8096
8097 /* return number of components, if the pointer was given */
8098 if( ncomponents != NULL )
8099 (*ncomponents) = digraph->ncomponents;
8100
8101 TERMINATE:
8102 if( retcode != SCIP_OKAY )
8103 {
8104 SCIPdigraphFreeComponents(digraph);
8105 }
8106 BMSfreeMemoryArrayNull(&ndirectedsuccessors);
8107 BMSfreeMemoryArrayNull(&stackadjvisited);
8108 BMSfreeMemoryArrayNull(&dfsstack);
8109 BMSfreeMemoryArrayNull(&visited);
8110
8111 return retcode;
8112 }
8113
8114 /** Performs an (almost) topological sort on the undirected components of the given directed graph. The undirected
8115 * components should be computed before using SCIPdigraphComputeUndirectedComponents().
8116 *
8117 * @note In general a topological sort is not unique. Note, that there might be directed cycles, that are randomly
8118 * broken, which is the reason for having only almost topologically sorted arrays.
8119 */
SCIPdigraphTopoSortComponents(SCIP_DIGRAPH * digraph)8120 SCIP_RETCODE SCIPdigraphTopoSortComponents(
8121 SCIP_DIGRAPH* digraph /**< directed graph */
8122 )
8123 {
8124 SCIP_Bool* visited = NULL;
8125 int* comps;
8126 int* compstarts;
8127 int* stackadjvisited = NULL;
8128 int* dfsstack = NULL;
8129 int* dfsnodes = NULL;
8130 int ndfsnodes;
8131 int ncomps;
8132 int i;
8133 int j;
8134 int k;
8135 int endidx;
8136 SCIP_RETCODE retcode = SCIP_OKAY;
8137
8138 assert(digraph != NULL);
8139
8140 ncomps = digraph->ncomponents;
8141 comps = digraph->components;
8142 compstarts = digraph->componentstarts;
8143
8144 SCIP_ALLOC_TERMINATE( retcode, BMSallocClearMemoryArray(&visited, digraph->nnodes), TERMINATE );
8145 SCIP_ALLOC_TERMINATE( retcode, BMSallocMemoryArray(&dfsnodes, digraph->nnodes), TERMINATE );
8146 SCIP_ALLOC_TERMINATE( retcode, BMSallocMemoryArray(&dfsstack, digraph->nnodes), TERMINATE );
8147 SCIP_ALLOC_TERMINATE( retcode, BMSallocMemoryArray(&stackadjvisited, digraph->nnodes), TERMINATE );
8148
8149 /* sort the components (almost) topologically */
8150 for( i = 0; i < ncomps; ++i )
8151 {
8152 endidx = compstarts[i+1] - 1;
8153 ndfsnodes = 0;
8154 for( j = compstarts[i]; j < compstarts[i+1]; ++j )
8155 {
8156 if( visited[comps[j]] )
8157 continue;
8158
8159 /* perform depth first search, nodes visited in this call are appended to the list dfsnodes in reverse
8160 * dfs order, after the nodes already contained;
8161 * so at every point in time, the nodes in dfsnode are in reverse (almost) topological order
8162 */
8163 depthFirstSearch(digraph, comps[j], visited, dfsstack, stackadjvisited, dfsnodes, &ndfsnodes);
8164 }
8165 assert(endidx - ndfsnodes == compstarts[i] - 1);
8166
8167 /* copy reverse (almost) topologically sorted array of nodes reached by the dfs searches;
8168 * reverse their order to get an (almost) topologically sort
8169 */
8170 for( k = 0; k < ndfsnodes; ++k )
8171 {
8172 digraph->components[endidx - k] = dfsnodes[k];
8173 }
8174 }
8175
8176 TERMINATE:
8177 BMSfreeMemoryArrayNull(&stackadjvisited);
8178 BMSfreeMemoryArrayNull(&dfsstack);
8179 BMSfreeMemoryArrayNull(&dfsnodes);
8180 BMSfreeMemoryArrayNull(&visited);
8181
8182 return retcode;
8183 }
8184
8185 /** returns the number of previously computed undirected components for the given directed graph */
SCIPdigraphGetNComponents(SCIP_DIGRAPH * digraph)8186 int SCIPdigraphGetNComponents(
8187 SCIP_DIGRAPH* digraph /**< directed graph */
8188 )
8189 {
8190 assert(digraph != NULL);
8191 assert(digraph->componentstartsize > 0); /* components should have been computed */
8192
8193 return digraph->ncomponents;
8194 }
8195
8196 /** Returns the previously computed undirected component of the given number for the given directed graph.
8197 * If the components were sorted using SCIPdigraphTopoSortComponents(), the component is (almost) topologically sorted.
8198 */
SCIPdigraphGetComponent(SCIP_DIGRAPH * digraph,int compidx,int ** nodes,int * nnodes)8199 void SCIPdigraphGetComponent(
8200 SCIP_DIGRAPH* digraph, /**< directed graph */
8201 int compidx, /**< number of the component to return */
8202 int** nodes, /**< pointer to store the nodes in the component; or NULL, if not needed */
8203 int* nnodes /**< pointer to store the number of nodes in the component;
8204 * or NULL, if not needed */
8205 )
8206 {
8207 assert(digraph != NULL);
8208 assert(compidx >= 0);
8209 assert(compidx < digraph->ncomponents);
8210 assert(nodes != NULL || nnodes != NULL);
8211
8212 if( nodes != NULL )
8213 (*nodes) = &(digraph->components[digraph->componentstarts[compidx]]);
8214 if( nnodes != NULL )
8215 (*nnodes) = digraph->componentstarts[compidx + 1] - digraph->componentstarts[compidx];
8216 }
8217
8218 /* Performs Tarjan's algorithm for a given directed graph to obtain the strongly connected components
8219 * which are reachable from a given node.
8220 */
8221 static
tarjan(SCIP_DIGRAPH * digraph,int v,int * lowlink,int * dfsidx,int * stack,int * stacksize,SCIP_Bool * unprocessed,SCIP_Bool * nodeinstack,int * maxdfs,int * strongcomponents,int * nstrongcomponents,int * strongcompstartidx,int * nstorednodes)8222 void tarjan(
8223 SCIP_DIGRAPH* digraph, /**< directed graph */
8224 int v, /**< node to start the algorithm */
8225 int* lowlink, /**< array to store lowlink values */
8226 int* dfsidx, /**< array to store dfs indices */
8227 int* stack, /**< array to store a stack */
8228 int* stacksize, /**< pointer to store the size of the stack */
8229 SCIP_Bool* unprocessed, /**< array to store which node is unprocessed yet */
8230 SCIP_Bool* nodeinstack, /**< array to store which nodes are in the stack */
8231 int* maxdfs, /**< pointer to store index for DFS */
8232 int* strongcomponents, /**< array to store for each node the strongly connected
8233 * component to which it belongs (components are
8234 * numbered 0 to nstrongcomponents - 1); */
8235 int* nstrongcomponents, /**< pointer to store the number of computed components so far */
8236 int* strongcompstartidx, /**< array to store the start index of the computed components */
8237 int* nstorednodes /**< pointer to store the number of already stored nodes */
8238 )
8239 {
8240 int i;
8241
8242 assert(digraph != NULL);
8243 assert(v >= 0);
8244 assert(v < digraph->nnodes);
8245 assert(lowlink != NULL);
8246 assert(dfsidx != NULL);
8247 assert(stack != NULL);
8248 assert(stacksize != NULL);
8249 assert(*stacksize >= 0);
8250 assert(*stacksize < digraph->nnodes);
8251 assert(unprocessed != NULL);
8252 assert(nodeinstack != NULL);
8253 assert(maxdfs != NULL);
8254 assert(strongcomponents != NULL);
8255 assert(nstrongcomponents != NULL);
8256 assert(strongcompstartidx != NULL);
8257 assert(nstorednodes != NULL);
8258 assert(*nstorednodes >= 0 && *nstorednodes < digraph->nnodes);
8259
8260 dfsidx[v] = *maxdfs;
8261 lowlink[v] = *maxdfs;
8262 *maxdfs += 1;
8263
8264 /* add v to the stack */
8265 stack[*stacksize] = v;
8266 *stacksize += 1;
8267 nodeinstack[v] = TRUE;
8268
8269 /* mark v as processed */
8270 unprocessed[v] = FALSE;
8271
8272 for( i = 0; i < digraph->nsuccessors[v]; ++i )
8273 {
8274 int w;
8275
8276 /* edge (v,w) */
8277 w = digraph->successors[v][i];
8278
8279 if( unprocessed[w] )
8280 {
8281 tarjan(digraph, w, lowlink, dfsidx, stack, stacksize, unprocessed, nodeinstack, maxdfs, strongcomponents,
8282 nstrongcomponents, strongcompstartidx, nstorednodes);
8283
8284 assert(lowlink[v] >= 0 && lowlink[v] < digraph->nnodes);
8285 assert(lowlink[w] >= 0 && lowlink[w] < digraph->nnodes);
8286
8287 /* update lowlink */
8288 lowlink[v] = MIN(lowlink[v], lowlink[w]);
8289 }
8290 else if( nodeinstack[w] )
8291 {
8292 assert(lowlink[v] >= 0 && lowlink[v] < digraph->nnodes);
8293 assert(dfsidx[w] >= 0 && dfsidx[w] < digraph->nnodes);
8294
8295 /* update lowlink */
8296 lowlink[v] = MIN(lowlink[v], dfsidx[w]);
8297 }
8298 }
8299
8300 /* found a root of a strong component */
8301 if( lowlink[v] == dfsidx[v] )
8302 {
8303 int w;
8304
8305 strongcompstartidx[*nstrongcomponents] = *nstorednodes;
8306 *nstrongcomponents += 1;
8307
8308 do
8309 {
8310 assert(*stacksize > 0);
8311
8312 /* stack.pop() */
8313 w = stack[*stacksize - 1];
8314 *stacksize -= 1;
8315 nodeinstack[w] = FALSE;
8316
8317 /* store the node in the corresponding component */
8318 strongcomponents[*nstorednodes] = w;
8319 *nstorednodes += 1;
8320 }
8321 while( v != w );
8322 }
8323 }
8324
8325 /** Computes all strongly connected components of an undirected connected component with Tarjan's Algorithm.
8326 * The resulting strongly connected components are sorted topologically (starting from the end of the
8327 * strongcomponents array).
8328 *
8329 * @note In general a topological sort of the strongly connected components is not unique.
8330 */
SCIPdigraphComputeDirectedComponents(SCIP_DIGRAPH * digraph,int compidx,int * strongcomponents,int * strongcompstartidx,int * nstrongcomponents)8331 SCIP_RETCODE SCIPdigraphComputeDirectedComponents(
8332 SCIP_DIGRAPH* digraph, /**< directed graph */
8333 int compidx, /**< number of the undirected connected component */
8334 int* strongcomponents, /**< array to store the strongly connected components
8335 * (length >= size of the component) */
8336 int* strongcompstartidx, /**< array to store the start indices of the strongly connected
8337 * components (length >= size of the component) */
8338 int* nstrongcomponents /**< pointer to store the number of strongly connected
8339 * components */
8340 )
8341 {
8342 int* lowlink;
8343 int* dfsidx;
8344 int* stack;
8345 int stacksize;
8346 SCIP_Bool* unprocessed;
8347 SCIP_Bool* nodeinstack;
8348 int maxdfs;
8349 int nstorednodes;
8350 int i;
8351 SCIP_RETCODE retcode;
8352
8353 assert(digraph != NULL);
8354 assert(compidx >= 0);
8355 assert(compidx < digraph->ncomponents);
8356 assert(strongcomponents != NULL);
8357 assert(strongcompstartidx != NULL);
8358 assert(nstrongcomponents != NULL);
8359
8360 retcode = SCIP_OKAY;
8361
8362 SCIP_ALLOC_TERMINATE( retcode, BMSallocMemoryArray(&lowlink, digraph->nnodes), TERMINATE );
8363 SCIP_ALLOC_TERMINATE( retcode, BMSallocMemoryArray(&dfsidx, digraph->nnodes), TERMINATE );
8364 SCIP_ALLOC_TERMINATE( retcode, BMSallocMemoryArray(&stack, digraph->nnodes), TERMINATE );
8365 SCIP_ALLOC_TERMINATE( retcode, BMSallocMemoryArray(&unprocessed, digraph->nnodes), TERMINATE );
8366 SCIP_ALLOC_TERMINATE( retcode, BMSallocMemoryArray(&nodeinstack, digraph->nnodes), TERMINATE );
8367
8368 for( i = 0; i < digraph->nnodes; ++i )
8369 {
8370 lowlink[i] = -1;
8371 dfsidx[i] = -1;
8372 stack[i] = -1;
8373 unprocessed[i] = TRUE;
8374 nodeinstack[i] = FALSE;
8375 }
8376
8377 nstorednodes = 0;
8378 stacksize = 0;
8379 maxdfs = 0;
8380 *nstrongcomponents = 0;
8381
8382 /* iterate over all nodes in the undirected connected component */
8383 for( i = digraph->componentstarts[compidx]; i < digraph->componentstarts[compidx + 1]; ++i )
8384 {
8385 int v;
8386
8387 v = digraph->components[i];
8388 assert(v >= 0 && v < digraph->nnodes);
8389
8390 /* call Tarjan's algorithm for unprocessed nodes */
8391 if( unprocessed[v] )
8392 {
8393 SCIPdebugMessage("apply Tarjan's algorithm for node %d\n", v);
8394 tarjan(digraph, v, lowlink, dfsidx, stack, &stacksize, unprocessed, nodeinstack, &maxdfs,
8395 strongcomponents, nstrongcomponents, strongcompstartidx, &nstorednodes);
8396 }
8397 }
8398
8399 /* we should have stored as many nodes as in the undirected connected component */
8400 assert(nstorednodes == digraph->componentstarts[compidx + 1] - digraph->componentstarts[compidx]);
8401
8402 /* to simplify the iteration over all strongly connected components */
8403 assert(*nstrongcomponents < digraph->nnodes + 1);
8404 strongcompstartidx[*nstrongcomponents] = nstorednodes;
8405
8406 assert(retcode == SCIP_OKAY);
8407
8408 TERMINATE:
8409 BMSfreeMemoryArrayNull(&lowlink);
8410 BMSfreeMemoryArrayNull(&dfsidx);
8411 BMSfreeMemoryArrayNull(&stack);
8412 BMSfreeMemoryArrayNull(&unprocessed);
8413 BMSfreeMemoryArrayNull(&nodeinstack);
8414
8415 return retcode;
8416 }
8417
8418 /** frees the component information for the given directed graph */
SCIPdigraphFreeComponents(SCIP_DIGRAPH * digraph)8419 void SCIPdigraphFreeComponents(
8420 SCIP_DIGRAPH* digraph /**< directed graph */
8421 )
8422 {
8423 BMS_BLKMEM* blkmem;
8424
8425 assert(digraph != NULL);
8426 assert(digraph->blkmem != NULL);
8427
8428 blkmem = digraph->blkmem;
8429
8430 /* free components structure */
8431 if( digraph->componentstartsize > 0 )
8432 {
8433 BMSfreeBlockMemoryArray(blkmem, &digraph->componentstarts, digraph->componentstartsize);
8434 BMSfreeBlockMemoryArray(blkmem, &digraph->components, digraph->nnodes);
8435 digraph->components = NULL;
8436 digraph->componentstarts = NULL;
8437 digraph->ncomponents = 0;
8438 digraph->componentstartsize = 0;
8439 }
8440 #ifndef NDEBUG
8441 else
8442 {
8443 assert(digraph->components == NULL);
8444 assert(digraph->componentstarts == NULL);
8445 assert(digraph->ncomponents == 0);
8446 }
8447 #endif
8448 }
8449
8450 /** output of the given directed graph via the given message handler */
SCIPdigraphPrint(SCIP_DIGRAPH * digraph,SCIP_MESSAGEHDLR * messagehdlr,FILE * file)8451 void SCIPdigraphPrint(
8452 SCIP_DIGRAPH* digraph, /**< directed graph */
8453 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8454 FILE* file /**< output file (or NULL for standard output) */
8455 )
8456 {
8457 int n;
8458
8459 for( n = 0; n < digraph->nnodes; ++n )
8460 {
8461 int* successors;
8462 int nsuccessors;
8463 int m;
8464
8465 nsuccessors = digraph->nsuccessors[n];
8466 successors = digraph->successors[n];
8467
8468 SCIPmessageFPrintInfo(messagehdlr, file, "node %d --> ", n);
8469
8470 for( m = 0; m < nsuccessors ; ++m )
8471 {
8472 if( m == 0 )
8473 {
8474 SCIPmessageFPrintInfo(messagehdlr, file, "%d", successors[m]);
8475 }
8476 else
8477 {
8478 SCIPmessageFPrintInfo(messagehdlr, file, ", %d", successors[m]);
8479 }
8480 }
8481 SCIPmessageFPrintInfo(messagehdlr, file, "\n");
8482 }
8483 }
8484
8485 /** prints the given directed graph structure in GML format into the given file */
SCIPdigraphPrintGml(SCIP_DIGRAPH * digraph,FILE * file)8486 void SCIPdigraphPrintGml(
8487 SCIP_DIGRAPH* digraph, /**< directed graph */
8488 FILE* file /**< file to write to */
8489 )
8490 {
8491 int n;
8492
8493 /* write GML format opening */
8494 SCIPgmlWriteOpening(file, TRUE);
8495
8496 /* write all nodes of the graph */
8497 for( n = 0; n < digraph->nnodes; ++n )
8498 {
8499 char label[SCIP_MAXSTRLEN];
8500
8501 (void)SCIPsnprintf(label, SCIP_MAXSTRLEN, "%d", n);
8502 SCIPgmlWriteNode(file, (unsigned int)n, label, "circle", NULL, NULL);
8503 }
8504
8505 /* write all edges */
8506 for( n = 0; n < digraph->nnodes; ++n )
8507 {
8508 int* successors;
8509 int nsuccessors;
8510 int m;
8511
8512 nsuccessors = digraph->nsuccessors[n];
8513 successors = digraph->successors[n];
8514
8515 for( m = 0; m < nsuccessors; ++m )
8516 {
8517 SCIPgmlWriteArc(file, (unsigned int)n, (unsigned int)successors[m], NULL, NULL);
8518 }
8519 }
8520 /* write GML format closing */
8521 SCIPgmlWriteClosing(file);
8522 }
8523
8524 /** output of the given directed graph via the given message handler */
SCIPdigraphPrintComponents(SCIP_DIGRAPH * digraph,SCIP_MESSAGEHDLR * messagehdlr,FILE * file)8525 void SCIPdigraphPrintComponents(
8526 SCIP_DIGRAPH* digraph, /**< directed graph */
8527 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8528 FILE* file /**< output file (or NULL for standard output) */
8529 )
8530 {
8531 int c;
8532 int i;
8533
8534 for( c = 0; c < digraph->ncomponents; ++c )
8535 {
8536 int start = digraph->componentstarts[c];
8537 int end = digraph->componentstarts[c+1];
8538
8539 SCIPmessageFPrintInfo(messagehdlr, file, "Components %d --> ", c);
8540
8541 for( i = start; i < end; ++i )
8542 {
8543 if( i == start )
8544 {
8545 SCIPmessageFPrintInfo(messagehdlr, file, "%d", digraph->components[i]);
8546 }
8547 else
8548 {
8549 SCIPmessageFPrintInfo(messagehdlr, file, ", %d", digraph->components[i]);
8550 }
8551 }
8552 SCIPmessageFPrintInfo(messagehdlr, file, "\n");
8553 }
8554 }
8555
8556 /*
8557 * Binary tree
8558 */
8559
8560 /** creates a node for a binary tree */
8561 static
btnodeCreateEmpty(SCIP_BT * tree,SCIP_BTNODE ** node)8562 SCIP_RETCODE btnodeCreateEmpty(
8563 SCIP_BT* tree, /**< binary tree */
8564 SCIP_BTNODE** node /**< pointer to store the created node */
8565 )
8566 {
8567 SCIP_ALLOC( BMSallocBlockMemory(tree->blkmem, node) );
8568
8569 (*node)->parent = NULL;
8570 (*node)->left = NULL;
8571 (*node)->right = NULL;
8572 (*node)->dataptr = NULL;
8573
8574 return SCIP_OKAY;
8575 }
8576
8577 /** creates a tree node with (optinal) user data */
SCIPbtnodeCreate(SCIP_BT * tree,SCIP_BTNODE ** node,void * dataptr)8578 SCIP_RETCODE SCIPbtnodeCreate(
8579 SCIP_BT* tree, /**< binary tree */
8580 SCIP_BTNODE** node, /**< pointer to store the created node */
8581 void* dataptr /**< user node data pointer, or NULL */
8582 )
8583 {
8584 assert(tree != NULL);
8585 assert(node != NULL);
8586
8587 SCIP_CALL( btnodeCreateEmpty(tree, node) );
8588
8589 assert((*node)->parent == NULL);
8590 assert((*node)->left == NULL);
8591 assert((*node)->right == NULL);
8592
8593 /* initialize user data */
8594 (*node)->dataptr = dataptr;
8595
8596 return SCIP_OKAY;
8597 }
8598
8599 /** frees a tree leaf */
8600 static
btnodeFreeLeaf(SCIP_BT * tree,SCIP_BTNODE ** node)8601 void btnodeFreeLeaf(
8602 SCIP_BT* tree, /**< binary tree */
8603 SCIP_BTNODE** node /**< pointer to node which has to be freed */
8604 )
8605 {
8606 assert(tree != NULL);
8607 assert(node != NULL);
8608 assert(*node != NULL);
8609
8610 assert((*node)->left == NULL);
8611 assert((*node)->right == NULL);
8612
8613 #if 0
8614 /* remove reference from parent node */
8615 if( (*node)->parent != NULL )
8616 {
8617 assert(*node != NULL);
8618
8619 assert((*node)->parent->left == *node || ((*node)->parent->right == *node));
8620
8621 if( (*node)->parent->left == *node )
8622 {
8623 (*node)->parent->left = NULL;
8624 }
8625 else
8626 {
8627 assert((*node)->parent->right == *node);
8628 (*node)->parent->right = NULL;
8629 }
8630 }
8631 #endif
8632
8633 assert(*node != NULL);
8634 BMSfreeBlockMemory(tree->blkmem, node);
8635 assert(*node == NULL);
8636 }
8637
8638 /** frees the node including the rooted subtree
8639 *
8640 * @note The user pointer (object) is not freed. If needed, it has to be done by the user.
8641 */
SCIPbtnodeFree(SCIP_BT * tree,SCIP_BTNODE ** node)8642 void SCIPbtnodeFree(
8643 SCIP_BT* tree, /**< binary tree */
8644 SCIP_BTNODE** node /**< node to be freed */
8645 )
8646 {
8647 assert(tree != NULL);
8648 assert(node != NULL);
8649 assert(*node != NULL);
8650
8651 if( (*node)->left != NULL )
8652 {
8653 SCIPbtnodeFree(tree, &(*node)->left);
8654 assert((*node)->left == NULL);
8655 }
8656
8657 if( (*node)->right != NULL )
8658 {
8659 SCIPbtnodeFree(tree, &(*node)->right);
8660 assert((*node)->right == NULL);
8661 }
8662
8663 btnodeFreeLeaf(tree, node);
8664 assert(*node == NULL);
8665 }
8666
8667 /* some simple variable functions implemented as defines */
8668
8669 /* In debug mode, the following methods are implemented as function calls to ensure
8670 * type validity.
8671 * In optimized mode, the methods are implemented as defines to improve performance.
8672 * However, we want to have them in the library anyways, so we have to undef the defines.
8673 */
8674
8675 #undef SCIPbtnodeGetData
8676 #undef SCIPbtnodeGetKey
8677 #undef SCIPbtnodeGetParent
8678 #undef SCIPbtnodeGetLeftchild
8679 #undef SCIPbtnodeGetRightchild
8680 #undef SCIPbtnodeGetSibling
8681 #undef SCIPbtnodeIsRoot
8682 #undef SCIPbtnodeIsLeaf
8683 #undef SCIPbtnodeIsLeftchild
8684 #undef SCIPbtnodeIsRightchild
8685
8686 /** returns the user data pointer stored in that node */
SCIPbtnodeGetData(SCIP_BTNODE * node)8687 void* SCIPbtnodeGetData(
8688 SCIP_BTNODE* node /**< node */
8689 )
8690 {
8691 assert(node != NULL);
8692
8693 return node->dataptr;
8694 }
8695
8696 /** returns the parent which can be NULL if the given node is the root */
SCIPbtnodeGetParent(SCIP_BTNODE * node)8697 SCIP_BTNODE* SCIPbtnodeGetParent(
8698 SCIP_BTNODE* node /**< node */
8699 )
8700 {
8701 assert(node != NULL);
8702
8703 return node->parent;
8704 }
8705
8706 /** returns left child which can be NULL if the given node is a leaf */
SCIPbtnodeGetLeftchild(SCIP_BTNODE * node)8707 SCIP_BTNODE* SCIPbtnodeGetLeftchild(
8708 SCIP_BTNODE* node /**< node */
8709 )
8710 {
8711 assert(node != NULL);
8712
8713 return node->left;
8714 }
8715
8716 /** returns right child which can be NULL if the given node is a leaf */
SCIPbtnodeGetRightchild(SCIP_BTNODE * node)8717 SCIP_BTNODE* SCIPbtnodeGetRightchild(
8718 SCIP_BTNODE* node /**< node */
8719 )
8720 {
8721 assert(node != NULL);
8722
8723 return node->right;
8724 }
8725
8726 /** returns the sibling of the node or NULL if does not exist */
SCIPbtnodeGetSibling(SCIP_BTNODE * node)8727 SCIP_BTNODE* SCIPbtnodeGetSibling(
8728 SCIP_BTNODE* node /**< node */
8729 )
8730 {
8731 SCIP_BTNODE* parent;
8732
8733 parent = SCIPbtnodeGetParent(node);
8734
8735 if( parent == NULL )
8736 return NULL;
8737
8738 if( SCIPbtnodeGetLeftchild(parent) == node )
8739 return SCIPbtnodeGetRightchild(parent);
8740
8741 assert(SCIPbtnodeGetRightchild(parent) == node);
8742
8743 return SCIPbtnodeGetLeftchild(parent);
8744 }
8745
8746 /** returns whether the node is a root node */
SCIPbtnodeIsRoot(SCIP_BTNODE * node)8747 SCIP_Bool SCIPbtnodeIsRoot(
8748 SCIP_BTNODE* node /**< node */
8749 )
8750 {
8751 assert(node != NULL);
8752
8753 return (node->parent == NULL);
8754 }
8755
8756 /** returns whether the node is a leaf */
SCIPbtnodeIsLeaf(SCIP_BTNODE * node)8757 SCIP_Bool SCIPbtnodeIsLeaf(
8758 SCIP_BTNODE* node /**< node */
8759 )
8760 {
8761 assert(node != NULL);
8762
8763 return (node->left == NULL && node->right == NULL);
8764 }
8765
8766 /** returns TRUE if the given node is left child */
SCIPbtnodeIsLeftchild(SCIP_BTNODE * node)8767 SCIP_Bool SCIPbtnodeIsLeftchild(
8768 SCIP_BTNODE* node /**< node */
8769 )
8770 {
8771 SCIP_BTNODE* parent;
8772
8773 if( SCIPbtnodeIsRoot(node) )
8774 return FALSE;
8775
8776 parent = SCIPbtnodeGetParent(node);
8777
8778 if( SCIPbtnodeGetLeftchild(parent) == node )
8779 return TRUE;
8780
8781 return FALSE;
8782 }
8783
8784 /** returns TRUE if the given node is right child */
SCIPbtnodeIsRightchild(SCIP_BTNODE * node)8785 SCIP_Bool SCIPbtnodeIsRightchild(
8786 SCIP_BTNODE* node /**< node */
8787 )
8788 {
8789 SCIP_BTNODE* parent;
8790
8791 if( SCIPbtnodeIsRoot(node) )
8792 return FALSE;
8793
8794 parent = SCIPbtnodeGetParent(node);
8795
8796 if( SCIPbtnodeGetRightchild(parent) == node )
8797 return TRUE;
8798
8799 return FALSE;
8800 }
8801
8802 /** sets the give node data
8803 *
8804 * @note The old user pointer is not freed.
8805 */
SCIPbtnodeSetData(SCIP_BTNODE * node,void * dataptr)8806 void SCIPbtnodeSetData(
8807 SCIP_BTNODE* node, /**< node */
8808 void* dataptr /**< node user data pointer */
8809 )
8810 {
8811 assert(node != NULL);
8812
8813 node->dataptr = dataptr;
8814 }
8815
8816 /** sets parent node
8817 *
8818 * @note The old parent including the rooted subtree is not delete.
8819 */
SCIPbtnodeSetParent(SCIP_BTNODE * node,SCIP_BTNODE * parent)8820 void SCIPbtnodeSetParent(
8821 SCIP_BTNODE* node, /**< node */
8822 SCIP_BTNODE* parent /**< new parent node, or NULL */
8823 )
8824 {
8825 assert(node != NULL);
8826
8827 node->parent = parent;
8828 }
8829
8830 /** sets left child
8831 *
8832 * @note The old left child including the rooted subtree is not delete.
8833 */
SCIPbtnodeSetLeftchild(SCIP_BTNODE * node,SCIP_BTNODE * left)8834 void SCIPbtnodeSetLeftchild(
8835 SCIP_BTNODE* node, /**< node */
8836 SCIP_BTNODE* left /**< new left child, or NULL */
8837 )
8838 {
8839 assert(node != NULL);
8840
8841 node->left = left;
8842 }
8843
8844 /** sets right child
8845 *
8846 * @note The old right child including the rooted subtree is not delete.
8847 */
SCIPbtnodeSetRightchild(SCIP_BTNODE * node,SCIP_BTNODE * right)8848 void SCIPbtnodeSetRightchild(
8849 SCIP_BTNODE* node, /**< node */
8850 SCIP_BTNODE* right /**< new right child, or NULL */
8851 )
8852 {
8853 assert(node != NULL);
8854
8855 node->right = right;
8856 }
8857
8858 /** creates an binary tree */
SCIPbtCreate(SCIP_BT ** tree,BMS_BLKMEM * blkmem)8859 SCIP_RETCODE SCIPbtCreate(
8860 SCIP_BT** tree, /**< pointer to store the created binary tree */
8861 BMS_BLKMEM* blkmem /**< block memory used to createnode */
8862 )
8863 {
8864 assert(tree != NULL);
8865 assert(blkmem != NULL);
8866
8867 SCIP_ALLOC( BMSallocBlockMemory(blkmem, tree) );
8868 (*tree)->blkmem = blkmem;
8869 (*tree)->root = NULL;
8870
8871 return SCIP_OKAY;
8872 }
8873
8874 /** frees binary tree
8875 *
8876 * @note The user pointers (object) of the nodes are not freed. If needed, it has to be done by the user.
8877 */
SCIPbtFree(SCIP_BT ** tree)8878 void SCIPbtFree(
8879 SCIP_BT** tree /**< pointer to binary tree */
8880 )
8881 {
8882 assert(tree != NULL);
8883
8884 if( (*tree)->root != NULL )
8885 {
8886 SCIPbtnodeFree(*tree, &((*tree)->root));
8887 }
8888
8889 BMSfreeBlockMemory((*tree)->blkmem, tree);
8890 }
8891
8892 /** prints the rooted subtree of the given binary tree node in GML format into the given file */
8893 static
btPrintSubtree(SCIP_BTNODE * node,FILE * file,int * nnodes)8894 void btPrintSubtree(
8895 SCIP_BTNODE* node, /**< binary tree node */
8896 FILE* file, /**< file to write to */
8897 int* nnodes /**< pointer to count the number of nodes */
8898 )
8899 {
8900 SCIP_BTNODE* left;
8901 SCIP_BTNODE* right;
8902 char label[SCIP_MAXSTRLEN];
8903
8904 assert(node != NULL);
8905
8906 (*nnodes)++;
8907 (void)SCIPsnprintf(label, SCIP_MAXSTRLEN, "%d", *nnodes);
8908
8909 SCIPgmlWriteNode(file, (unsigned int)(size_t)node, label, "circle", NULL, NULL);
8910
8911 left = SCIPbtnodeGetLeftchild(node);
8912 right = SCIPbtnodeGetRightchild(node);
8913
8914 if( left != NULL )
8915 {
8916 btPrintSubtree(left, file, nnodes);
8917
8918 SCIPgmlWriteArc(file, (unsigned int)(size_t)node, (unsigned int)(size_t)left, NULL, NULL);
8919 }
8920
8921 if( right != NULL )
8922 {
8923 btPrintSubtree(right, file, nnodes);
8924
8925 SCIPgmlWriteArc(file, (unsigned int)(size_t)node, (unsigned int)(size_t)right, NULL, NULL);
8926 }
8927 }
8928
8929 /** prints the binary tree in GML format into the given file */
SCIPbtPrintGml(SCIP_BT * tree,FILE * file)8930 void SCIPbtPrintGml(
8931 SCIP_BT* tree, /**< binary tree */
8932 FILE* file /**< file to write to */
8933 )
8934 {
8935 /* write GML opening */
8936 SCIPgmlWriteOpening(file, TRUE);
8937
8938 if( !SCIPbtIsEmpty(tree) )
8939 {
8940 SCIP_BTNODE* root;
8941 int nnodes;
8942
8943 root = SCIPbtGetRoot(tree);
8944 assert(root != NULL);
8945
8946 nnodes = 0;
8947
8948 btPrintSubtree(root, file, &nnodes);
8949 }
8950
8951 /* write GML closing */
8952 SCIPgmlWriteClosing(file);
8953 }
8954
8955 /* some simple variable functions implemented as defines */
8956 #undef SCIPbtIsEmpty
8957 #undef SCIPbtGetRoot
8958
8959 /** returns whether the binary tree is empty (has no nodes) */
SCIPbtIsEmpty(SCIP_BT * tree)8960 SCIP_Bool SCIPbtIsEmpty(
8961 SCIP_BT* tree /**< binary tree */
8962 )
8963 {
8964 assert(tree != NULL);
8965
8966 return (tree->root == NULL);
8967 }
8968
8969 /** returns the the root node of the binary or NULL if the binary tree is empty */
SCIPbtGetRoot(SCIP_BT * tree)8970 SCIP_BTNODE* SCIPbtGetRoot(
8971 SCIP_BT* tree /**< tree to be evaluated */
8972 )
8973 {
8974 assert(tree != NULL);
8975
8976 return tree->root;
8977 }
8978
8979 /** sets root node
8980 *
8981 * @note The old root including the rooted subtree is not delete.
8982 */
SCIPbtSetRoot(SCIP_BT * tree,SCIP_BTNODE * root)8983 void SCIPbtSetRoot(
8984 SCIP_BT* tree, /**< tree to be evaluated */
8985 SCIP_BTNODE* root /**< new root, or NULL */
8986 )
8987 {
8988 assert(tree != NULL);
8989
8990 tree->root = root;
8991 }
8992
8993
8994 /*
8995 * Numerical methods
8996 */
8997
8998 /** returns the machine epsilon: the smallest number eps > 0, for which 1.0 + eps > 1.0 */
SCIPcalcMachineEpsilon(void)8999 SCIP_Real SCIPcalcMachineEpsilon(
9000 void
9001 )
9002 {
9003 SCIP_Real eps;
9004 SCIP_Real lasteps;
9005 SCIP_Real one;
9006 SCIP_Real onepluseps;
9007
9008 one = 1.0;
9009 eps = 1.0;
9010 do
9011 {
9012 lasteps = eps;
9013 eps /= 2.0;
9014 onepluseps = one + eps;
9015 }
9016 while( onepluseps > one );
9017
9018 return lasteps;
9019 }
9020
9021 /** calculates the greatest common divisor of the two given values */
SCIPcalcGreComDiv(SCIP_Longint val1,SCIP_Longint val2)9022 SCIP_Longint SCIPcalcGreComDiv(
9023 SCIP_Longint val1, /**< first value of greatest common devisor calculation */
9024 SCIP_Longint val2 /**< second value of greatest common devisor calculation */
9025 )
9026 {
9027 int t;
9028
9029 assert(val1 > 0);
9030 assert(val2 > 0);
9031
9032 t = 0;
9033 /* if val1 is even, divide it by 2 */
9034 while( !(val1 & 1) )
9035 {
9036 val1 >>= 1; /*lint !e704*/
9037
9038 /* if val2 is even too, divide it by 2 and increase t(=number of e) */
9039 if( !(val2 & 1) )
9040 {
9041 val2 >>= 1; /*lint !e704*/
9042 ++t;
9043 }
9044 /* only val1 can be odd */
9045 else
9046 {
9047 /* while val1 is even, divide it by 2 */
9048 while( !(val1 & 1) )
9049 val1 >>= 1; /*lint !e704*/
9050
9051 break;
9052 }
9053 }
9054
9055 /* while val2 is even, divide it by 2 */
9056 while( !(val2 & 1) )
9057 val2 >>= 1; /*lint !e704*/
9058
9059 /* the following if/else condition is only to make sure that we do not overflow when adding up both values before
9060 * dividing them by 4 in the following while loop
9061 */
9062 if( t == 0 )
9063 {
9064 if( val1 > val2 )
9065 {
9066 val1 -= val2;
9067
9068 /* divide val1 by 2 as long as possible */
9069 while( !(val1 & 1) )
9070 val1 >>= 1; /*lint !e704*/
9071 }
9072 else if( val1 < val2 )
9073 {
9074 val2 -= val1;
9075
9076 /* divide val2 by 2 as long as possible */
9077 while( !(val2 & 1) )
9078 val2 >>= 1; /*lint !e704*/
9079 }
9080 }
9081
9082 /* val1 and val2 are odd */
9083 while( val1 != val2 )
9084 {
9085 if( val1 > val2 )
9086 {
9087 /* we can stop if one value reached one */
9088 if( val2 == 1 )
9089 return (val2 << t); /*lint !e647 !e703*/
9090
9091 /* if ((val1 xor val2) and 2) = 2, then gcd(val1, val2) = gcd((val1 + val2)/4, val2),
9092 * and otherwise gcd(val1, val2) = gcd((val1 − val2)/4, val2)
9093 */
9094 if( ((val1 ^ val2) & 2) == 2 )
9095 val1 += val2;
9096 else
9097 val1 -= val2;
9098
9099 assert((val1 & 3) == 0);
9100 val1 >>= 2; /*lint !e704*/
9101
9102 /* if val1 is still even, divide it by 2 */
9103 while( !(val1 & 1) )
9104 val1 >>= 1; /*lint !e704*/
9105 }
9106 else
9107 {
9108 /* we can stop if one value reached one */
9109 if( val1 == 1 )
9110 return (val1 << t); /*lint !e647 !e703*/
9111
9112 /* if ((val2 xor val1) and 2) = 2, then gcd(val2, val1) = gcd((val2 + val1)/4, val1),
9113 * and otherwise gcd(val2, val1) = gcd((val2 − val1)/4, val1)
9114 */
9115 if( ((val2 ^ val1) & 2) == 2 )
9116 val2 += val1;
9117 else
9118 val2 -= val1;
9119
9120 assert((val2 & 3) == 0);
9121 val2 >>= 2; /*lint !e704*/
9122
9123 /* if val2 is still even, divide it by 2 */
9124 while( !(val2 & 1) )
9125 val2 >>= 1; /*lint !e704*/
9126 }
9127 }
9128
9129 return (val1 << t); /*lint !e703*/
9130 }
9131
9132
9133 /* for the MS compiler, the function nextafter is named _nextafter */
9134 #if defined(_MSC_VER) && !defined(NO_NEXTAFTER)
9135 #define nextafter(x,y) _nextafter(x,y)
9136 #endif
9137
9138 /* on systems where the function nextafter is not defined, we provide an implementation from Sun */
9139 #ifdef NO_NEXTAFTER
9140 /* The following implementation of the routine nextafter() comes with the following license:
9141 *
9142 * ====================================================
9143 * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
9144 *
9145 * Developed at SunSoft, a Sun Microsystems, Inc. business.
9146 * Permission to use, copy, modify, and distribute this
9147 * software is freely granted, provided that this notice
9148 * is preserved.
9149 * ====================================================
9150 */
9151
9152 #define __HI(x) *(1+(int*)&x)
9153 #define __LO(x) *(int*)&x
9154 #define __HIp(x) *(1+(int*)x)
9155 #define __LOp(x) *(int*)x
9156
9157 static
nextafter(double x,double y)9158 double nextafter(double x, double y)
9159 {
9160 int hx;
9161 int hy;
9162 int ix;
9163 int iy;
9164 unsigned lx;
9165 unsigned ly;
9166
9167 /* cppcheck-suppress invalidPointerCast */
9168 hx = __HI(x); /* high word of x */
9169 /* cppcheck-suppress invalidPointerCast */
9170 lx = __LO(x); /* low word of x */
9171 /* cppcheck-suppress invalidPointerCast */
9172 hy = __HI(y); /* high word of y */
9173 /* cppcheck-suppress invalidPointerCast */
9174 ly = __LO(y); /* low word of y */
9175 ix = hx&0x7fffffff; /* |x| */
9176 iy = hy&0x7fffffff; /* |y| */
9177
9178 if( ((ix>=0x7ff00000) && ((ix-0x7ff00000)|lx) != 0 ) || /* x is nan */
9179 ( (iy>=0x7ff00000) && ((iy-0x7ff00000)|ly) != 0 )) /* y is nan */
9180 return x + y;
9181
9182 /* x == y, return x */
9183 if( x == y )
9184 return x;
9185
9186 /* x == 0 */
9187 if( (ix|lx) == 0 )
9188 {
9189 /* return +-minsubnormal */
9190 /* cppcheck-suppress invalidPointerCast */
9191 __HI(x) = hy&0x80000000;
9192 /* cppcheck-suppress invalidPointerCast */
9193 __LO(x) = 1;
9194 y = x * x;
9195 if ( y == x )
9196 return y;
9197 else
9198 return x; /* raise underflow flag */
9199 }
9200 /* x > 0 */
9201 if( hx >= 0 )
9202 {
9203 /* x > y, x -= ulp */
9204 if( hx > hy || ((hx == hy) && (lx > ly)) )
9205 {
9206 if ( lx == 0 )
9207 hx -= 1;
9208 lx -= 1;
9209 }
9210 else
9211 {
9212 /* x < y, x += ulp */
9213 lx += 1;
9214 if ( lx == 0 )
9215 hx += 1;
9216 }
9217 }
9218 else
9219 {
9220 /* x < 0 */
9221 if( hy >= 0 || hx > hy || ((hx == hy) && (lx > ly)) )
9222 {
9223 /* x < y, x -= ulp */
9224 if ( lx == 0 )
9225 hx -= 1;
9226 lx -= 1;
9227 }
9228 else
9229 {
9230 /* x > y, x += ulp */
9231 lx += 1;
9232 if( lx == 0 )
9233 hx += 1;
9234 }
9235 }
9236 hy = hx&0x7ff00000;
9237 /* overflow */
9238 if( hy >= 0x7ff00000 )
9239 return x + x;
9240 if( hy < 0x00100000 )
9241 {
9242 /* underflow */
9243 y = x*x;
9244 if( y != x )
9245 {
9246 /* raise underflow flag */
9247 /* cppcheck-suppress invalidPointerCast */
9248 __HI(y) = hx;
9249 /* cppcheck-suppress invalidPointerCast */
9250 __LO(y) = lx;
9251 return y;
9252 }
9253 }
9254
9255 /* cppcheck-suppress invalidPointerCast */
9256 __HI(x) = hx;
9257 /* cppcheck-suppress invalidPointerCast */
9258 __LO(x) = lx;
9259 return x;
9260 }
9261 #endif
9262
9263
9264 /** returns the next representable value of from in the direction of to */
SCIPnextafter(SCIP_Real from,SCIP_Real to)9265 SCIP_Real SCIPnextafter(
9266 SCIP_Real from, /**< value from which the next representable value should be returned */
9267 SCIP_Real to /**< direction in which the next representable value should be returned */
9268 )
9269 {
9270 return nextafter(from, to);
9271 }
9272
9273 /** calculates the smallest common multiple of the two given values */
SCIPcalcSmaComMul(SCIP_Longint val1,SCIP_Longint val2)9274 SCIP_Longint SCIPcalcSmaComMul(
9275 SCIP_Longint val1, /**< first value of smallest common multiple calculation */
9276 SCIP_Longint val2 /**< second value of smallest common multiple calculation */
9277 )
9278 {
9279 SCIP_Longint gcd;
9280
9281 assert(val1 > 0);
9282 assert(val2 > 0);
9283
9284 gcd = SCIPcalcGreComDiv(val1, val2);
9285
9286 return val1/gcd * val2;
9287 }
9288
9289 static const SCIP_Real simplednoms[] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0,
9290 17.0, 18.0, 19.0, 25.0, -1.0};
9291
9292 /** converts a real number into a (approximate) rational representation, and returns TRUE iff the conversion was
9293 * successful
9294 */
SCIPrealToRational(SCIP_Real val,SCIP_Real mindelta,SCIP_Real maxdelta,SCIP_Longint maxdnom,SCIP_Longint * nominator,SCIP_Longint * denominator)9295 SCIP_Bool SCIPrealToRational(
9296 SCIP_Real val, /**< real value r to convert into rational number */
9297 SCIP_Real mindelta, /**< minimal allowed difference r - q of real r and rational q = n/d */
9298 SCIP_Real maxdelta, /**< maximal allowed difference r - q of real r and rational q = n/d */
9299 SCIP_Longint maxdnom, /**< maximal denominator allowed */
9300 SCIP_Longint* nominator, /**< pointer to store the nominator n of the rational number */
9301 SCIP_Longint* denominator /**< pointer to store the denominator d of the rational number */
9302 )
9303 {
9304 SCIP_Real a;
9305 SCIP_Real b;
9306 SCIP_Real g0;
9307 SCIP_Real g1;
9308 SCIP_Real gx;
9309 SCIP_Real h0;
9310 SCIP_Real h1;
9311 SCIP_Real hx;
9312 SCIP_Real delta0;
9313 SCIP_Real delta1;
9314 SCIP_Real epsilon;
9315 int i;
9316
9317 assert(mindelta < 0.0);
9318 assert(maxdelta > 0.0);
9319 assert(nominator != NULL);
9320 assert(denominator != NULL);
9321
9322 if( REALABS(val) >= ((SCIP_Real)SCIP_LONGINT_MAX) / maxdnom )
9323 return FALSE;
9324
9325 /* try the simple denominators first: each value of the simpledenoms table multiplied by powers of 10
9326 * is tried as denominator
9327 */
9328 for( i = 0; simplednoms[i] > 0.0; ++i )
9329 {
9330 SCIP_Real nom;
9331 SCIP_Real dnom;
9332 SCIP_Real ratval0;
9333 SCIP_Real ratval1;
9334
9335 /* try powers of 10 (including 10^0) */
9336 dnom = simplednoms[i];
9337 while( dnom <= maxdnom )
9338 {
9339 nom = floor(val * dnom);
9340 ratval0 = nom/dnom;
9341 ratval1 = (nom+1.0)/dnom;
9342 if( mindelta <= val - ratval0 && val - ratval1 <= maxdelta )
9343 {
9344 if( val - ratval0 <= maxdelta )
9345 {
9346 *nominator = (SCIP_Longint)nom;
9347 *denominator = (SCIP_Longint)dnom;
9348 return TRUE;
9349 }
9350 if( mindelta <= val - ratval1 )
9351 {
9352 *nominator = (SCIP_Longint)(nom+1.0);
9353 *denominator = (SCIP_Longint)dnom;
9354 return TRUE;
9355 }
9356 }
9357 dnom *= 10.0;
9358 }
9359 }
9360
9361 /* the simple denominators didn't work: calculate rational representation with arbitrary denominator */
9362 epsilon = MIN(-mindelta, maxdelta)/2.0;
9363
9364 b = val;
9365 a = EPSFLOOR(b, epsilon);
9366 g0 = a;
9367 h0 = 1.0;
9368 g1 = 1.0;
9369 h1 = 0.0;
9370 delta0 = val - g0/h0;
9371 delta1 = (delta0 < 0.0 ? val - (g0-1.0)/h0 : val - (g0+1.0)/h0);
9372
9373 while( (delta0 < mindelta || delta0 > maxdelta) && (delta1 < mindelta || delta1 > maxdelta) )
9374 {
9375 assert(EPSGT(b, a, epsilon));
9376 assert(h0 >= 0.0);
9377 assert(h1 >= 0.0);
9378
9379 b = 1.0 / (b - a);
9380 a = EPSFLOOR(b, epsilon);
9381
9382 assert(a >= 0.0);
9383 gx = g0;
9384 hx = h0;
9385
9386 g0 = a * g0 + g1;
9387 h0 = a * h0 + h1;
9388
9389 g1 = gx;
9390 h1 = hx;
9391
9392 if( h0 > maxdnom )
9393 return FALSE;
9394
9395 delta0 = val - g0/h0;
9396 delta1 = (delta0 < 0.0 ? val - (g0-1.0)/h0 : val - (g0+1.0)/h0);
9397 }
9398
9399 if( REALABS(g0) > (SCIP_Real)(SCIP_LONGINT_MAX >> 4) || h0 > (SCIP_Real)(SCIP_LONGINT_MAX >> 4) )
9400 return FALSE;
9401
9402 assert(h0 > 0.5);
9403
9404 if( delta0 < mindelta )
9405 {
9406 assert(mindelta <= delta1 && delta1 <= maxdelta);
9407 *nominator = (SCIP_Longint)(g0 - 1.0);
9408 *denominator = (SCIP_Longint)h0;
9409 }
9410 else if( delta0 > maxdelta )
9411 {
9412 assert(mindelta <= delta1 && delta1 <= maxdelta);
9413 *nominator = (SCIP_Longint)(g0 + 1.0);
9414 *denominator = (SCIP_Longint)h0;
9415 }
9416 else
9417 {
9418 *nominator = (SCIP_Longint)g0;
9419 *denominator = (SCIP_Longint)h0;
9420 }
9421 assert(*denominator >= 1);
9422 assert(val - (SCIP_Real)(*nominator)/(SCIP_Real)(*denominator) >= mindelta);
9423 assert(val - (SCIP_Real)(*nominator)/(SCIP_Real)(*denominator) <= maxdelta);
9424
9425 return TRUE;
9426 }
9427
9428 /** checks, whether the given scalar scales the given value to an integral number with error in the given bounds */
9429 static
isIntegralScalar(SCIP_Real val,SCIP_Real scalar,SCIP_Real mindelta,SCIP_Real maxdelta)9430 SCIP_Bool isIntegralScalar(
9431 SCIP_Real val, /**< value that should be scaled to an integral value */
9432 SCIP_Real scalar, /**< scalar that should be tried */
9433 SCIP_Real mindelta, /**< minimal relative allowed difference of scaled coefficient s*c and integral i */
9434 SCIP_Real maxdelta /**< maximal relative allowed difference of scaled coefficient s*c and integral i */
9435 )
9436 {
9437 SCIP_Real sval;
9438 SCIP_Real downval;
9439 SCIP_Real upval;
9440
9441 assert(mindelta <= 0.0);
9442 assert(maxdelta >= 0.0);
9443
9444 sval = val * scalar;
9445 downval = floor(sval);
9446 upval = ceil(sval);
9447
9448 return (SCIPrelDiff(sval, downval) <= maxdelta || SCIPrelDiff(sval, upval) >= mindelta);
9449 }
9450
9451 /** additional scalars that are tried in integrality scaling */
9452 static const SCIP_Real scalars[] = {3.0, 5.0, 7.0, 9.0, 11.0, 13.0, 15.0, 17.0, 19.0};
9453 static const int nscalars = 9;
9454
9455 /** tries to find a value, such that all given values, if scaled with this value become integral in relative allowed
9456 * difference in between mindelta and maxdelta
9457 */
SCIPcalcIntegralScalar(SCIP_Real * vals,int nvals,SCIP_Real mindelta,SCIP_Real maxdelta,SCIP_Longint maxdnom,SCIP_Real maxscale,SCIP_Real * intscalar,SCIP_Bool * success)9458 SCIP_RETCODE SCIPcalcIntegralScalar(
9459 SCIP_Real* vals, /**< values to scale */
9460 int nvals, /**< number of values to scale */
9461 SCIP_Real mindelta, /**< minimal relative allowed difference of scaled coefficient s*c and integral i */
9462 SCIP_Real maxdelta, /**< maximal relative allowed difference of scaled coefficient s*c and integral i */
9463 SCIP_Longint maxdnom, /**< maximal denominator allowed in rational numbers */
9464 SCIP_Real maxscale, /**< maximal allowed scalar */
9465 SCIP_Real* intscalar, /**< pointer to store scalar that would make the coefficients integral, or NULL */
9466 SCIP_Bool* success /**< stores whether returned value is valid */
9467 )
9468 {
9469 SCIP_Real bestscalar;
9470 SCIP_Longint gcd;
9471 SCIP_Longint scm;
9472 SCIP_Longint nominator;
9473 SCIP_Longint denominator;
9474 SCIP_Real val;
9475 SCIP_Real minval;
9476 SCIP_Real absval;
9477 SCIP_Real scaleval;
9478 SCIP_Bool scalable;
9479 SCIP_Bool rational;
9480 int c;
9481 int s;
9482 int i;
9483
9484 assert(vals != NULL);
9485 assert(nvals >= 0);
9486 assert(maxdnom >= 1);
9487 assert(mindelta < 0.0);
9488 assert(maxdelta > 0.0);
9489 assert(success != NULL);
9490
9491 SCIPdebugMessage("trying to find rational representation for given values\n");
9492
9493 if( intscalar != NULL )
9494 *intscalar = SCIP_INVALID;
9495 *success = FALSE;
9496
9497 /* get minimal absolute non-zero value */
9498 minval = SCIP_REAL_MAX;
9499 for( c = 0; c < nvals; ++c )
9500 {
9501 val = vals[c];
9502 if( val < mindelta || val > maxdelta )
9503 {
9504 absval = REALABS(val);
9505 minval = MIN(minval, absval);
9506 }
9507 }
9508
9509 if( minval == SCIP_REAL_MAX ) /*lint !e777*/
9510 {
9511 /* all coefficients are zero (inside tolerances) */
9512 if( intscalar != NULL )
9513 *intscalar = 1.0;
9514 *success = TRUE;
9515 SCIPdebugMessage(" -> all values are zero (inside tolerances)\n");
9516
9517 return SCIP_OKAY;
9518 }
9519 assert(minval > MIN(-mindelta, maxdelta));
9520
9521 bestscalar = SCIP_INVALID;
9522
9523 for( i = 0; i < 2; ++i )
9524 {
9525 scalable = TRUE;
9526
9527 /* try, if values can be made integral multiplying them with the reciprocal of the smallest value and a power of 2 */
9528 if( i == 0 )
9529 scaleval = 1.0/minval;
9530 /* try, if values can be made integral by multiplying them by a power of 2 */
9531 else
9532 scaleval = 1.0;
9533
9534 for( c = 0; c < nvals && scalable; ++c )
9535 {
9536 /* check, if the value can be scaled with a simple scalar */
9537 val = vals[c];
9538 if( val == 0.0 ) /* zeros are allowed in the vals array */
9539 continue;
9540
9541 absval = REALABS(val);
9542 while( scaleval <= maxscale
9543 && (absval * scaleval < 0.5 || !isIntegralScalar(val, scaleval, mindelta, maxdelta)) )
9544 {
9545 for( s = 0; s < nscalars; ++s )
9546 {
9547 if( isIntegralScalar(val, scaleval * scalars[s], mindelta, maxdelta) )
9548 {
9549 scaleval *= scalars[s];
9550 break;
9551 }
9552 }
9553 if( s >= nscalars )
9554 scaleval *= 2.0;
9555 }
9556 scalable = (scaleval <= maxscale);
9557 SCIPdebugMessage(" -> val=%g, scaleval=%g, val*scaleval=%g, scalable=%u\n",
9558 val, scaleval, val*scaleval, scalable);
9559 }
9560 if( scalable )
9561 {
9562 /* make values integral by dividing them by the smallest value (and multiplying them with a power of 2) */
9563 assert(scaleval <= maxscale);
9564
9565 /* check if we found a better scaling value */
9566 if( scaleval < bestscalar )
9567 bestscalar = scaleval;
9568
9569 SCIPdebugMessage(" -> integrality could be achieved by scaling with %g\n", scaleval);
9570
9571 /* if the scalar is still the reciprocal of the minimal value, all coeffcients are the same and we do not get a better scalar */
9572 if( i == 0 && EPSEQ(scaleval, 1.0/minval, SCIP_DEFAULT_EPSILON) )
9573 {
9574 if( intscalar != NULL )
9575 *intscalar = bestscalar;
9576 *success = TRUE;
9577
9578 return SCIP_OKAY;
9579 }
9580 }
9581 }
9582
9583 /* convert each value into a rational number, calculate the greatest common divisor of the nominators
9584 * and the smallest common multiple of the denominators
9585 */
9586 gcd = 1;
9587 scm = 1;
9588 rational = TRUE;
9589
9590 /* first value (to initialize gcd) */
9591 for( c = 0; c < nvals && rational; ++c )
9592 {
9593 val = vals[c];
9594 if( val == 0.0 ) /* zeros are allowed in the vals array */
9595 continue;
9596
9597 rational = SCIPrealToRational(val, mindelta, maxdelta, maxdnom, &nominator, &denominator);
9598 if( rational && nominator != 0 )
9599 {
9600 assert(denominator > 0);
9601 gcd = ABS(nominator);
9602 scm = denominator;
9603 rational = ((SCIP_Real)scm/(SCIP_Real)gcd <= maxscale);
9604 SCIPdebugMessage(" -> c=%d first rational: val: %g == %" SCIP_LONGINT_FORMAT "/%" SCIP_LONGINT_FORMAT ", gcd=%" SCIP_LONGINT_FORMAT ", scm=%" SCIP_LONGINT_FORMAT ", rational=%u\n",
9605 c, val, nominator, denominator, gcd, scm, rational);
9606 break;
9607 }
9608 }
9609
9610 /* remaining values */
9611 for( ++c; c < nvals && rational; ++c )
9612 {
9613 val = vals[c];
9614 if( val == 0.0 ) /* zeros are allowed in the vals array */
9615 continue;
9616
9617 rational = SCIPrealToRational(val, mindelta, maxdelta, maxdnom, &nominator, &denominator);
9618 if( rational && nominator != 0 )
9619 {
9620 assert(denominator > 0);
9621 gcd = SCIPcalcGreComDiv(gcd, ABS(nominator));
9622 scm *= denominator / SCIPcalcGreComDiv(scm, denominator);
9623 rational = ((SCIP_Real)scm/(SCIP_Real)gcd <= maxscale);
9624 SCIPdebugMessage(" -> c=%d next rational : val: %g == %" SCIP_LONGINT_FORMAT "/%" SCIP_LONGINT_FORMAT ", gcd=%" SCIP_LONGINT_FORMAT ", scm=%" SCIP_LONGINT_FORMAT ", rational=%u\n",
9625 c, val, nominator, denominator, gcd, scm, rational);
9626 }
9627 else
9628 {
9629 SCIPdebugMessage(" -> failed to convert %g into a rational representation\n", val);
9630 }
9631 }
9632
9633 if( rational )
9634 {
9635 /* make values integral by multiplying them with the smallest common multiple of the denominators */
9636 assert((SCIP_Real)scm/(SCIP_Real)gcd <= maxscale);
9637
9638 /* check if we found a better scaling value */
9639 if( (SCIP_Real)scm/(SCIP_Real)gcd < bestscalar )
9640 bestscalar = (SCIP_Real)scm/(SCIP_Real)gcd;
9641
9642 SCIPdebugMessage(" -> integrality could be achieved by scaling with %g (rational:%" SCIP_LONGINT_FORMAT "/%" SCIP_LONGINT_FORMAT ")\n",
9643 (SCIP_Real)scm/(SCIP_Real)gcd, scm, gcd);
9644 }
9645
9646 if( bestscalar < SCIP_INVALID )
9647 {
9648 if( intscalar != NULL )
9649 *intscalar = bestscalar;
9650 *success = TRUE;
9651
9652 SCIPdebugMessage(" -> smallest value to achieve integrality is %g \n", bestscalar);
9653 }
9654
9655 return SCIP_OKAY;
9656 }
9657
9658 /* Inform compiler that this code accesses the floating-point environment, so that
9659 * certain optimizations should be omitted (http://www.cplusplus.com/reference/cfenv/FENV_ACCESS/).
9660 * Not supported by Clang (gives warning) and GCC (silently), at the moment.
9661 */
9662 #if defined(__INTEL_COMPILER) || defined(_MSC_VER)
9663 #pragma fenv_access (on)
9664 #elif defined __GNUC__
9665 #pragma STDC FENV_ACCESS ON
9666 #endif
9667
9668 /** given a (usually very small) interval, tries to find a rational number with simple denominator (i.e. a small
9669 * number, probably multiplied with powers of 10) out of this interval; returns TRUE iff a valid rational
9670 * number inside the interval was found
9671 */
SCIPfindSimpleRational(SCIP_Real lb,SCIP_Real ub,SCIP_Longint maxdnom,SCIP_Longint * nominator,SCIP_Longint * denominator)9672 SCIP_Bool SCIPfindSimpleRational(
9673 SCIP_Real lb, /**< lower bound of the interval */
9674 SCIP_Real ub, /**< upper bound of the interval */
9675 SCIP_Longint maxdnom, /**< maximal denominator allowed for resulting rational number */
9676 SCIP_Longint* nominator, /**< pointer to store the nominator n of the rational number */
9677 SCIP_Longint* denominator /**< pointer to store the denominator d of the rational number */
9678 )
9679 {
9680 SCIP_Real center;
9681 SCIP_Real delta;
9682
9683 assert(lb <= ub);
9684
9685 center = 0.5*(lb+ub);
9686
9687 /* in order to compute a rational number that is exactly within the bounds (as the user expects),
9688 * we computed the allowed delta with downward rounding, if available
9689 */
9690 if( SCIPintervalHasRoundingControl() )
9691 {
9692 SCIP_ROUNDMODE roundmode;
9693
9694 roundmode = SCIPintervalGetRoundingMode();
9695 SCIPintervalSetRoundingModeDownwards();
9696
9697 delta = 0.5*(ub-lb);
9698
9699 SCIPintervalSetRoundingMode(roundmode);
9700 }
9701 else
9702 {
9703 delta = 0.5*(ub-lb);
9704 }
9705
9706 return SCIPrealToRational(center, -delta, +delta, maxdnom, nominator, denominator);
9707 }
9708
9709 #if defined(__INTEL_COMPILER) || defined(_MSC_VER)
9710 #pragma fenv_access (off)
9711 #elif defined __GNUC__
9712 #pragma STDC FENV_ACCESS OFF
9713 #endif
9714
9715 /** given a (usually very small) interval, selects a value inside this interval; it is tried to select a rational number
9716 * with simple denominator (i.e. a small number, probably multiplied with powers of 10);
9717 * if no valid rational number inside the interval was found, selects the central value of the interval
9718 */
SCIPselectSimpleValue(SCIP_Real lb,SCIP_Real ub,SCIP_Longint maxdnom)9719 SCIP_Real SCIPselectSimpleValue(
9720 SCIP_Real lb, /**< lower bound of the interval */
9721 SCIP_Real ub, /**< upper bound of the interval */
9722 SCIP_Longint maxdnom /**< maximal denominator allowed for resulting rational number */
9723 )
9724 {
9725 SCIP_Real val;
9726
9727 val = 0.5*(lb+ub);
9728 if( lb < ub )
9729 {
9730 SCIP_Longint nominator;
9731 SCIP_Longint denominator;
9732 SCIP_Bool success;
9733
9734 /* try to find a "simple" rational number inside the interval */
9735 SCIPdebugMessage("simple rational in [%.9f,%.9f]:", lb, ub);
9736 success = SCIPfindSimpleRational(lb, ub, maxdnom, &nominator, &denominator);
9737 if( success )
9738 {
9739 val = (SCIP_Real)nominator/(SCIP_Real)denominator;
9740 SCIPdebugPrintf(" %" SCIP_LONGINT_FORMAT "/%" SCIP_LONGINT_FORMAT " == %.9f\n", nominator, denominator, val);
9741
9742 if( val - lb < 0.0 || val - ub > 0.0 )
9743 {
9744 SCIPdebugPrintf(" value is out of interval bounds by %g -> failed\n", MAX(lb-val, val-ub));
9745 val = 0.5*(lb+ub);
9746 }
9747 }
9748 else
9749 {
9750 SCIPdebugPrintf(" failed\n");
9751 }
9752 }
9753
9754 return val;
9755 }
9756
9757
9758
9759
9760 /*
9761 * Random Numbers
9762 */
9763
9764 #if defined(NO_RAND_R) || defined(_WIN32) || defined(_WIN64)
9765
9766 #define SCIP_RAND_MAX 32767
9767 /** returns a random number between 0 and SCIP_RAND_MAX */
9768 static
getRand(unsigned int * seedp)9769 int getRand(
9770 unsigned int* seedp /**< pointer to seed value */
9771 )
9772 {
9773 SCIP_Longint nextseed;
9774
9775 assert(seedp != NULL);
9776
9777 nextseed = (*seedp) * (SCIP_Longint)1103515245 + 12345;
9778 *seedp = (unsigned int)nextseed;
9779
9780 return (int)((unsigned int)(nextseed/(2*(SCIP_RAND_MAX+1))) % (SCIP_RAND_MAX+1));
9781 }
9782
9783 #else
9784
9785 #define SCIP_RAND_MAX RAND_MAX
9786
9787 /** returns a random number between 0 and SCIP_RAND_MAX */
9788 static
getRand(unsigned int * seedp)9789 int getRand(
9790 unsigned int* seedp /**< pointer to seed value */
9791 )
9792 {
9793 return rand_r(seedp);
9794 }
9795
9796 #endif
9797
9798 /** returns a random integer between minrandval and maxrandval */
9799 static
getRandomInt(int minrandval,int maxrandval,unsigned int * seedp)9800 int getRandomInt(
9801 int minrandval, /**< minimal value to return */
9802 int maxrandval, /**< maximal value to return */
9803 unsigned int* seedp /**< pointer to seed value */
9804 )
9805 {
9806 SCIP_Real randnumber;
9807
9808 randnumber = (SCIP_Real)getRand(seedp)/(SCIP_RAND_MAX+1.0);
9809 assert(randnumber >= 0.0);
9810 assert(randnumber < 1.0);
9811
9812 /* we multiply minrandval and maxrandval separately by randnumber in order to avoid overflow if they are more than INT_MAX
9813 * apart
9814 */
9815 return (int) (minrandval*(1.0 - randnumber) + maxrandval*randnumber + randnumber);
9816 }
9817
9818 /** returns a random real between minrandval and maxrandval */
9819 static
getRandomReal(SCIP_Real minrandval,SCIP_Real maxrandval,unsigned int * seedp)9820 SCIP_Real getRandomReal(
9821 SCIP_Real minrandval, /**< minimal value to return */
9822 SCIP_Real maxrandval, /**< maximal value to return */
9823 unsigned int* seedp /**< pointer to seed value */
9824 )
9825 {
9826 SCIP_Real randnumber;
9827
9828 randnumber = (SCIP_Real)getRand(seedp)/(SCIP_Real)SCIP_RAND_MAX;
9829 assert(randnumber >= 0.0);
9830 assert(randnumber <= 1.0);
9831
9832 /* we multiply minrandval and maxrandval separately by randnumber in order to avoid overflow if they are more than
9833 * SCIP_REAL_MAX apart
9834 */
9835 return minrandval*(1.0 - randnumber) + maxrandval*randnumber;
9836 }
9837
9838 /** returns a random integer between minrandval and maxrandval
9839 *
9840 * @deprecated Please use SCIPrandomGetInt() to request a random integer.
9841 */
SCIPgetRandomInt(int minrandval,int maxrandval,unsigned int * seedp)9842 int SCIPgetRandomInt(
9843 int minrandval, /**< minimal value to return */
9844 int maxrandval, /**< maximal value to return */
9845 unsigned int* seedp /**< pointer to seed value */
9846 )
9847 {
9848 return getRandomInt(minrandval, maxrandval, seedp);
9849 }
9850
9851 /** returns a random real between minrandval and maxrandval
9852 *
9853 * @deprecated Please use SCIPrandomGetReal() to request a random real.
9854 */
SCIPgetRandomReal(SCIP_Real minrandval,SCIP_Real maxrandval,unsigned int * seedp)9855 SCIP_Real SCIPgetRandomReal(
9856 SCIP_Real minrandval, /**< minimal value to return */
9857 SCIP_Real maxrandval, /**< maximal value to return */
9858 unsigned int* seedp /**< pointer to seed value */
9859 )
9860 {
9861 return getRandomReal(minrandval, maxrandval, seedp);
9862 }
9863
9864
9865 /* initial seeds for KISS random number generator */
9866 #define DEFAULT_SEED UINT32_C(123456789)
9867 #define DEFAULT_XOR UINT32_C(362436000)
9868 #define DEFAULT_MWC UINT32_C(521288629)
9869 #define DEFAULT_CST UINT32_C(7654321)
9870
9871
9872 /** initializes a random number generator with a given start seed */
SCIPrandomSetSeed(SCIP_RANDNUMGEN * randnumgen,unsigned int initseed)9873 void SCIPrandomSetSeed(
9874 SCIP_RANDNUMGEN* randnumgen, /**< random number generator */
9875 unsigned int initseed /**< initial random seed */
9876 )
9877 {
9878 assert(randnumgen != NULL);
9879
9880 /* use MAX() to avoid zero after over flowing */
9881 randnumgen->seed = MAX(SCIPhashTwo(DEFAULT_SEED, initseed), 1u);
9882 randnumgen->xor_seed = MAX(SCIPhashTwo(DEFAULT_XOR, initseed), 1u);
9883 randnumgen->mwc_seed = MAX(SCIPhashTwo(DEFAULT_MWC, initseed), 1u);
9884 randnumgen->cst_seed = SCIPhashTwo(DEFAULT_CST, initseed);
9885
9886 assert(randnumgen->seed > 0);
9887 assert(randnumgen->xor_seed > 0);
9888 assert(randnumgen->mwc_seed > 0);
9889 }
9890
9891 /** returns a random number between 0 and UINT32_MAX
9892 *
9893 * implementation of KISS random number generator developed by George Marsaglia.
9894 * KISS is combination of three different random number generators:
9895 * - Linear congruential generator
9896 * - Xorshift
9897 * - Lag-1 Multiply-with-carry
9898 *
9899 * KISS has a period of 2^123 and passes all statistical test part of BigCrush-Test of TestU01 [1].
9900 *
9901 * [1] http://dl.acm.org/citation.cfm?doid=1268776.1268777
9902 */
9903 static
randomGetRand(SCIP_RANDNUMGEN * randnumgen)9904 uint32_t randomGetRand(
9905 SCIP_RANDNUMGEN* randnumgen /**< random number generator */
9906 )
9907 {
9908 uint64_t t;
9909
9910 /* linear congruential */
9911 randnumgen->seed = (uint32_t) (randnumgen->seed * UINT64_C(1103515245) + UINT64_C(12345));
9912
9913 /* Xorshift */
9914 randnumgen->xor_seed ^= (randnumgen->xor_seed << 13);
9915 randnumgen->xor_seed ^= (randnumgen->xor_seed >> 17);
9916 randnumgen->xor_seed ^= (randnumgen->xor_seed << 5);
9917
9918 /* Multiply-with-carry */
9919 t = UINT64_C(698769069) * randnumgen->mwc_seed + randnumgen->cst_seed;
9920 randnumgen->cst_seed = (uint32_t) (t >> 32);
9921 randnumgen->mwc_seed = (uint32_t) t;
9922
9923 return randnumgen->seed + randnumgen->xor_seed + randnumgen->mwc_seed;
9924 }
9925
9926 /** creates and initializes a random number generator */
SCIPrandomCreate(SCIP_RANDNUMGEN ** randnumgen,BMS_BLKMEM * blkmem,unsigned int initialseed)9927 SCIP_RETCODE SCIPrandomCreate(
9928 SCIP_RANDNUMGEN** randnumgen, /**< random number generator */
9929 BMS_BLKMEM* blkmem, /**< block memory */
9930 unsigned int initialseed /**< initial random seed */
9931 )
9932 {
9933 assert(randnumgen != NULL);
9934
9935 SCIP_ALLOC( BMSallocBlockMemory(blkmem, randnumgen) );
9936
9937 SCIPrandomSetSeed((*randnumgen), initialseed);
9938
9939 return SCIP_OKAY;
9940 }
9941
9942 /** frees a random number generator */
SCIPrandomFree(SCIP_RANDNUMGEN ** randnumgen,BMS_BLKMEM * blkmem)9943 void SCIPrandomFree(
9944 SCIP_RANDNUMGEN** randnumgen, /**< random number generator */
9945 BMS_BLKMEM* blkmem /**< block memory */
9946 )
9947 {
9948 assert(randnumgen != NULL);
9949 assert((*randnumgen) != NULL);
9950
9951 BMSfreeBlockMemory(blkmem, randnumgen);
9952
9953 return;
9954 }
9955
9956
9957
9958 /** returns a random integer between minrandval and maxrandval */
SCIPrandomGetInt(SCIP_RANDNUMGEN * randnumgen,int minrandval,int maxrandval)9959 int SCIPrandomGetInt(
9960 SCIP_RANDNUMGEN* randnumgen, /**< random number generator */
9961 int minrandval, /**< minimal value to return */
9962 int maxrandval /**< maximal value to return */
9963 )
9964 {
9965 SCIP_Real randnumber;
9966 SCIP_Longint zeromax;
9967
9968 randnumber = (SCIP_Real)randomGetRand(randnumgen)/(UINT32_MAX+1.0);
9969 assert(randnumber >= 0.0);
9970 assert(randnumber < 1.0);
9971
9972 /* we need to shift the range to the non-negative integers to handle negative integer values correctly.
9973 * we use a long integer to avoid overflows.
9974 */
9975 zeromax = (SCIP_Longint)maxrandval - (SCIP_Longint)minrandval + 1;
9976
9977 return (int) ((SCIP_Longint)(zeromax * randnumber) + (SCIP_Longint)minrandval);
9978 }
9979
9980 /** returns a random real between minrandval and maxrandval */
SCIPrandomGetReal(SCIP_RANDNUMGEN * randnumgen,SCIP_Real minrandval,SCIP_Real maxrandval)9981 SCIP_Real SCIPrandomGetReal(
9982 SCIP_RANDNUMGEN* randnumgen, /**< random number generator */
9983 SCIP_Real minrandval, /**< minimal value to return */
9984 SCIP_Real maxrandval /**< maximal value to return */
9985 )
9986 {
9987 SCIP_Real randnumber;
9988
9989 randnumber = (SCIP_Real)randomGetRand(randnumgen)/(SCIP_Real)UINT32_MAX;
9990 assert(randnumber >= 0.0);
9991 assert(randnumber <= 1.0);
9992
9993 /* we multiply minrandval and maxrandval separately by randnumber in order to avoid overflow if they are more than
9994 * SCIP_REAL_MAX apart
9995 */
9996 return minrandval*(1.0 - randnumber) + maxrandval*randnumber;
9997 }
9998
9999 /** randomly shuffles parts of an integer array using the Fisher-Yates algorithm */
SCIPrandomPermuteIntArray(SCIP_RANDNUMGEN * randnumgen,int * array,int begin,int end)10000 void SCIPrandomPermuteIntArray(
10001 SCIP_RANDNUMGEN* randnumgen, /**< random number generator */
10002 int* array, /**< array to be shuffled */
10003 int begin, /**< first included index that should be subject to shuffling
10004 * (0 for first array entry)
10005 */
10006 int end /**< first excluded index that should not be subject to shuffling
10007 * (array size for last array entry)
10008 */
10009 )
10010 {
10011 int tmp;
10012 int i;
10013
10014 /* loop backwards through all elements and always swap the current last element to a random position */
10015 while( end > begin+1 )
10016 {
10017 --end;
10018
10019 /* get a random position into which the last entry should be shuffled */
10020 i = SCIPrandomGetInt(randnumgen, begin, end);
10021
10022 /* swap the last element and the random element */
10023 tmp = array[i];
10024 array[i] = array[end];
10025 array[end] = tmp;
10026 }
10027 }
10028
10029 /** randomly shuffles parts of an array using the Fisher-Yates algorithm */
SCIPrandomPermuteArray(SCIP_RANDNUMGEN * randnumgen,void ** array,int begin,int end)10030 void SCIPrandomPermuteArray(
10031 SCIP_RANDNUMGEN* randnumgen, /**< random number generator */
10032 void** array, /**< array to be shuffled */
10033 int begin, /**< first included index that should be subject to shuffling
10034 * (0 for first array entry)
10035 */
10036 int end /**< first excluded index that should not be subject to shuffling
10037 * (array size for last array entry)
10038 */
10039 )
10040 {
10041 void* tmp;
10042 int i;
10043
10044 /* loop backwards through all elements and always swap the current last element to a random position */
10045 while( end > begin+1 )
10046 {
10047 end--;
10048
10049 /* get a random position into which the last entry should be shuffled */
10050 i = SCIPrandomGetInt(randnumgen, begin, end);
10051
10052 /* swap the last element and the random element */
10053 tmp = array[i];
10054 array[i] = array[end];
10055 array[end] = tmp;
10056 }
10057 }
10058
10059 /** draws a random subset of disjoint elements from a given set of disjoint elements;
10060 * this implementation is suited for the case that nsubelems is considerably smaller then nelems
10061 */
SCIPrandomGetSubset(SCIP_RANDNUMGEN * randnumgen,void ** set,int nelems,void ** subset,int nsubelems)10062 SCIP_RETCODE SCIPrandomGetSubset(
10063 SCIP_RANDNUMGEN* randnumgen, /**< random number generator */
10064 void** set, /**< original set, from which elements should be drawn */
10065 int nelems, /**< number of elements in original set */
10066 void** subset, /**< subset in which drawn elements should be stored */
10067 int nsubelems /**< number of elements that should be drawn and stored */
10068 )
10069 {
10070 int i;
10071 int j;
10072
10073 /* if both sets are of equal size, we just copy the array */
10074 if( nelems == nsubelems)
10075 {
10076 BMScopyMemoryArray(subset,set,nelems);
10077 return SCIP_OKAY;
10078 }
10079
10080 /* abort, if size of subset is too big */
10081 if( nsubelems > nelems )
10082 {
10083 SCIPerrorMessage("Cannot create %d-elementary subset of %d-elementary set.\n", nsubelems, nelems);
10084 return SCIP_INVALIDDATA;
10085 }
10086 #ifndef NDEBUG
10087 for( i = 0; i < nsubelems; i++ )
10088 for( j = 0; j < i; j++ )
10089 assert(set[i] != set[j]);
10090 #endif
10091
10092 /* draw each element individually */
10093 i = 0;
10094 while( i < nsubelems )
10095 {
10096 int r;
10097
10098 r = SCIPrandomGetInt(randnumgen, 0, nelems-1);
10099 subset[i] = set[r];
10100
10101 /* if we get an element that we already had, we will draw again */
10102 for( j = 0; j < i; j++ )
10103 {
10104 if( subset[i] == subset[j] )
10105 {
10106 --i;
10107 break;
10108 }
10109 }
10110 ++i;
10111 }
10112 return SCIP_OKAY;
10113 }
10114
10115 /*
10116 * Additional math functions
10117 */
10118
10119 /** calculates a binomial coefficient n over m, choose m elements out of n, maximal value will be 33 over 16 (because
10120 * the n=33 is the last line in the Pascal's triangle where each entry fits in a 4 byte value), an error occurs due to
10121 * big numbers or an negative value m (and m < n) and -1 will be returned
10122 */
SCIPcalcBinomCoef(int n,int m)10123 SCIP_Longint SCIPcalcBinomCoef(
10124 int n, /**< number of different elements */
10125 int m /**< number to choose out of the above */
10126 )
10127 {
10128 if( m == 0 || m >= n )
10129 return 1;
10130
10131 if( m < 0 )
10132 return -1;
10133
10134 /* symmetry of the binomial coefficient, choose smaller m */
10135 if( m > n/2 )
10136 m = n - m;
10137
10138 /* trivial case m == 1 */
10139 if( m == 1 )
10140 return n;
10141
10142 /* simple case m == 2 */
10143 if( m == 2 )
10144 {
10145 if( ((SCIP_Real)SCIP_LONGINT_MAX) / n >= (n-1) * 2 ) /*lint !e790*/
10146 return ((SCIP_Longint)n*(n-1)/2); /*lint !e647*/
10147 else
10148 return -1;
10149 }
10150
10151 /* abort on to big numbers */
10152 if( m > 16 || n > 33 )
10153 return -1;
10154
10155 /* simple case m == 3 */
10156 if( m == 3 )
10157 return (n*(n-1)*(n-2)/6); /*lint !e647*/
10158 else
10159 {
10160 /* first half of Pascal's triangle numbers(without the symmetric part) backwards from (33,16) over (32,16),
10161 * (33,15), (32,15),(31,15, (30,15), (33,14) to (8,4) (rest is calculated directly)
10162 *
10163 * due to this order we can extract the right binomial coefficient by (16-m)^2+(16-m)+(33-n)
10164 */
10165 static const SCIP_Longint binoms[182] = {
10166 1166803110, 601080390, 1037158320, 565722720, 300540195, 155117520, 818809200, 471435600, 265182525, 145422675,
10167 77558760, 40116600, 573166440, 347373600, 206253075, 119759850, 67863915, 37442160, 20058300, 10400600,
10168 354817320, 225792840, 141120525, 86493225, 51895935, 30421755, 17383860, 9657700, 5200300, 2704156, 193536720,
10169 129024480, 84672315, 54627300, 34597290, 21474180, 13037895, 7726160, 4457400, 2496144, 1352078, 705432,
10170 92561040, 64512240, 44352165, 30045015, 20030010, 13123110, 8436285, 5311735, 3268760, 1961256, 1144066,
10171 646646, 352716, 184756, 38567100, 28048800, 20160075, 14307150, 10015005, 6906900, 4686825, 3124550, 2042975,
10172 1307504, 817190, 497420, 293930, 167960, 92378, 48620, 13884156, 10518300, 7888725, 5852925, 4292145, 3108105,
10173 2220075, 1562275, 1081575, 735471, 490314, 319770, 203490, 125970, 75582, 43758, 24310, 12870, 4272048, 3365856,
10174 2629575, 2035800, 1560780, 1184040, 888030, 657800, 480700, 346104, 245157, 170544, 116280, 77520, 50388, 31824,
10175 19448, 11440, 6435, 3432, 1107568, 906192, 736281, 593775, 475020, 376740, 296010, 230230, 177100, 134596,
10176 100947, 74613, 54264, 38760, 27132, 18564, 12376, 8008, 5005, 3003, 1716, 924, 237336, 201376, 169911, 142506,
10177 118755, 98280, 80730, 65780, 53130, 42504, 33649, 26334, 20349, 15504, 11628, 8568, 6188, 4368, 3003, 2002,
10178 1287, 792, 462, 252, 40920, 35960, 31465, 27405, 23751, 20475, 17550, 14950, 12650, 10626, 8855, 7315, 5985,
10179 4845, 3876, 3060, 2380, 1820, 1365, 1001, 715, 495, 330, 210, 126, 70};
10180
10181 /* m can at most be 16 */
10182 const int t = 16-m;
10183 assert(t >= 0);
10184 assert(n <= 33);
10185
10186 /* binoms array hast exactly 182 elements */
10187 assert(t*(t+1)+(33-n) < 182);
10188
10189 return binoms[t*(t+1)+(33-n)]; /*lint !e662 !e661*/
10190 }
10191 }
10192
10193 /** negates a number */
SCIPnegateReal(SCIP_Real x)10194 SCIP_Real SCIPnegateReal(
10195 SCIP_Real x /**< value to negate */
10196 )
10197 {
10198 return -x;
10199 }
10200
10201 /*
10202 * Permutations / Shuffling
10203 */
10204
10205 /** swaps two ints */
SCIPswapInts(int * value1,int * value2)10206 void SCIPswapInts(
10207 int* value1, /**< pointer to first integer */
10208 int* value2 /**< pointer to second integer */
10209 )
10210 {
10211 int tmp;
10212
10213 tmp = *value1;
10214 *value1 = *value2;
10215 *value2 = tmp;
10216 }
10217
10218 /** swaps two real values */
SCIPswapReals(SCIP_Real * value1,SCIP_Real * value2)10219 void SCIPswapReals(
10220 SCIP_Real* value1, /**< pointer to first real value */
10221 SCIP_Real* value2 /**< pointer to second real value */
10222 )
10223 {
10224 SCIP_Real tmp;
10225
10226 tmp = *value1;
10227 *value1 = *value2;
10228 *value2 = tmp;
10229 }
10230
10231 /** swaps the addresses of two pointers */
SCIPswapPointers(void ** pointer1,void ** pointer2)10232 void SCIPswapPointers(
10233 void** pointer1, /**< first pointer */
10234 void** pointer2 /**< second pointer */
10235 )
10236 {
10237 void* tmp;
10238
10239 tmp = *pointer1;
10240 *pointer1 = *pointer2;
10241 *pointer2 = tmp;
10242 }
10243
10244 /** randomly shuffles parts of an integer array using the Fisher-Yates algorithm
10245 *
10246 * @deprecated Please use SCIPrandomPermuteIntArray()
10247 */
SCIPpermuteIntArray(int * array,int begin,int end,unsigned int * randseed)10248 void SCIPpermuteIntArray(
10249 int* array, /**< array to be shuffled */
10250 int begin, /**< first included index that should be subject to shuffling
10251 * (0 for first array entry)
10252 */
10253 int end, /**< first excluded index that should not be subject to shuffling
10254 * (array size for last array entry)
10255 */
10256 unsigned int* randseed /**< seed value for the random generator */
10257 )
10258 {
10259 int tmp;
10260 int i;
10261
10262 /* loop backwards through all elements and always swap the current last element to a random position */
10263 while( end > begin+1 )
10264 {
10265 --end;
10266
10267 /* get a random position into which the last entry should be shuffled */
10268 i = getRandomInt(begin, end, randseed);
10269
10270 /* swap the last element and the random element */
10271 tmp = array[i];
10272 array[i] = array[end];
10273 array[end] = tmp;
10274 }
10275 }
10276
10277
10278 /** randomly shuffles parts of an array using the Fisher-Yates algorithm
10279 *
10280 * @deprecated Please use SCIPrandomPermuteArray()
10281 */
SCIPpermuteArray(void ** array,int begin,int end,unsigned int * randseed)10282 void SCIPpermuteArray(
10283 void** array, /**< array to be shuffled */
10284 int begin, /**< first included index that should be subject to shuffling
10285 * (0 for first array entry)
10286 */
10287 int end, /**< first excluded index that should not be subject to shuffling
10288 * (array size for last array entry)
10289 */
10290 unsigned int* randseed /**< seed value for the random generator */
10291 )
10292 {
10293 void* tmp;
10294 int i;
10295
10296 /* loop backwards through all elements and always swap the current last element to a random position */
10297 while( end > begin+1 )
10298 {
10299 end--;
10300
10301 /* get a random position into which the last entry should be shuffled */
10302 i = getRandomInt(begin, end, randseed);
10303
10304 /* swap the last element and the random element */
10305 tmp = array[i];
10306 array[i] = array[end];
10307 array[end] = tmp;
10308 }
10309 }
10310
10311 /** draws a random subset of disjoint elements from a given set of disjoint elements;
10312 * this implementation is suited for the case that nsubelems is considerably smaller then nelems
10313 *
10314 * @deprecated Please use SCIPrandomGetSubset()
10315 */
SCIPgetRandomSubset(void ** set,int nelems,void ** subset,int nsubelems,unsigned int randseed)10316 SCIP_RETCODE SCIPgetRandomSubset(
10317 void** set, /**< original set, from which elements should be drawn */
10318 int nelems, /**< number of elements in original set */
10319 void** subset, /**< subset in which drawn elements should be stored */
10320 int nsubelems, /**< number of elements that should be drawn and stored */
10321 unsigned int randseed /**< seed value for random generator */
10322 )
10323 {
10324 int i;
10325 int j;
10326
10327 /* if both sets are of equal size, we just copy the array */
10328 if( nelems == nsubelems)
10329 {
10330 BMScopyMemoryArray(subset,set,nelems);
10331 return SCIP_OKAY;
10332 }
10333
10334 /* abort, if size of subset is too big */
10335 if( nsubelems > nelems )
10336 {
10337 SCIPerrorMessage("Cannot create %d-elementary subset of %d-elementary set.\n", nsubelems, nelems);
10338 return SCIP_INVALIDDATA;
10339 }
10340 #ifndef NDEBUG
10341 for( i = 0; i < nsubelems; i++ )
10342 for( j = 0; j < i; j++ )
10343 assert(set[i] != set[j]);
10344 #endif
10345
10346 /* draw each element individually */
10347 i = 0;
10348 while( i < nsubelems )
10349 {
10350 int r;
10351
10352 r = getRandomInt(0, nelems-1, &randseed);
10353 subset[i] = set[r];
10354
10355 /* if we get an element that we already had, we will draw again */
10356 for( j = 0; j < i; j++ )
10357 {
10358 if( subset[i] == subset[j] )
10359 {
10360 --i;
10361 break;
10362 }
10363 }
10364 ++i;
10365 }
10366 return SCIP_OKAY;
10367 }
10368
10369
10370 /*
10371 * Arrays
10372 */
10373
10374 /** computes set intersection (duplicates removed) of two integer arrays that are ordered ascendingly */
SCIPcomputeArraysIntersection(int * array1,int narray1,int * array2,int narray2,int * intersectarray,int * nintersectarray)10375 SCIP_RETCODE SCIPcomputeArraysIntersection(
10376 int* array1, /**< first array (in ascending order) */
10377 int narray1, /**< number of entries of first array */
10378 int* array2, /**< second array (in ascending order) */
10379 int narray2, /**< number of entries of second array */
10380 int* intersectarray, /**< intersection of array1 and array2
10381 * (note: it is possible to use array1 for this input argument) */
10382 int* nintersectarray /**< pointer to store number of entries of intersection array
10383 * (note: it is possible to use narray1 for this input argument) */
10384 )
10385 {
10386 int cnt = 0;
10387 int k = 0;
10388 int v1;
10389 int v2;
10390
10391 assert( array1 != NULL );
10392 assert( array2 != NULL );
10393 assert( intersectarray != NULL );
10394 assert( nintersectarray != NULL );
10395
10396 /* determine intersection of array1 and array2 */
10397 for (v1 = 0; v1 < narray1; ++v1)
10398 {
10399 assert( v1 == 0 || array1[v1] >= array1[v1-1] );
10400
10401 /* skip duplicate entries */
10402 if ( v1+1 < narray1 && array1[v1] == array1[v1+1])
10403 continue;
10404
10405 for (v2 = k; v2 < narray2; ++v2)
10406 {
10407 assert( v2 == 0 || array2[v2] >= array2[v2-1] );
10408
10409 if ( array2[v2] > array1[v1] )
10410 {
10411 k = v2;
10412 break;
10413 }
10414 else if ( array2[v2] == array1[v1] )
10415 {
10416 intersectarray[cnt++] = array2[v2];
10417 k = v2 + 1;
10418 break;
10419 }
10420 }
10421 }
10422
10423 /* store size of intersection array */
10424 *nintersectarray = cnt;
10425
10426 return SCIP_OKAY;
10427 }
10428
10429
10430 /** computes set difference (duplicates removed) of two integer arrays that are ordered ascendingly */
SCIPcomputeArraysSetminus(int * array1,int narray1,int * array2,int narray2,int * setminusarray,int * nsetminusarray)10431 SCIP_RETCODE SCIPcomputeArraysSetminus(
10432 int* array1, /**< first array (in ascending order) */
10433 int narray1, /**< number of entries of first array */
10434 int* array2, /**< second array (in ascending order) */
10435 int narray2, /**< number of entries of second array */
10436 int* setminusarray, /**< array to store entries of array1 that are not an entry of array2
10437 * (note: it is possible to use array1 for this input argument) */
10438 int* nsetminusarray /**< pointer to store number of entries of setminus array
10439 * (note: it is possible to use narray1 for this input argument) */
10440 )
10441 {
10442 int cnt = 0;
10443 int v1 = 0;
10444 int v2 = 0;
10445
10446 assert( array1 != NULL );
10447 assert( array2 != NULL );
10448 assert( setminusarray != NULL );
10449 assert( nsetminusarray != NULL );
10450
10451 while ( v1 < narray1 )
10452 {
10453 int entry1;
10454
10455 assert( v1 == 0 || array1[v1] >= array1[v1-1] );
10456
10457 /* skip duplicate entries */
10458 while ( v1 + 1 < narray1 && array1[v1] == array1[v1 + 1] )
10459 ++v1;
10460
10461 entry1 = array1[v1];
10462
10463 while ( v2 < narray2 && array2[v2] < entry1 )
10464 ++v2;
10465
10466 if ( v2 >= narray2 || entry1 < array2[v2] )
10467 setminusarray[cnt++] = entry1;
10468 ++v1;
10469 }
10470
10471 /* store size of setminus array */
10472 *nsetminusarray = cnt;
10473
10474 return SCIP_OKAY;
10475 }
10476
10477
10478 /*
10479 * Strings
10480 */
10481
10482
10483 /** copies characters from 'src' to 'dest', copying is stopped when either the 'stop' character is reached or after
10484 * 'cnt' characters have been copied, whichever comes first.
10485 *
10486 * @note undefined behavior on overlapping arrays
10487 */
SCIPmemccpy(char * dest,const char * src,char stop,unsigned int cnt)10488 int SCIPmemccpy(
10489 char* dest, /**< destination pointer to copy to */
10490 const char* src, /**< source pointer to copy from */
10491 char stop, /**< character when found stop copying */
10492 unsigned int cnt /**< maximal number of characters to copy */
10493 )
10494 {
10495 if( dest == NULL || src == NULL || cnt == 0 )
10496 return -1;
10497 else
10498 {
10499 char* destination = dest;
10500
10501 while( cnt-- && (*destination++ = *src++) != stop ); /*lint !e722*/
10502
10503 return (int)(destination - dest);
10504 }
10505 }
10506
10507 /** prints an error message containing of the given string followed by a string describing the current system error
10508 *
10509 * Prefers to use the strerror_r method, which is threadsafe. On systems where this method does not exist,
10510 * NO_STRERROR_R should be defined (see INSTALL). In this case, strerror is used which is not guaranteed to be
10511 * threadsafe (on SUN-systems, it actually is).
10512 */
SCIPprintSysError(const char * message)10513 void SCIPprintSysError(
10514 const char* message /**< first part of the error message, e.g. the filename */
10515 )
10516 {
10517 #ifdef NO_STRERROR_R
10518 SCIPmessagePrintError("%s: %s\n", message, strerror(errno));
10519 #else
10520 char buf[SCIP_MAXSTRLEN];
10521
10522 #if defined(_WIN32) || defined(_WIN64)
10523 /* strerror_s returns 0 on success; the string is \0 terminated. */
10524 if ( strerror_s(buf, SCIP_MAXSTRLEN, errno) != 0 )
10525 SCIPmessagePrintError("Unknown error number %d or error message too long.\n", errno);
10526 SCIPmessagePrintError("%s: %s\n", message, buf);
10527 #elif (_POSIX_C_SOURCE >= 200112L || __DARWIN_C_LEVEL > 200112L || _XOPEN_SOURCE >= 600) && ! defined(_GNU_SOURCE)
10528 /* We are in the POSIX/XSI case, where strerror_r returns 0 on success; \0 termination is unclear. */
10529 if ( strerror_r(errno, buf, SCIP_MAXSTRLEN) != 0 )
10530 SCIPmessagePrintError("Unknown error number %d.\n", errno);
10531 buf[SCIP_MAXSTRLEN - 1] = '\0';
10532 SCIPmessagePrintError("%s: %s\n", message, buf);
10533 #else
10534 /* We are in the GNU case, where strerror_r returns a pointer to the error string. This string is possibly stored
10535 * in buf and is always \0 terminated.
10536 * However, if compiling on one system and executing on another system, we might actually call a different
10537 * variant of the strerror_r function than we had at compile time.
10538 */
10539 char* errordescr;
10540 *buf = '\0';
10541 errordescr = strerror_r(errno, buf, SCIP_MAXSTRLEN);
10542 if( *buf != '\0' )
10543 {
10544 /* strerror_r wrote into buf */
10545 SCIPmessagePrintError("%s: %s\n", message, buf);
10546 }
10547 else if( errordescr != NULL )
10548 {
10549 /* strerror_r returned something non-NULL */
10550 SCIPmessagePrintError("%s: %s\n", message, errordescr);
10551 }
10552 else
10553 {
10554 /* strerror_r did return NULL and did not write into buf */
10555 SCIPmessagePrintError("Could not obtain description for error %d.\n", errno);
10556 }
10557 #endif
10558 #endif
10559 }
10560
10561 /** extracts tokens from strings - wrapper method for strtok_r() */
SCIPstrtok(char * s,const char * delim,char ** ptrptr)10562 char* SCIPstrtok(
10563 char* s, /**< string to parse */
10564 const char* delim, /**< delimiters for parsing */
10565 char** ptrptr /**< pointer to working char pointer - must stay the same while parsing */
10566 )
10567 {
10568 #ifdef SCIP_NO_STRTOK_R
10569 return strtok(s, delim);
10570 #else
10571 return strtok_r(s, delim, ptrptr);
10572 #endif
10573 }
10574
10575 /** translates the given string into a string where symbols ", ', and spaces are escaped with a \ prefix */
SCIPescapeString(char * t,int bufsize,const char * s)10576 void SCIPescapeString(
10577 char* t, /**< target buffer to store escaped string */
10578 int bufsize, /**< size of buffer t */
10579 const char* s /**< string to transform into escaped string */
10580 )
10581 {
10582 int len;
10583 int i;
10584 int p;
10585
10586 assert(t != NULL);
10587 assert(bufsize > 0);
10588
10589 len = (int)strlen(s);
10590 for( p = 0, i = 0; i <= len && p < bufsize; ++i, ++p )
10591 {
10592 if( s[i] == ' ' || s[i] == '"' || s[i] == '\'' )
10593 {
10594 t[p] = '\\';
10595 p++;
10596 }
10597 if( p < bufsize )
10598 t[p] = s[i];
10599 }
10600 t[bufsize-1] = '\0';
10601 }
10602
10603 /* safe version of snprintf */
SCIPsnprintf(char * t,int len,const char * s,...)10604 int SCIPsnprintf(
10605 char* t, /**< target string */
10606 int len, /**< length of the string to copy */
10607 const char* s, /**< source string */
10608 ... /**< further parameters */
10609 )
10610 {
10611 va_list ap;
10612 int n;
10613
10614 assert(t != NULL);
10615 assert(len > 0);
10616
10617 va_start(ap, s); /*lint !e826*/
10618
10619 #if defined(_WIN32) || defined(_WIN64)
10620 n = _vsnprintf(t, (size_t) len, s, ap);
10621 #else
10622 n = vsnprintf(t, (size_t) len, s, ap); /*lint !e571*/
10623 #endif
10624 va_end(ap);
10625
10626 if( n < 0 || n >= len )
10627 {
10628 #ifndef NDEBUG
10629 if( n < 0 )
10630 {
10631 SCIPerrorMessage("vsnprintf returned %d\n",n);
10632 }
10633 #endif
10634 t[len-1] = '\0';
10635 n = len-1;
10636 }
10637 return n;
10638 }
10639
10640 /** safe version of strncpy
10641 *
10642 * Copies string in s to t using at most @a size-1 nonzero characters (strncpy copies size characters). It always adds
10643 * a terminating zero char. Does not pad the remaining string with zero characters (unlike strncpy). Returns the number
10644 * of copied nonzero characters, if the length of s is at most size - 1, and returns size otherwise. Thus, the original
10645 * string was truncated if the return value is size.
10646 */
SCIPstrncpy(char * t,const char * s,int size)10647 int SCIPstrncpy(
10648 char* t, /**< target string */
10649 const char* s, /**< source string */
10650 int size /**< maximal size of t */
10651 )
10652 {
10653 int n;
10654
10655 if( size <= 0 )
10656 return 0;
10657
10658 /* decrease size by 1 to create space for terminating zero char */
10659 --size;
10660 for( n = 0; n < size && *s != '\0'; n++ )
10661 *(t++) = *(s++);
10662 *t = '\0';
10663
10664 if( *s != '\0' )
10665 ++n;
10666
10667 return n;
10668 }
10669
10670 /** extract the next token as a integer value if it is one; in case no value is parsed the endptr is set to @p str
10671 *
10672 * @return Returns TRUE if a value could be extracted, otherwise FALSE
10673 */
SCIPstrToIntValue(const char * str,int * value,char ** endptr)10674 SCIP_Bool SCIPstrToIntValue(
10675 const char* str, /**< string to search */
10676 int* value, /**< pointer to store the parsed value */
10677 char** endptr /**< pointer to store the final string position if successfully parsed, otherwise @p str */
10678 )
10679 {
10680 assert(str != NULL);
10681 assert(value != NULL);
10682 assert(endptr != NULL);
10683
10684 /* init errno to detect possible errors */
10685 errno = 0;
10686
10687 *value = (int) strtol(str, endptr, 10);
10688
10689 if( *endptr != str && *endptr != NULL )
10690 {
10691 SCIPdebugMessage("parsed integer value <%d>\n", *value);
10692 return TRUE;
10693 }
10694 *endptr = (char*)str;
10695
10696 SCIPdebugMessage("failed parsing integer value <%s>\n", str);
10697
10698 return FALSE;
10699 }
10700
10701 /** extract the next token as a double value if it is one; in case no value is parsed the endptr is set to @p str
10702 *
10703 * @return Returns TRUE if a value could be extracted, otherwise FALSE
10704 */
SCIPstrToRealValue(const char * str,SCIP_Real * value,char ** endptr)10705 SCIP_Bool SCIPstrToRealValue(
10706 const char* str, /**< string to search */
10707 SCIP_Real* value, /**< pointer to store the parsed value */
10708 char** endptr /**< pointer to store the final string position if successfully parsed, otherwise @p str */
10709 )
10710 {
10711 assert(str != NULL);
10712 assert(value != NULL);
10713 assert(endptr != NULL);
10714
10715 /* init errno to detect possible errors */
10716 errno = 0;
10717
10718 *value = strtod(str, endptr);
10719
10720 if( *endptr != str && *endptr != NULL )
10721 {
10722 SCIPdebugMessage("parsed real value <%g>\n", *value);
10723 return TRUE;
10724 }
10725 *endptr = (char*)str;
10726
10727 SCIPdebugMessage("failed parsing real value <%s>\n", str);
10728
10729 return FALSE;
10730 }
10731
10732 /** copies the first size characters between a start and end character of str into token, if no error occurred endptr
10733 * will point to the position after the read part, otherwise it will point to @p str
10734 */
SCIPstrCopySection(const char * str,char startchar,char endchar,char * token,int size,char ** endptr)10735 void SCIPstrCopySection(
10736 const char* str, /**< string to search */
10737 char startchar, /**< character which defines the beginning */
10738 char endchar, /**< character which defines the ending */
10739 char* token, /**< string to store the copy */
10740 int size, /**< size of the token char array */
10741 char** endptr /**< pointer to store the final string position if successfully parsed, otherwise @p str */
10742 )
10743 {
10744 const char* copystr;
10745 int nchars;
10746
10747 assert(str != NULL);
10748 assert(token != NULL);
10749 assert(size > 0);
10750 assert(endptr != NULL);
10751
10752 nchars = 0;
10753
10754 copystr = str;
10755
10756 /* find starting character */
10757 while( *str != '\0' && *str != startchar )
10758 ++str;
10759
10760 /* did not find start character */
10761 if( *str == '\0' )
10762 {
10763 *endptr = (char*)copystr;
10764 return;
10765 }
10766
10767 /* skip start character */
10768 ++str;
10769
10770 /* copy string */
10771 while( *str != '\0' && *str != endchar && nchars < size-1 )
10772 {
10773 assert(nchars < SCIP_MAXSTRLEN);
10774 token[nchars] = *str;
10775 nchars++;
10776 ++str;
10777 }
10778
10779 /* add end to token */
10780 token[nchars] = '\0';
10781
10782 /* if section was longer than size, we want to reach the end of the parsing section anyway */
10783 if( nchars == (size-1) )
10784 while( *str != '\0' && *str != endchar )
10785 ++str;
10786
10787 /* did not find end character */
10788 if( *str == '\0' )
10789 {
10790 *endptr = (char*)copystr;
10791 return;
10792 }
10793
10794 /* skip end character */
10795 ++str;
10796
10797 SCIPdebugMessage("parsed section <%s>\n", token);
10798
10799 *endptr = (char*) str;
10800 }
10801
10802 /*
10803 * File methods
10804 */
10805
10806 /** returns, whether the given file exists */
SCIPfileExists(const char * filename)10807 SCIP_Bool SCIPfileExists(
10808 const char* filename /**< file name */
10809 )
10810 {
10811 FILE* f;
10812
10813 f = fopen(filename, "r");
10814 if( f == NULL )
10815 return FALSE;
10816
10817 fclose(f);
10818
10819 return TRUE;
10820 }
10821
10822 /** splits filename into path, name, and extension */
SCIPsplitFilename(char * filename,char ** path,char ** name,char ** extension,char ** compression)10823 void SCIPsplitFilename(
10824 char* filename, /**< filename to split; is destroyed (but not freed) during process */
10825 char** path, /**< pointer to store path, or NULL if not needed */
10826 char** name, /**< pointer to store name, or NULL if not needed */
10827 char** extension, /**< pointer to store extension, or NULL if not needed */
10828 char** compression /**< pointer to store compression extension, or NULL if not needed */
10829 )
10830 {
10831 char* lastslash;
10832 char* lastbackslash;
10833 char* lastdot;
10834
10835 assert(filename != NULL);
10836
10837 if( path != NULL )
10838 *path = NULL;
10839 if( name != NULL )
10840 *name = NULL;
10841 if( extension != NULL )
10842 *extension = NULL;
10843 if( compression != NULL )
10844 *compression = NULL;
10845
10846 /* treat both slashes '/' and '\' as directory delimiters */
10847 lastslash = strrchr(filename, '/');
10848 lastbackslash = strrchr(filename, '\\');
10849 lastslash = MAX(lastslash, lastbackslash); /*lint !e613*/
10850 lastdot = strrchr(filename, '.');
10851 if( lastslash != NULL && lastdot != NULL && lastdot < lastslash ) /* is the last dot belonging to the path? */
10852 lastdot = NULL;
10853
10854 /* detect known compression extensions */
10855 #ifdef SCIP_WITH_ZLIB
10856 if( lastdot != NULL )
10857 {
10858 char* compext;
10859
10860 compext = lastdot+1;
10861 if( strcmp(compext, "gz") == 0
10862 || strcmp(compext, "z") == 0
10863 || strcmp(compext, "Z") == 0 )
10864 {
10865 if( compression != NULL )
10866 *compression = compext;
10867 *lastdot = '\0';
10868 }
10869
10870 /* find again the last dot in the filename without compression extension */
10871 lastdot = strrchr(filename, '.');
10872 if( lastslash != NULL && lastdot != NULL && lastdot < lastslash ) /* is the last dot belonging to the path? */
10873 lastdot = NULL;
10874 }
10875 #endif
10876
10877 if( lastslash == NULL )
10878 {
10879 if( name != NULL )
10880 *name = filename;
10881 }
10882 else
10883 {
10884 if( path != NULL )
10885 *path = filename;
10886 if( name != NULL )
10887 *name = lastslash+1;
10888 *lastslash = '\0';
10889 }
10890
10891 if( lastdot != NULL )
10892 {
10893 if( extension != NULL )
10894 *extension = lastdot+1;
10895 *lastdot = '\0';
10896 }
10897 }
10898
10899 /*
10900 * simple functions implemented as defines
10901 */
10902
10903 /* In debug mode, the following methods are implemented as function calls to ensure
10904 * type validity.
10905 * In optimized mode, the methods are implemented as defines to improve performance.
10906 * However, we want to have them in the library anyways, so we have to undef the defines.
10907 */
10908
10909 #undef SCIPrelDiff
10910
10911 /** returns the relative difference: (val1-val2)/max(|val1|,|val2|,1.0) */
SCIPrelDiff(SCIP_Real val1,SCIP_Real val2)10912 SCIP_Real SCIPrelDiff(
10913 SCIP_Real val1, /**< first value to be compared */
10914 SCIP_Real val2 /**< second value to be compared */
10915 )
10916 {
10917 SCIP_Real absval1;
10918 SCIP_Real absval2;
10919 SCIP_Real quot;
10920
10921 absval1 = REALABS(val1);
10922 absval2 = REALABS(val2);
10923 quot = MAX3(1.0, absval1, absval2);
10924
10925 return (val1-val2)/quot;
10926 }
10927
10928
10929 /** computes the gap from the primal and the dual bound */
SCIPcomputeGap(SCIP_Real eps,SCIP_Real inf,SCIP_Real primalbound,SCIP_Real dualbound)10930 SCIP_Real SCIPcomputeGap(
10931 SCIP_Real eps, /**< the value treated as zero */
10932 SCIP_Real inf, /**< the value treated as infinity */
10933 SCIP_Real primalbound, /**< the primal bound */
10934 SCIP_Real dualbound /**< the dual bound */
10935 )
10936 {
10937 if( EPSEQ(primalbound, dualbound, eps) )
10938 return 0.0;
10939 else
10940 {
10941 SCIP_Real absdual = REALABS(dualbound);
10942 SCIP_Real absprimal = REALABS(primalbound);
10943
10944 if( EPSZ(dualbound, eps) || EPSZ(primalbound, eps) || absprimal >= inf || absdual >= inf ||
10945 primalbound * dualbound < 0.0 )
10946 return inf;
10947 else
10948 return REALABS((primalbound - dualbound)/MIN(absdual, absprimal));
10949 }
10950 }
10951
10952 /*
10953 * disjoint set (union-find) data structure
10954 */
10955
10956 /** creates a disjoint set (union find) structure \p djset for \p ncomponents many components (of size one) */
SCIPdisjointsetCreate(SCIP_DISJOINTSET ** djset,BMS_BLKMEM * blkmem,int ncomponents)10957 SCIP_RETCODE SCIPdisjointsetCreate(
10958 SCIP_DISJOINTSET** djset, /**< disjoint set (union find) data structure */
10959 BMS_BLKMEM* blkmem, /**< block memory */
10960 int ncomponents /**< number of components */
10961 )
10962 {
10963 assert(djset != NULL);
10964 assert(blkmem != NULL);
10965
10966 /* allocate the necessary memory */
10967 assert(ncomponents > 0);
10968 SCIP_ALLOC( BMSallocBlockMemory(blkmem, djset) );
10969 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &((*djset)->parents), ncomponents) );
10970 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &((*djset)->sizes), ncomponents) );
10971 (*djset)->size = ncomponents;
10972
10973 /* clear the data structure */
10974 SCIPdisjointsetClear(*djset);
10975
10976 return SCIP_OKAY;
10977 }
10978
10979 /** clears the disjoint set (union find) structure \p djset */
SCIPdisjointsetClear(SCIP_DISJOINTSET * djset)10980 void SCIPdisjointsetClear(
10981 SCIP_DISJOINTSET* djset /**< disjoint set (union find) data structure */
10982 )
10983 {
10984 int i;
10985
10986 djset->componentcount = djset->size;
10987
10988 /* reset all components to be unconnected */
10989 for( i = 0; i < djset->componentcount; i++ )
10990 {
10991 djset->parents[i] = i;
10992 djset->sizes[i] = 1;
10993 }
10994 }
10995
10996 /** finds and returns the component identifier of this \p element */
SCIPdisjointsetFind(SCIP_DISJOINTSET * djset,int element)10997 int SCIPdisjointsetFind(
10998 SCIP_DISJOINTSET* djset, /**< disjoint set (union find) data structure */
10999 int element /**< element to be found */
11000 )
11001 {
11002 int newelement;
11003 int root = element;
11004 int* parents = djset->parents;
11005
11006 /* find root of this element */
11007 while( root != parents[root] )
11008 {
11009 root = parents[root];
11010 }
11011
11012 /* compress the path to make future queries faster */
11013 while( element != root )
11014 {
11015 newelement = parents[element];
11016 parents[element] = root;
11017 element = newelement;
11018 }
11019
11020 return root;
11021 }
11022
11023 /** merges the components containing the elements \p p and \p q */
SCIPdisjointsetUnion(SCIP_DISJOINTSET * djset,int p,int q,SCIP_Bool forcerepofp)11024 void SCIPdisjointsetUnion(
11025 SCIP_DISJOINTSET* djset, /**< disjoint set (union find) data structure */
11026 int p, /**< first element */
11027 int q, /**< second element */
11028 SCIP_Bool forcerepofp /**< force representative of p to be new representative */
11029 )
11030 {
11031 int idp;
11032 int idq;
11033 int* sizes;
11034 int* parents;
11035
11036 assert(djset != NULL);
11037 assert(0 <= p);
11038 assert(0 <= q);
11039 assert(djset->size > p);
11040 assert(djset->size > q);
11041
11042 idp = SCIPdisjointsetFind(djset, p);
11043 idq = SCIPdisjointsetFind(djset, q);
11044
11045 /* if p and q lie in the same component, there is nothing to be done */
11046 if( idp == idq )
11047 return;
11048
11049 sizes = djset->sizes;
11050 parents = djset->parents;
11051
11052 if( forcerepofp )
11053 {
11054 parents[idq] = idp;
11055 sizes[idp] += sizes[idq];
11056 }
11057 else
11058 {
11059 if( sizes[idp] < sizes[idq] )
11060 {
11061 parents[idp] = idq;
11062 sizes[idq] += sizes[idp];
11063 }
11064 else
11065 {
11066 parents[idq] = idp;
11067 sizes[idp] += sizes[idq];
11068 }
11069 }
11070 /* one less component */
11071 djset->componentcount--;
11072 }
11073
11074 /** frees the disjoint set (union find) data structure */
SCIPdisjointsetFree(SCIP_DISJOINTSET ** djset,BMS_BLKMEM * blkmem)11075 void SCIPdisjointsetFree(
11076 SCIP_DISJOINTSET** djset, /**< pointer to disjoint set (union find) data structure */
11077 BMS_BLKMEM* blkmem /**< block memory */
11078 )
11079 {
11080 SCIP_DISJOINTSET* dsptr;
11081
11082 assert(djset != NULL);
11083 assert(*djset != NULL);
11084
11085 dsptr = *djset;
11086
11087 BMSfreeBlockMemoryArray(blkmem, &dsptr->sizes, dsptr->size);
11088 BMSfreeBlockMemoryArray(blkmem, &dsptr->parents, dsptr->size);
11089
11090 BMSfreeBlockMemory(blkmem, djset);
11091 }
11092
11093 /** returns the number of independent components in this disjoint set (union find) data structure */
SCIPdisjointsetGetComponentCount(SCIP_DISJOINTSET * djset)11094 int SCIPdisjointsetGetComponentCount(
11095 SCIP_DISJOINTSET* djset /**< disjoint set (union find) data structure */
11096 )
11097 {
11098 assert(djset != NULL);
11099
11100 return djset->componentcount;
11101 }
11102
11103 /** returns the size (number of nodes) of this disjoint set (union find) data structure */
SCIPdisjointsetGetSize(SCIP_DISJOINTSET * djset)11104 int SCIPdisjointsetGetSize(
11105 SCIP_DISJOINTSET* djset /**< disjoint set (union find) data structure */
11106 )
11107 {
11108 assert(djset != NULL);
11109
11110 return djset->size;
11111 }
11112
11113 /** checks whether a given string t appears at the beginning of the string s (up to spaces at beginning) */
SCIPstrAtStart(const char * s,const char * t,size_t tlen)11114 SCIP_Bool SCIPstrAtStart(
11115 const char* s, /**< string to search in */
11116 const char* t, /**< string to search for */
11117 size_t tlen /**< length of t */
11118 )
11119 {
11120 int idxctr = 0;
11121
11122 assert(s != NULL);
11123 assert(t != NULL);
11124
11125 /* skip whitespace at beginning */
11126 while( idxctr < SCIP_MAXSTRLEN && isspace((unsigned char)s[idxctr]) )
11127 ++idxctr;
11128 if( strncmp(&s[idxctr], t, tlen) == 0 )
11129 return TRUE;
11130 return FALSE;
11131 }
11132