Scippy

SCIP

Solving Constraint Integer Programs

misc.c
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the program and library */
4/* SCIP --- Solving Constraint Integer Programs */
5/* */
6/* Copyright (c) 2002-2024 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file misc.c
26 * @ingroup OTHER_CFILES
27 * @brief miscellaneous methods
28 * @author Tobias Achterberg
29 * @author Gerald Gamrath
30 * @author Stefan Heinz
31 * @author Michael Winkler
32 * @author Kati Wolter
33 * @author Gregor Hendel
34 */
35
36/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
37
38#define _USE_MATH_DEFINES /* to get M_SQRT2 on Windows */ /*lint !750 */
39
40#include <assert.h>
41#include <string.h>
42#include <stdarg.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <errno.h>
46#include <ctype.h>
47#include <math.h>
48#ifndef _MSC_VER
49#include <strings.h>
50#endif
51
52#include "scip/def.h"
53#include "scip/pub_message.h"
54#include "scip/misc.h"
55#include "scip/intervalarith.h"
56#include "scip/pub_misc.h"
57
58#ifndef NDEBUG
59#include "scip/struct_misc.h"
60#endif
61
62/*
63 * methods for statistical tests
64 */
65
66/**< contains all critical values for a one-sided two sample t-test up to 15 degrees of freedom
67 * a critical value represents a threshold for rejecting the null-hypothesis in hypothesis testing at
68 * a certain confidence level;
69 *
70 * access through method SCIPstudentTGetCriticalValue()
71 *
72 * source: German Wikipedia
73 *
74 * for confidence levels
75 * c =
76 * 0.75 0.875 0.90 0.95 0.975 (one-sided)
77 * 0.50 0.750 0.80 0.90 0.950 (two-sided)
78 *
79 */
80static const SCIP_Real studentt_quartiles[] = { /* df:*/
81 1.000, 2.414, 3.078, 6.314, 12.706, /* 1 */
82 0.816, 1.604, 1.886, 2.920, 4.303, /* 2 */
83 0.765, 1.423, 1.638, 2.353, 3.182, /* 3 */
84 0.741, 1.344, 1.533, 2.132, 2.776, /* 4 */
85 0.727, 1.301, 1.476, 2.015, 2.571, /* 5 */
86 0.718, 1.273, 1.440, 1.943, 2.447, /* 6 */
87 0.711, 1.254, 1.415, 1.895, 2.365, /* 7 */
88 0.706, 1.240, 1.397, 1.860, 2.306, /* 8 */
89 0.703, 1.230, 1.383, 1.833, 2.262, /* 9 */
90 0.700, 1.221, 1.372, 1.812, 2.228, /* 10 */
91 0.697, 1.214, 1.363, 1.796, 2.201, /* 11 */
92 0.695, 1.209, 1.356, 1.782, 2.179, /* 12 */
93 0.694, 1.204, 1.350, 1.771, 2.160, /* 13 */
94 0.692, 1.200, 1.345, 1.761, 2.145, /* 14 */
95 0.691, 1.197, 1.341, 1.753, 2.131 /* 15 */
96};
97
98/**< critical values for higher degrees of freedom of Student-T distribution for the same error probabilities; infact,
99 * these are critical values of the standard normal distribution with mean 0 and variance 1
100 */
102 0.674, 1.150, 1.282, 1.645, 1.960
103};
104
105/** the maximum degrees of freedom represented before switching to normal approximation */
106static const int studentt_maxdf = sizeof(studentt_quartiles)/(5 * sizeof(SCIP_Real));
107
108/** get critical value of a Student-T distribution for a given number of degrees of freedom at a confidence level */
110 SCIP_CONFIDENCELEVEL clevel, /**< (one-sided) confidence level */
111 int df /**< degrees of freedom */
112 )
113{
114 if( df > studentt_maxdf )
115 return studentt_quartilesabove[(int)clevel];
116 else
117 return studentt_quartiles[(int)clevel + 5 * (df - 1)];
118}
119
120/** compute a t-value for the hypothesis that x and y are from the same population; Assuming that
121 * x and y represent normally distributed random samples with equal variance, the returned value
122 * comes from a Student-T distribution with countx + county - 2 degrees of freedom; this
123 * value can be compared with a critical value (see also SCIPstudentTGetCriticalValue()) at
124 * a predefined confidence level for checking if x and y significantly differ in location
125 */
127 SCIP_Real meanx, /**< the mean of the first distribution */
128 SCIP_Real meany, /**< the mean of the second distribution */
129 SCIP_Real variancex, /**< the variance of the x-distribution */
130 SCIP_Real variancey, /**< the variance of the y-distribution */
131 SCIP_Real countx, /**< number of samples of x */
132 SCIP_Real county /**< number of samples of y */
133 )
134{
135 SCIP_Real pooledvariance;
136 SCIP_Real tresult;
137
138 /* too few samples */
139 if( countx < 1.9 || county < 1.9 )
140 return SCIP_INVALID;
141
142 /* pooled variance is the weighted average of the two variances */
143 pooledvariance = (countx - 1) * variancex + (county - 1) * variancey;
144 pooledvariance /= (countx + county - 2);
145
146 /* a variance close to zero means the distributions are basically constant */
147 pooledvariance = MAX(pooledvariance, 1e-9);
148
149 /* tresult can be understood as realization of a Student-T distributed variable with
150 * countx + county - 2 degrees of freedom
151 */
152 tresult = (meanx - meany) / sqrt(pooledvariance);
153 tresult *= sqrt(countx * county / (countx + county));
154
155 return tresult;
156}
157
158/** returns the value of the Gauss error function evaluated at a given point */
160 SCIP_Real x /**< value to evaluate */
161 )
162{
163#if defined(_WIN32) || defined(_WIN64)
164 SCIP_Real a1, a2, a3, a4, a5, p, t, y;
165 int sign;
166
167 a1 = 0.254829592;
168 a2 = -0.284496736;
169 a3 = 1.421413741;
170 a4 = -1.453152027;
171 a5 = 1.061405429;
172 p = 0.3275911;
173
174 sign = (x >= 0) ? 1 : -1;
175 x = REALABS(x);
176
177 t = 1.0/(1.0 + p*x);
178 y = 1.0 - (((((a5*t + a4)*t) + a3)*t + a2)*t + a1)*t*exp(-x*x);
179 return sign * y;
180#else
181 return erf(x);
182#endif
183}
184
185/** get critical value of a standard normal distribution at a given confidence level */
187 SCIP_CONFIDENCELEVEL clevel /**< (one-sided) confidence level */
188 )
189{
190 return studentt_quartilesabove[(int)clevel];
191}
192
193/** calculates the cumulative distribution P(-infinity <= x <= value) that a normally distributed
194 * random variable x takes a value between -infinity and parameter \p value.
195 *
196 * The distribution is given by the respective mean and deviation. This implementation
197 * uses the error function SCIPerf().
198 */
200 SCIP_Real mean, /**< the mean value of the distribution */
201 SCIP_Real variance, /**< the square of the deviation of the distribution */
202 SCIP_Real value /**< the upper limit of the calculated distribution integral */
203 )
204{
205 SCIP_Real normvalue;
207
208 /* we need to calculate the standard deviation from the variance */
209 assert(variance >= -1e-9);
210 if( variance < 1e-9 )
211 std = 0.0;
212 else
213 std = sqrt(variance);
214
215 /* special treatment for zero variance */
216 if( std < 1e-9 )
217 {
218 if( value < mean + 1e-9 )
219 return 1.0;
220 else
221 return 0.0;
222 }
223 assert( std != 0.0 ); /* for lint */
224
225 /* scale and translate to standard normal distribution. Factor sqrt(2) is needed for SCIPerf() function */
226 normvalue = (value - mean)/(std * M_SQRT2);
227
228 SCIPdebugMessage(" Normalized value %g = ( %g - %g ) / (%g * 1.4142136)\n", normvalue, value, mean, std);
229
230 /* calculate the cumulative distribution function for normvalue. For negative normvalues, we negate the normvalue and
231 * use the oddness of the SCIPerf()-function; special treatment for values close to zero.
232 */
233 if( normvalue < 1e-9 && normvalue > -1e-9 )
234 return .5;
235 else if( normvalue > 0 )
236 {
237 SCIP_Real erfresult;
238
239 erfresult = SCIPerf(normvalue);
240 return erfresult / 2.0 + 0.5;
241 }
242 else
243 {
244 SCIP_Real erfresult;
245
246 erfresult = SCIPerf(-normvalue);
247
248 return 0.5 - erfresult / 2.0;
249 }
250}
251
252/*
253 * SCIP regression methods
254 */
255
256/** returns the number of observations of this regression */
258 SCIP_REGRESSION* regression /**< regression data structure */
259 )
260{
261 assert(regression != NULL);
262
263 return regression->nobservations;
264}
265
266/** return the current slope of the regression */
268 SCIP_REGRESSION* regression /**< regression data structure */
269 )
270{
271 assert(regression != NULL);
272
273 return regression->slope;
274}
275
276/** get the current y-intercept of the regression */
278 SCIP_REGRESSION* regression /**< regression data structure */
279 )
280{
281 assert(regression != NULL);
282
283 return regression->intercept;
284}
285
286/** recomputes regression coefficients from available observation data */
287static
289 SCIP_REGRESSION* regression /**< regression data structure */
290 )
291{
292 /* regression coefficients require two or more observations and variance in x */
293 if( regression->nobservations <= 1 || EPSZ(regression->variancesumx, 1e-9) )
294 {
295 regression->slope = SCIP_INVALID;
296 regression->intercept = SCIP_INVALID;
297 regression->corrcoef = SCIP_INVALID;
298 }
299 else if( EPSZ(regression->variancesumy, 1e-9) )
300 {
301 /* 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 */
302 regression->slope = 0.0;
303 regression->corrcoef = 0.0;
304 regression->intercept = regression->meany;
305 }
306 else
307 {
308 /* we ruled this case out already, but to please some compilers... */
309 assert(regression->variancesumx > 0.0);
310 assert(regression->variancesumy > 0.0);
311
312 /* compute slope */
313 regression->slope = (regression->sumxy - regression->nobservations * regression->meanx * regression->meany) / regression->variancesumx;
314
315 /* compute y-intercept */
316 regression->intercept = regression->meany - regression->slope * regression->meanx;
317
318 /* compute empirical correlation coefficient */
319 regression->corrcoef = (regression->sumxy - regression->nobservations * regression->meanx * regression->meany) /
320 sqrt(regression->variancesumx * regression->variancesumy);
321 }
322}
323
324/* incremental update of statistics describing mean and variance */
325static
327 SCIP_Real value, /**< current value to be added to incremental statistics */
328 SCIP_Real* meanptr, /**< pointer to value of current mean */
329 SCIP_Real* sumvarptr, /**< pointer to the value of the current variance sum term */
330 int nobservations, /**< total number of observations */
331 SCIP_Bool add /**< TRUE if the value should be added, FALSE for removing it */
332 )
333{
334 SCIP_Real oldmean;
335 SCIP_Real addfactor;
336 assert(meanptr != NULL);
337 assert(sumvarptr != NULL);
338 assert(nobservations > 0 || add);
339
340 addfactor = add ? 1.0 : -1.0;
341
342 oldmean = *meanptr;
343 *meanptr = oldmean + addfactor * (value - oldmean)/(SCIP_Real)nobservations;
344 *sumvarptr += addfactor * (value - oldmean) * (value - (*meanptr));
345
346 /* it may happen that *sumvarptr is slightly negative, especially after a series of add/removal operations */
347 assert(*sumvarptr >= -1e-4);
348 *sumvarptr = MAX(0.0, *sumvarptr);
349}
350
351/** removes an observation (x,y) from the regression */
353 SCIP_REGRESSION* regression, /**< regression data structure */
354 SCIP_Real x, /**< X of observation */
355 SCIP_Real y /**< Y of the observation */
356 )
357{
358 assert(regression != NULL);
359 assert(regression->nobservations > 0);
360
361 /* simply call the reset function in the case of a single remaining observation to avoid numerical troubles */
362 if( regression->nobservations == 1 )
363 {
364 SCIPregressionReset(regression);
365 }
366 else
367 {
368 SCIP_Bool add = FALSE;
369 --regression->nobservations;
370
371 /* decrement individual means and variances */
372 incrementalStatsUpdate(x, &regression->meanx, &regression->variancesumx, regression->nobservations, add);
373 incrementalStatsUpdate(y, &regression->meany, &regression->variancesumy, regression->nobservations, add);
374
375 /* decrement product sum */
376 regression->sumxy -= (x * y);
377 }
378
379 /* recompute regression parameters */
380 regressionRecompute(regression);
381}
382
383/** update regression by a new observation (x,y) */
385 SCIP_REGRESSION* regression, /**< regression data structure */
386 SCIP_Real x, /**< X of observation */
387 SCIP_Real y /**< Y of the observation */
388 )
389{
390 SCIP_Bool add = TRUE;
391 assert(regression != NULL);
392
393 ++(regression->nobservations);
394 incrementalStatsUpdate(x, &regression->meanx, &regression->variancesumx, regression->nobservations, add);
395 incrementalStatsUpdate(y, &regression->meany, &regression->variancesumy, regression->nobservations, add);
396
397 regression->sumxy += x * y;
398
399 regressionRecompute(regression);
400}
401
402/** reset regression data structure */
404 SCIP_REGRESSION* regression /**< regression data structure */
405 )
406{
407 regression->intercept = SCIP_INVALID;
408 regression->slope = SCIP_INVALID;
409 regression->corrcoef = SCIP_INVALID;
410 regression->meanx = 0;
411 regression->variancesumx = 0;
412 regression->sumxy = 0;
413 regression->meany = 0;
414 regression->variancesumy = 0;
415 regression->nobservations = 0;
416}
417
418/** creates and resets a regression */
420 SCIP_REGRESSION** regression /**< regression data structure */
421 )
422{
423 assert(regression != NULL);
424
425 /* allocate necessary memory */
426 SCIP_ALLOC (BMSallocMemory(regression) );
427
428 /* reset the regression */
429 SCIPregressionReset(*regression);
430
431 return SCIP_OKAY;
432}
433
434/** creates and resets a regression */
436 SCIP_REGRESSION** regression /**< regression data structure */
437 )
438{
439 BMSfreeMemory(regression);
440}
441
442/** calculate memory size for dynamically allocated arrays (copied from scip/set.c) */
443static
445 int initsize, /**< initial size of array */
446 SCIP_Real growfac, /**< growing factor of array */
447 int num /**< minimum number of entries to store */
448 )
449{
450 int size;
451
452 assert(initsize >= 0);
453 assert(growfac >= 1.0);
454 assert(num >= 0);
455
456 if( growfac == 1.0 )
457 size = MAX(initsize, num);
458 else
459 {
460 int oldsize;
461
462 /* calculate the size with this loop, such that the resulting numbers are always the same (-> block memory) */
463 initsize = MAX(initsize, 4);
464 size = initsize;
465 oldsize = size - 1;
466
467 /* second condition checks against overflow */
468 while( size < num && size > oldsize )
469 {
470 oldsize = size;
471 size = (int)(growfac * size + initsize);
472 }
473
474 /* if an overflow happened, set the correct value */
475 if( size <= oldsize )
476 size = num;
477 }
478
479 assert(size >= initsize);
480 assert(size >= num);
481
482 return size;
483}
484
485/*
486 * GML graphical printing methods
487 * For a detailed format decription see http://docs.yworks.com/yfiles/doc/developers-guide/gml.html
488 */
489
490#define GMLNODEWIDTH 120.0
491#define GMLNODEHEIGTH 30.0
492#define GMLFONTSIZE 13
493#define GMLNODETYPE "rectangle"
494#define GMLNODEFILLCOLOR "#ff0000"
495#define GMLEDGECOLOR "black"
496#define GMLNODEBORDERCOLOR "#000000"
497
498
499/** writes a node section to the given graph file */
501 FILE* file, /**< file to write to */
502 unsigned int id, /**< id of the node */
503 const char* label, /**< label of the node */
504 const char* nodetype, /**< type of the node, or NULL */
505 const char* fillcolor, /**< color of the node's interior, or NULL */
506 const char* bordercolor /**< color of the node's border, or NULL */
507 )
508{
509 assert(file != NULL);
510 assert(label != NULL);
511
512 fprintf(file, " node\n");
513 fprintf(file, " [\n");
514 fprintf(file, " id %u\n", id);
515 fprintf(file, " label \"%s\"\n", label);
516 fprintf(file, " graphics\n");
517 fprintf(file, " [\n");
518 fprintf(file, " w %g\n", GMLNODEWIDTH);
519 fprintf(file, " h %g\n", GMLNODEHEIGTH);
520
521 if( nodetype != NULL )
522 fprintf(file, " type \"%s\"\n", nodetype);
523 else
524 fprintf(file, " type \"%s\"\n", GMLNODETYPE);
525
526 if( fillcolor != NULL )
527 fprintf(file, " fill \"%s\"\n", fillcolor);
528 else
529 fprintf(file, " fill \"%s\"\n", GMLNODEFILLCOLOR);
530
531 if( bordercolor != NULL )
532 fprintf(file, " outline \"%s\"\n", bordercolor);
533 else
534 fprintf(file, " outline \"%s\"\n", GMLNODEBORDERCOLOR);
535
536 fprintf(file, " ]\n");
537 fprintf(file, " LabelGraphics\n");
538 fprintf(file, " [\n");
539 fprintf(file, " text \"%s\"\n", label);
540 fprintf(file, " fontSize %d\n", GMLFONTSIZE);
541 fprintf(file, " fontName \"Dialog\"\n");
542 fprintf(file, " anchor \"c\"\n");
543 fprintf(file, " ]\n");
544 fprintf(file, " ]\n");
545}
546
547/** writes a node section including weight to the given graph file */
549 FILE* file, /**< file to write to */
550 unsigned int id, /**< id of the node */
551 const char* label, /**< label of the node */
552 const char* nodetype, /**< type of the node, or NULL */
553 const char* fillcolor, /**< color of the node's interior, or NULL */
554 const char* bordercolor, /**< color of the node's border, or NULL */
555 SCIP_Real weight /**< weight of node */
556 )
557{
558 assert(file != NULL);
559 assert(label != NULL);
560
561 fprintf(file, " node\n");
562 fprintf(file, " [\n");
563 fprintf(file, " id %u\n", id);
564 fprintf(file, " label \"%s\"\n", label);
565 fprintf(file, " weight %g\n", weight);
566 fprintf(file, " graphics\n");
567 fprintf(file, " [\n");
568 fprintf(file, " w %g\n", GMLNODEWIDTH);
569 fprintf(file, " h %g\n", GMLNODEHEIGTH);
570
571 if( nodetype != NULL )
572 fprintf(file, " type \"%s\"\n", nodetype);
573 else
574 fprintf(file, " type \"%s\"\n", GMLNODETYPE);
575
576 if( fillcolor != NULL )
577 fprintf(file, " fill \"%s\"\n", fillcolor);
578 else
579 fprintf(file, " fill \"%s\"\n", GMLNODEFILLCOLOR);
580
581 if( bordercolor != NULL )
582 fprintf(file, " outline \"%s\"\n", bordercolor);
583 else
584 fprintf(file, " outline \"%s\"\n", GMLNODEBORDERCOLOR);
585
586 fprintf(file, " ]\n");
587 fprintf(file, " LabelGraphics\n");
588 fprintf(file, " [\n");
589 fprintf(file, " text \"%s\"\n", label);
590 fprintf(file, " fontSize %d\n", GMLFONTSIZE);
591 fprintf(file, " fontName \"Dialog\"\n");
592 fprintf(file, " anchor \"c\"\n");
593 fprintf(file, " ]\n");
594 fprintf(file, " ]\n");
595}
596
597/** writes an edge section to the given graph file */
599 FILE* file, /**< file to write to */
600 unsigned int source, /**< source node id of the node */
601 unsigned int target, /**< target node id of the edge */
602 const char* label, /**< label of the edge, or NULL */
603 const char* color /**< color of the edge, or NULL */
604 )
605{
606 assert(file != NULL);
607
608 fprintf(file, " edge\n");
609 fprintf(file, " [\n");
610 fprintf(file, " source %u\n", source);
611 fprintf(file, " target %u\n", target);
612
613 if( label != NULL)
614 fprintf(file, " label \"%s\"\n", label);
615
616 fprintf(file, " graphics\n");
617 fprintf(file, " [\n");
618
619 if( color != NULL )
620 fprintf(file, " fill \"%s\"\n", color);
621 else
622 fprintf(file, " fill \"%s\"\n", GMLEDGECOLOR);
623
624 /* fprintf(file, " arrow \"both\"\n"); */
625 fprintf(file, " ]\n");
626
627 if( label != NULL)
628 {
629 fprintf(file, " LabelGraphics\n");
630 fprintf(file, " [\n");
631 fprintf(file, " text \"%s\"\n", label);
632 fprintf(file, " fontSize %d\n", GMLFONTSIZE);
633 fprintf(file, " fontName \"Dialog\"\n");
634 fprintf(file, " anchor \"c\"\n");
635 fprintf(file, " ]\n");
636 }
637
638 fprintf(file, " ]\n");
639}
640
641/** writes an arc section to the given graph file */
643 FILE* file, /**< file to write to */
644 unsigned int source, /**< source node id of the node */
645 unsigned int target, /**< target node id of the edge */
646 const char* label, /**< label of the edge, or NULL */
647 const char* color /**< color of the edge, or NULL */
648 )
649{
650 assert(file != NULL);
651
652 fprintf(file, " edge\n");
653 fprintf(file, " [\n");
654 fprintf(file, " source %u\n", source);
655 fprintf(file, " target %u\n", target);
656
657 if( label != NULL)
658 fprintf(file, " label \"%s\"\n", label);
659
660 fprintf(file, " graphics\n");
661 fprintf(file, " [\n");
662
663 if( color != NULL )
664 fprintf(file, " fill \"%s\"\n", color);
665 else
666 fprintf(file, " fill \"%s\"\n", GMLEDGECOLOR);
667
668 fprintf(file, " targetArrow \"standard\"\n");
669 fprintf(file, " ]\n");
670
671 if( label != NULL)
672 {
673 fprintf(file, " LabelGraphics\n");
674 fprintf(file, " [\n");
675 fprintf(file, " text \"%s\"\n", label);
676 fprintf(file, " fontSize %d\n", GMLFONTSIZE);
677 fprintf(file, " fontName \"Dialog\"\n");
678 fprintf(file, " anchor \"c\"\n");
679 fprintf(file, " ]\n");
680 }
681
682 fprintf(file, " ]\n");
683}
684
685/** writes the starting line to a GML graph file, does not open a file */
687 FILE* file, /**< file to write to */
688 SCIP_Bool directed /**< is the graph directed */
689 )
690{
691 assert(file != NULL);
692
693 fprintf(file, "graph\n");
694 fprintf(file, "[\n");
695 fprintf(file, " hierarchic 1\n");
696
697 if( directed )
698 fprintf(file, " directed 1\n");
699}
700
701/** writes the ending lines to a GML graph file, does not close a file */
703 FILE* file /**< file to close */
704 )
705{
706 assert(file != NULL);
707
708 fprintf(file, "]\n");
709}
710
711/**
712 * writes the opening line to a dot graph file, does not open a file
713 */
715 FILE* file /**< file to write to */
716 )
717{
718 assert(file != NULL);
719
720 fprintf(file, "digraph G {\n");
721}
722
723/** adds a node to the dot graph */
725 FILE* file, /**< file to write to */
726 int node, /**< node id */
727 const char* label, /**< node label */
728 const char* nodetype, /**< type of the node, or NULL */
729 const char* fillcolor, /**< color of the node's interior, or NULL */
730 const char* bordercolor /**< color of the node's border, or NULL */
731 )
732{
733 assert(file != NULL);
734
735 fprintf(file, "\t%d [shape=\"%s\", label=\"%s\", style=\"filled\", fillcolor=\"%s\", color=\"%s\"];\n", node, nodetype, label, fillcolor, bordercolor);
736}
737
738/** adds an arc (edge) between two nodes in the dot graph */
740 FILE* file, /**< file to write to */
741 int source, /**< source node id of the node */
742 int target, /**< target node id of the edge */
743 const char* color /**< color of the edge, or NULL */
744 )
745{
746 assert(file != NULL);
747
748 fprintf(file, "\t%d -> %d [color=\"%s\"];\n", source, target, color);
749}
750
751/** writes the closing line to a dot graph file, does not close a file */
753 FILE* file /**< file to write to */
754 )
755{
756 assert(file != NULL);
757
758 fprintf(file, "}\n");
759}
760
761/*
762 * Sparse solution
763 */
764
765/** creates a sparse solution */
767 SCIP_SPARSESOL** sparsesol, /**< pointer to store the created sparse solution */
768 SCIP_VAR** vars, /**< variables in the sparse solution, must not contain continuous
769 * variables
770 */
771 int nvars, /**< number of variables to store, size of the lower and upper bound
772 * arrays
773 */
774 SCIP_Bool cleared /**< should the lower and upper bound arrays be cleared (entries set to
775 * 0)
776 */
777 )
778{
779 assert(sparsesol != NULL);
780 assert(vars != NULL);
781 assert(nvars >= 0);
782
783 SCIP_ALLOC( BMSallocMemory(sparsesol) );
784
785#ifndef NDEBUG
786 {
787 int v;
788
789 for( v = nvars - 1; v >= 0; --v )
790 {
791 assert(vars[v] != NULL);
792 /* assert(SCIPvarGetType(vars[v]) != SCIP_VARTYPE_CONTINUOUS); */
793 }
794 }
795#endif
796
797 /* copy variables */
798 SCIP_ALLOC( BMSduplicateMemoryArray(&((*sparsesol)->vars), vars, nvars) );
799
800 /* create bound arrays */
801 if( cleared )
802 {
803 SCIP_ALLOC( BMSallocClearMemoryArray(&((*sparsesol)->lbvalues), nvars) );
804 SCIP_ALLOC( BMSallocClearMemoryArray(&((*sparsesol)->ubvalues), nvars) );
805 }
806 else
807 {
808 SCIP_ALLOC( BMSallocMemoryArray(&((*sparsesol)->lbvalues), nvars) );
809 SCIP_ALLOC( BMSallocMemoryArray(&((*sparsesol)->ubvalues), nvars) );
810 }
811
812 (*sparsesol)->nvars = nvars;
813
814 return SCIP_OKAY;
815}
816
817/** frees sparse solution */
819 SCIP_SPARSESOL** sparsesol /**< pointer to a sparse solution */
820 )
821{
822 assert(sparsesol != NULL);
823 assert(*sparsesol != NULL);
824
825 BMSfreeMemoryArray(&((*sparsesol)->vars));
826 BMSfreeMemoryArray(&((*sparsesol)->ubvalues));
827 BMSfreeMemoryArray(&((*sparsesol)->lbvalues));
828 BMSfreeMemory(sparsesol);
829}
830
831/** returns the variables stored in the given sparse solution */
833 SCIP_SPARSESOL* sparsesol /**< a sparse solution */
834 )
835{
836 assert(sparsesol != NULL);
837
838 return sparsesol->vars;
839}
840
841/** returns the number of variables stored in the given sparse solution */
843 SCIP_SPARSESOL* sparsesol /**< a sparse solution */
844 )
845{
846 assert(sparsesol != NULL);
847
848 return sparsesol->nvars;
849}
850
851/** returns the lower bound array for all variables for a given sparse solution */
853 SCIP_SPARSESOL* sparsesol /**< a sparse solution */
854 )
855{
856 assert(sparsesol != NULL);
857
858 return sparsesol->lbvalues;
859}
860
861/** returns the upper bound array for all variables for a given sparse solution */
863 SCIP_SPARSESOL* sparsesol /**< a sparse solution */
864 )
865{
866 assert(sparsesol != NULL);
867
868 return sparsesol->ubvalues;
869}
870
871/** constructs the first solution of sparse solution (all variables are set to their lower bound value */
873 SCIP_SPARSESOL* sparsesol, /**< sparse solutions */
874 SCIP_Longint* sol, /**< array to store the first solution */
875 int nvars /**< number of variables */
876 )
877{
878 SCIP_Longint* lbvalues;
879 int v;
880
881 assert(sparsesol != NULL);
882 assert(sol != NULL);
883 assert(nvars == SCIPsparseSolGetNVars(sparsesol));
884
885 lbvalues = SCIPsparseSolGetLbs(sparsesol);
886 assert(lbvalues != NULL);
887
888 /* copy the lower bounds */
889 for( v = 0; v < nvars; ++v )
890 sol[v] = lbvalues[v];
891}
892
893
894/** constructs the next solution of the sparse solution and return whether there was one more or not */
896 SCIP_SPARSESOL* sparsesol, /**< sparse solutions */
897 SCIP_Longint* sol, /**< current solution array which get changed to the next solution */
898 int nvars /**< number of variables */
899 )
900{
901 SCIP_Longint* lbvalues;
902 SCIP_Longint* ubvalues;
903 SCIP_Longint lbvalue;
904 SCIP_Longint ubvalue;
905 SCIP_Bool singular;
906 SCIP_Bool carryflag;
907 int v;
908
909 assert(sparsesol != NULL);
910 assert(sol != NULL);
911
912 if( nvars == 0 )
913 return FALSE;
914
915 assert(nvars > 0);
916 assert(nvars == SCIPsparseSolGetNVars(sparsesol));
917
918 lbvalues = SCIPsparseSolGetLbs(sparsesol);
919 ubvalues = SCIPsparseSolGetUbs(sparsesol);
920 assert(lbvalues != NULL);
921 assert(ubvalues != NULL);
922
923 singular = TRUE;
924 carryflag = FALSE;
925
926 for( v = 0; v < nvars; ++v )
927 {
928 lbvalue = lbvalues[v];
929 ubvalue = ubvalues[v];
930
931 if( lbvalue < ubvalue )
932 {
933 singular = FALSE;
934
935 if( carryflag == FALSE )
936 {
937 if( sol[v] < ubvalue )
938 {
939 sol[v]++;
940 break;
941 }
942 else
943 {
944 /* in the last solution the variables v was set to its upper bound value */
945 assert(sol[v] == ubvalue);
946 sol[v] = lbvalue;
947 carryflag = TRUE;
948 }
949 }
950 else
951 {
952 if( sol[v] < ubvalue )
953 {
954 sol[v]++;
955 carryflag = FALSE;
956 break;
957 }
958 else
959 {
960 assert(sol[v] == ubvalue);
961 sol[v] = lbvalue;
962 }
963 }
964 }
965 }
966
967 return (!carryflag && !singular);
968}
969
970
971/*
972 * Queue
973 */
974
975/** resizes element memory to hold at least the given number of elements */
976static
978 SCIP_QUEUE* queue, /**< pointer to a queue */
979 int minsize /**< minimal number of storable elements */
980 )
981{
982 assert(queue != NULL);
983 assert(minsize > 0);
984
985 if( minsize <= queue->size )
986 return SCIP_OKAY;
987
988 queue->size = MAX(minsize, (int)(queue->size * queue->sizefac));
989 SCIP_ALLOC( BMSreallocMemoryArray(&queue->slots, queue->size) );
990
991 return SCIP_OKAY;
992}
993
994
995/** creates a (circular) queue, best used if the size will be fixed or will not be increased that much */
997 SCIP_QUEUE** queue, /**< pointer to the new queue */
998 int initsize, /**< initial number of available element slots */
999 SCIP_Real sizefac /**< memory growing factor applied, if more element slots are needed */
1000 )
1001{
1002 assert(queue != NULL);
1003
1004 initsize = MAX(1, initsize);
1005 sizefac = MAX(1.0, sizefac);
1006
1007 SCIP_ALLOC( BMSallocMemory(queue) );
1008 (*queue)->firstfree = 0;
1009 (*queue)->firstused = -1;
1010 (*queue)->size = 0;
1011 (*queue)->sizefac = sizefac;
1012 (*queue)->slots = NULL;
1013
1014 SCIP_CALL( queueResize(*queue, initsize) );
1015
1016 return SCIP_OKAY;
1017}
1018
1019/** frees queue, but not the data elements themselves */
1021 SCIP_QUEUE** queue /**< pointer to a queue */
1022 )
1023{
1024 assert(queue != NULL);
1025
1026 BMSfreeMemoryArray(&(*queue)->slots);
1027 BMSfreeMemory(queue);
1028}
1029
1030/** clears the queue, but doesn't free the data elements themselves */
1032 SCIP_QUEUE* queue /**< queue */
1033 )
1034{
1035 assert(queue != NULL);
1036
1037 queue->firstfree = 0;
1038 queue->firstused = -1;
1039}
1040
1041/** reallocates slots if queue is necessary */
1042static
1044 SCIP_QUEUE* queue /**< queue */
1045 )
1046{
1047 if( queue->firstfree == queue->firstused )
1048 {
1049 int sizediff;
1050 int oldsize = queue->size;
1051
1052 SCIP_CALL( queueResize(queue, queue->size+1) );
1053 assert(oldsize < queue->size);
1054
1055 sizediff = queue->size - oldsize;
1056
1057 /* move the used memory at the slots to the end */
1058 BMSmoveMemoryArray(&(queue->slots[queue->firstused + sizediff]), &(queue->slots[queue->firstused]), oldsize - queue->firstused); /*lint !e866*/
1059 queue->firstused += sizediff;
1060 }
1061 assert(queue->firstfree != queue->firstused);
1062
1063 return SCIP_OKAY;
1064}
1065
1066/** checks and adjusts marker of first free and first used slot */
1067static
1069 SCIP_QUEUE* queue /**< queue */
1070 )
1071{
1072 /* if we saved the value at the last position we need to reset the firstfree position */
1073 if( queue->firstfree == queue->size )
1074 queue->firstfree = 0;
1075
1076 /* if a first element was added, we need to update the firstused counter */
1077 if( queue->firstused == -1 )
1078 queue->firstused = 0;
1079}
1080
1081/** inserts pointer element at the end of the queue */
1083 SCIP_QUEUE* queue, /**< queue */
1084 void* elem /**< element to be inserted */
1085 )
1086{
1087 assert(queue != NULL);
1088 assert(queue->slots != NULL);
1089 assert(queue->firstused >= -1 && queue->firstused < queue->size);
1090 assert(queue->firstfree >= 0 && queue->firstused < queue->size);
1091 assert(queue->firstused > -1 || queue->firstfree == 0);
1092 assert(elem != NULL);
1093
1094 /* check allocated memory */
1095 SCIP_CALL( queueCheckSize(queue) );
1096
1097 /* insert element at the first free slot */
1098 queue->slots[queue->firstfree].ptr = elem;
1099 ++(queue->firstfree);
1100
1101 /* check and adjust marker */
1102 queueCheckMarker(queue);
1103
1104 return SCIP_OKAY;
1105}
1106
1107/** inserts unsigned integer element at the end of the queue */
1109 SCIP_QUEUE* queue, /**< queue */
1110 unsigned int elem /**< element to be inserted */
1111 )
1112{
1113 assert(queue != NULL);
1114 assert(queue->slots != NULL);
1115 assert(queue->firstused >= -1 && queue->firstused < queue->size);
1116 assert(queue->firstfree >= 0 && queue->firstused < queue->size);
1117 assert(queue->firstused > -1 || queue->firstfree == 0);
1118
1119 /* check allocated memory */
1120 SCIP_CALL( queueCheckSize(queue) );
1121
1122 /* insert element at the first free slot */
1123 queue->slots[queue->firstfree].uinteger = elem;
1124 ++(queue->firstfree);
1125
1126 /* check and adjust marker */
1127 queueCheckMarker(queue);
1128
1129 return SCIP_OKAY;
1130}
1131
1132/** removes and returns the first pointer element of the queue, or NULL if no element exists */
1134 SCIP_QUEUE* queue /**< queue */
1135 )
1136{
1137 int pos;
1138
1139 assert(queue != NULL);
1140 assert(queue->firstused >= -1 && queue->firstused < queue->size);
1141 assert(queue->firstfree >= 0 && queue->firstused < queue->size);
1142 assert(queue->firstused > -1 || queue->firstfree == 0);
1143
1144 if( queue->firstused == -1 )
1145 return NULL;
1146
1147 assert(queue->slots != NULL);
1148
1149 pos = queue->firstused;
1150 ++(queue->firstused);
1151
1152 /* if we removed the value at the last position we need to reset the firstused position */
1153 if( queue->firstused == queue->size )
1154 queue->firstused = 0;
1155
1156 /* if we reached the first free position we can reset both, firstused and firstused, positions */
1157 if( queue->firstused == queue->firstfree )
1158 {
1159 queue->firstused = -1;
1160 queue->firstfree = 0; /* this is not necessary but looks better if we have an empty list to reset this value */
1161 }
1162
1163 return (queue->slots[pos].ptr);
1164}
1165
1166/** removes and returns the first unsigned integer element of the queue, or UINT_MAX if no element exists */
1168 SCIP_QUEUE* queue /**< queue */
1169 )
1170{
1171 int pos;
1172
1173 assert(queue != NULL);
1174 assert(queue->firstused >= -1 && queue->firstused < queue->size);
1175 assert(queue->firstfree >= 0 && queue->firstused < queue->size);
1176 assert(queue->firstused > -1 || queue->firstfree == 0);
1177
1178 if( queue->firstused == -1 )
1179 return UINT_MAX;
1180
1181 assert(queue->slots != NULL);
1182
1183 pos = queue->firstused;
1184 ++(queue->firstused);
1185
1186 /* if we removed the value at the last position we need to reset the firstused position */
1187 if( queue->firstused == queue->size )
1188 queue->firstused = 0;
1189
1190 /* if we reached the first free position we can reset both, firstused and firstused, positions */
1191 if( queue->firstused == queue->firstfree )
1192 {
1193 queue->firstused = -1;
1194 queue->firstfree = 0; /* this is not necessary but looks better if we have an empty list to reset this value */
1195 }
1196
1197 return (queue->slots[pos].uinteger);
1198}
1199
1200/** returns the first element of the queue without removing it, or NULL if no element exists */
1202 SCIP_QUEUE* queue /**< queue */
1203 )
1204{
1205 assert(queue != NULL);
1206 assert(queue->firstused >= -1 && queue->firstused < queue->size);
1207 assert(queue->firstfree >= 0 && queue->firstused < queue->size);
1208 assert(queue->firstused > -1 || queue->firstfree == 0);
1209
1210 if( queue->firstused == -1 )
1211 return NULL;
1212
1213 assert(queue->slots != NULL);
1214
1215 return queue->slots[queue->firstused].ptr;
1216}
1217
1218/** returns the first unsigned integer element of the queue without removing it, or UINT_MAX if no element exists */
1220 SCIP_QUEUE* queue /**< queue */
1221 )
1222{
1223 assert(queue != NULL);
1224 assert(queue->firstused >= -1 && queue->firstused < queue->size);
1225 assert(queue->firstfree >= 0 && queue->firstused < queue->size);
1226 assert(queue->firstused > -1 || queue->firstfree == 0);
1227
1228 if( queue->firstused == -1 )
1229 return UINT_MAX;
1230
1231 assert(queue->slots != NULL);
1232
1233 return queue->slots[queue->firstused].uinteger;
1234}
1235
1236/** returns whether the queue is empty */
1238 SCIP_QUEUE* queue /**< queue */
1239 )
1240{
1241 assert(queue != NULL);
1242 assert(queue->firstused >= -1 && queue->firstused < queue->size);
1243 assert(queue->firstfree >= 0 && queue->firstused < queue->size);
1244 assert(queue->firstused > -1 || queue->firstfree == 0);
1245
1246 return (queue->firstused == -1);
1247}
1248
1249/** returns the number of elements in the queue */
1251 SCIP_QUEUE* queue /**< queue */
1252 )
1253{
1254 assert(queue != NULL);
1255 assert(queue->firstused >= -1 && queue->firstused < queue->size);
1256 assert(queue->firstfree >= 0 && queue->firstused < queue->size);
1257 assert(queue->firstused > -1 || queue->firstfree == 0);
1258
1259 if( queue->firstused == -1 )
1260 return 0;
1261 else if( queue->firstused < queue->firstfree )
1262 return queue->firstfree - queue->firstused;
1263 else if( queue->firstused == queue->firstfree )
1264 return queue->size;
1265 else
1266 return queue->firstfree + (queue->size - queue->firstused);
1267}
1268
1269
1270/*
1271 * Priority Queue
1272 */
1273
1274#define PQ_PARENT(q) (((q)+1)/2-1)
1275#define PQ_LEFTCHILD(p) (2*(p)+1)
1276#define PQ_RIGHTCHILD(p) (2*(p)+2)
1277
1278
1279/** resizes element memory to hold at least the given number of elements */
1280static
1282 SCIP_PQUEUE* pqueue, /**< pointer to a priority queue */
1283 int minsize /**< minimal number of storable elements */
1284 )
1285{
1286 assert(pqueue != NULL);
1287
1288 if( minsize <= pqueue->size )
1289 return SCIP_OKAY;
1290
1291 pqueue->size = MAX(minsize, (int)(pqueue->size * pqueue->sizefac));
1292 SCIP_ALLOC( BMSreallocMemoryArray(&pqueue->slots, pqueue->size) );
1293
1294 return SCIP_OKAY;
1295}
1296
1297/** creates priority queue */
1299 SCIP_PQUEUE** pqueue, /**< pointer to a priority queue */
1300 int initsize, /**< initial number of available element slots */
1301 SCIP_Real sizefac, /**< memory growing factor applied, if more element slots are needed */
1302 SCIP_DECL_SORTPTRCOMP((*ptrcomp)), /**< data element comparator */
1303 SCIP_DECL_PQUEUEELEMCHGPOS((*elemchgpos)) /**< callback to act on position change of elem in priority queue, or NULL */
1304 )
1305{
1306 assert(pqueue != NULL);
1307 assert(ptrcomp != NULL);
1308
1309 initsize = MAX(1, initsize);
1310 sizefac = MAX(1.0, sizefac);
1311
1312 SCIP_ALLOC( BMSallocMemory(pqueue) );
1313 (*pqueue)->len = 0;
1314 (*pqueue)->size = 0;
1315 (*pqueue)->sizefac = sizefac;
1316 (*pqueue)->slots = NULL;
1317 (*pqueue)->ptrcomp = ptrcomp;
1318 (*pqueue)->elemchgpos = elemchgpos;
1319 SCIP_CALL( pqueueResize(*pqueue, initsize) );
1320
1321 return SCIP_OKAY;
1322}
1323
1324/** frees priority queue, but not the data elements themselves */
1326 SCIP_PQUEUE** pqueue /**< pointer to a priority queue */
1327 )
1328{
1329 assert(pqueue != NULL);
1330
1331 BMSfreeMemoryArray(&(*pqueue)->slots);
1332 BMSfreeMemory(pqueue);
1333}
1334
1335/** clears the priority queue, but doesn't free the data elements themselves */
1337 SCIP_PQUEUE* pqueue /**< priority queue */
1338 )
1339{
1340 assert(pqueue != NULL);
1341
1342 pqueue->len = 0;
1343}
1344
1345/** assign element to new slot in priority queue */
1346static
1348 SCIP_PQUEUE* pqueue, /**< priority queue */
1349 void* elem, /**< element whose position changes */
1350 int oldpos, /**< old position or -1 if elem is newly inserted */
1351 int newpos /**< new position */
1352 )
1353{
1354 pqueue->slots[newpos] = elem;
1355
1356 /* act on position change */
1357 if( pqueue->elemchgpos != NULL )
1358 {
1359 pqueue->elemchgpos(elem, oldpos, newpos);
1360 }
1361}
1362
1363#ifdef SCIP_MORE_DEBUG
1364/** ensure that the priority queue still has the heap property */
1365static
1366SCIP_Bool pqueueHasHeapProperty(
1367 SCIP_PQUEUE* pqueue /**< priority queue */
1368 )
1369{
1370 int i;
1371
1372 if( SCIPpqueueNElems(pqueue) == 0 )
1373 return TRUE;
1374
1375 /* check local heap property between parents and children */
1376 for( i = 0; i < SCIPpqueueNElems(pqueue); ++i )
1377 {
1378 if( i > 0 && pqueue->ptrcomp(pqueue->slots[i], pqueue->slots[PQ_PARENT(i)]) < 0 )
1379 return FALSE;
1380 if( i < PQ_PARENT(SCIPpqueueNElems(pqueue)) )
1381 {
1382 int leftchild = PQ_LEFTCHILD(i);
1383 int rightchild = PQ_RIGHTCHILD(i);
1384 assert(leftchild < SCIPpqueueNElems(pqueue));
1385 assert(rightchild <= SCIPpqueueNElems(pqueue));
1386 if( pqueue->ptrcomp(pqueue->slots[i], pqueue->slots[leftchild]) > 0 )
1387 return FALSE;
1388 if( rightchild < SCIPpqueueNElems(pqueue) && pqueue->ptrcomp(pqueue->slots[i], pqueue->slots[rightchild]) > 0)
1389 return FALSE;
1390 }
1391 }
1392 return TRUE;
1393}
1394#endif
1395
1396/** inserts element into priority queue */
1398 SCIP_PQUEUE* pqueue, /**< priority queue */
1399 void* elem /**< element to be inserted */
1400 )
1401{
1402 int pos;
1403 int parentpos;
1404
1405 assert(pqueue != NULL);
1406 assert(pqueue->len >= 0);
1407 assert(elem != NULL);
1408
1409 SCIP_CALL( pqueueResize(pqueue, pqueue->len+1) );
1410
1411 /* insert element as leaf in the tree, move it towards the root as long it is better than its parent */
1412 pos = pqueue->len;
1413 pqueue->len++;
1414 parentpos = PQ_PARENT(pos);
1415 while( pos > 0 && (*pqueue->ptrcomp)(elem, pqueue->slots[parentpos]) < 0 )
1416 {
1417 assert((*pqueue->ptrcomp)(pqueue->slots[parentpos], elem) >= 0);
1418 pqueueElemChgPos(pqueue, pqueue->slots[parentpos], parentpos, pos);
1419
1420 pos = parentpos;
1421 parentpos = PQ_PARENT(pos);
1422 }
1423
1424 /* insert element at the found position */
1425 pqueueElemChgPos(pqueue, elem, -1, pos);
1426
1427#ifdef SCIP_MORE_DEBUG
1428 assert(pqueueHasHeapProperty(pqueue));
1429#endif
1430
1431 return SCIP_OKAY;
1432}
1433
1434
1435/** delete element at specified position, maintaining the heap property */
1437 SCIP_PQUEUE* pqueue, /**< priority queue */
1438 int pos /**< position of element that should be deleted */
1439 )
1440{
1441 void* last;
1442
1443 assert(pqueue != NULL);
1444 assert(pos >= 0);
1445 assert(pos < SCIPpqueueNElems(pqueue));
1446
1447 /* remove element at specified position of the tree, move the better child to its parents position until the last element
1448 * of the queue could be placed in the empty slot
1449 */
1450 pqueue->len--;
1451
1452 /* everything in place */
1453 if( pos == pqueue->len )
1454 return;
1455
1456 last = pqueue->slots[pqueue->len];
1457
1458 /* last element is brought to pos. it may now violate the heap property compared to its parent, or to its children.
1459 * In the first case, move it up, otherwise, move it down.
1460 */
1461 while( pos > 0 && (*pqueue->ptrcomp)(last, pqueue->slots[PQ_PARENT(pos)]) < 0 )
1462 {
1463 pqueueElemChgPos(pqueue, pqueue->slots[PQ_PARENT(pos)], PQ_PARENT(pos), pos);
1464 pos = PQ_PARENT(pos);
1465 }
1466
1467 while( pos <= PQ_PARENT(pqueue->len-1) )
1468 {
1469 int childpos = PQ_LEFTCHILD(pos);
1470 int brotherpos = PQ_RIGHTCHILD(pos);
1471
1472 /* determine better of the two children */
1473 if( brotherpos < pqueue->len && (*pqueue->ptrcomp)(pqueue->slots[brotherpos], pqueue->slots[childpos]) < 0 )
1474 childpos = brotherpos;
1475
1476 if( (*pqueue->ptrcomp)(last, pqueue->slots[childpos]) <= 0 )
1477 break;
1478
1479 /* move better element from childpos to pos */
1480 pqueueElemChgPos(pqueue, pqueue->slots[childpos], childpos, pos);
1481
1482 pos = childpos;
1483 }
1484
1485 /* pos must point into a valid position */
1486 assert(pos <= pqueue->len - 1);
1487
1488 pqueueElemChgPos(pqueue, last, pqueue->len, pos);
1489
1490#ifdef SCIP_MORE_DEBUG
1491 assert(pqueueHasHeapProperty(pqueue));
1492#endif
1493}
1494
1495/** removes and returns best element from the priority queue */
1497 SCIP_PQUEUE* pqueue /**< priority queue */
1498 )
1499{
1500 void* root;
1501
1502 assert(pqueue != NULL);
1503 assert(pqueue->len >= 0);
1504
1505 if( pqueue->len == 0 )
1506 return NULL;
1507
1508 root = pqueue->slots[0];
1509
1510 SCIPpqueueDelPos(pqueue, 0);
1511
1512 return root;
1513}
1514
1515/** returns the best element of the queue without removing it */
1517 SCIP_PQUEUE* pqueue /**< priority queue */
1518 )
1519{
1520 assert(pqueue != NULL);
1521 assert(pqueue->len >= 0);
1522
1523 if( pqueue->len == 0 )
1524 return NULL;
1525
1526 return pqueue->slots[0];
1527}
1528
1529/** returns the number of elements in the queue */
1531 SCIP_PQUEUE* pqueue /**< priority queue */
1532 )
1533{
1534 assert(pqueue != NULL);
1535 assert(pqueue->len >= 0);
1536
1537 return pqueue->len;
1538}
1539
1540/** returns the elements of the queue; changing the returned array may destroy the queue's ordering! */
1542 SCIP_PQUEUE* pqueue /**< priority queue */
1543 )
1544{
1545 assert(pqueue != NULL);
1546 assert(pqueue->len >= 0);
1547
1548 return pqueue->slots;
1549}
1550
1551/** return the position of @p elem in the priority queue, or -1 if element is not found */
1553 SCIP_PQUEUE* pqueue, /**< priority queue */
1554 void* elem /**< element to be inserted */
1555 )
1556{
1557 int pos = -1;
1558
1559 while( ++pos < SCIPpqueueNElems(pqueue) )
1560 {
1561 if( pqueue->slots[pos] == elem )
1562 return pos;
1563 }
1564
1565 return -1;
1566}
1567
1568
1569
1570
1571/*
1572 * Hash Table
1573 */
1574
1575/** table of some prime numbers */
1576static int primetable[] = {
1577 2,
1578 7,
1579 19,
1580 31,
1581 59,
1582 227,
1583 617,
1584 1523,
1585 3547,
1586 8011,
1587 17707,
1588 38723,
1589 83833,
1590 180317,
1591 385897,
1592 821411,
1593 1742369,
1594 3680893,
1595 5693959,
1596 7753849,
1597 9849703,
1598 11973277,
1599 14121853,
1600 17643961,
1601 24273817,
1602 32452843,
1603 49979687,
1604 67867967,
1605 86028121,
1606 104395301,
1607 122949823,
1608 141650939,
1609 160481183,
1610 179424673,
1611 198491317,
1612 217645177,
1613 256203161,
1614 314606869,
1615 373587883,
1616 433024223,
1617 492876847,
1618 553105243,
1619 613651349,
1620 694847533,
1621 756065159,
1622 817504243,
1623 879190747,
1624 941083981,
1625 982451653,
1626 INT_MAX
1627};
1628static const int primetablesize = sizeof(primetable)/sizeof(int);
1629
1630/** simple and fast 2-universal hash function using multiply and shift */
1631static
1632uint32_t hashvalue(
1633 uint64_t input /**< key value */
1634 )
1635{
1636 return ( (uint32_t) ((UINT64_C(0x9e3779b97f4a7c15) * input)>>32) ) | 1u;
1637}
1638
1639/** returns a reasonable hash table size (a prime number) that is at least as large as the specified value */
1641 int minsize /**< minimal size of the hash table */
1642 )
1643{
1644 int pos;
1645
1646 (void) SCIPsortedvecFindInt(primetable, minsize, primetablesize, &pos);
1647 assert(0 <= pos && pos < primetablesize);
1648
1649 return primetable[pos];
1650}
1651
1652/** appends element to the multihash list */
1653static
1655 SCIP_MULTIHASHLIST** multihashlist, /**< pointer to hash list */
1656 BMS_BLKMEM* blkmem, /**< block memory */
1657 void* element /**< element to append to the list */
1658 )
1659{
1660 SCIP_MULTIHASHLIST* newlist;
1661
1662 assert(multihashlist != NULL);
1663 assert(blkmem != NULL);
1664 assert(element != NULL);
1665
1666 SCIP_ALLOC( BMSallocBlockMemory(blkmem, &newlist) );
1667 newlist->element = element;
1668 newlist->next = *multihashlist;
1669 *multihashlist = newlist;
1670
1671 return SCIP_OKAY;
1672}
1673
1674/** frees a multihash list entry and all its successors */
1675static
1677 SCIP_MULTIHASHLIST** multihashlist, /**< pointer to multihash list to free */
1678 BMS_BLKMEM* blkmem /**< block memory */
1679 )
1680{
1681 SCIP_MULTIHASHLIST* list;
1682 SCIP_MULTIHASHLIST* nextlist;
1683
1684 assert(multihashlist != NULL);
1685 assert(blkmem != NULL);
1686
1687 list = *multihashlist;
1688 while( list != NULL )
1689 {
1690 nextlist = list->next;
1691 BMSfreeBlockMemory(blkmem, &list);
1692 list = nextlist;
1693 }
1694
1695 *multihashlist = NULL;
1696}
1697
1698/** finds multihash list entry pointing to element with given key in the multihash list, returns NULL if not found */
1699static
1701 SCIP_MULTIHASHLIST* multihashlist, /**< multihash list */
1702 SCIP_DECL_HASHGETKEY((*hashgetkey)), /**< gets the key of the given element */
1703 SCIP_DECL_HASHKEYEQ ((*hashkeyeq)), /**< returns TRUE iff both keys are equal */
1704 SCIP_DECL_HASHKEYVAL((*hashkeyval)), /**< returns the hash value of the key */
1705 void* userptr, /**< user pointer */
1706 uint64_t keyval, /**< hash value of key */
1707 void* key /**< key to retrieve */
1708 )
1709{
1710 uint64_t currentkeyval;
1711 void* currentkey;
1712
1713 assert(hashkeyeq != NULL);
1714 assert(key != NULL);
1715
1716 while( multihashlist != NULL )
1717 {
1718 currentkey = hashgetkey(userptr, multihashlist->element);
1719 currentkeyval = hashkeyval(userptr, currentkey);
1720 if( currentkeyval == keyval && hashkeyeq(userptr, currentkey, key) )
1721 return multihashlist;
1722
1723 multihashlist = multihashlist->next;
1724 }
1725
1726 return NULL;
1727}
1728
1729/** retrieves element with given key from the multihash list, or NULL */
1730static
1732 SCIP_MULTIHASHLIST* multihashlist, /**< hash list */
1733 SCIP_DECL_HASHGETKEY((*hashgetkey)), /**< gets the key of the given element */
1734 SCIP_DECL_HASHKEYEQ ((*hashkeyeq)), /**< returns TRUE iff both keys are equal */
1735 SCIP_DECL_HASHKEYVAL((*hashkeyval)), /**< returns the hash value of the key */
1736 void* userptr, /**< user pointer */
1737 uint64_t keyval, /**< hash value of key */
1738 void* key /**< key to retrieve */
1739 )
1740{
1742
1743 /* find hash list entry */
1744 h = multihashlistFind(multihashlist, hashgetkey, hashkeyeq, hashkeyval, userptr, keyval, key);
1745
1746 /* return element */
1747 if( h != NULL )
1748 {
1749#ifndef NDEBUG
1751
1752 h2 = multihashlistFind(h->next, hashgetkey, hashkeyeq, hashkeyval, userptr, keyval, key);
1753
1754 if( h2 != NULL )
1755 {
1756 void* key1;
1757 void* key2;
1758
1759 key1 = hashgetkey(userptr, h->element);
1760 key2 = hashgetkey(userptr, h2->element);
1761 assert(hashkeyval(userptr, key1) == hashkeyval(userptr, key2));
1762
1763 if( hashkeyeq(userptr, key1, key2) )
1764 {
1765 SCIPerrorMessage("WARNING: hashkey with same value exists multiple times (e.g. duplicate constraint/variable names), so the return value is maybe not correct\n");
1766 }
1767 }
1768#endif
1769
1770 return h->element;
1771 }
1772 else
1773 return NULL;
1774}
1775
1776
1777/** retrieves element with given key from the multihash list, or NULL
1778 * returns pointer to multihash table list entry
1779 */
1780static
1782 SCIP_MULTIHASHLIST** multihashlist, /**< on input: hash list to search; on exit: hash list entry corresponding
1783 * to element after retrieved one, or NULL */
1784 SCIP_DECL_HASHGETKEY((*hashgetkey)), /**< gets the key of the given element */
1785 SCIP_DECL_HASHKEYEQ ((*hashkeyeq)), /**< returns TRUE iff both keys are equal */
1786 SCIP_DECL_HASHKEYVAL((*hashkeyval)), /**< returns the hash value of the key */
1787 void* userptr, /**< user pointer */
1788 uint64_t keyval, /**< hash value of key */
1789 void* key /**< key to retrieve */
1790 )
1791{
1793
1794 assert(multihashlist != NULL);
1795
1796 /* find hash list entry */
1797 h = multihashlistFind(*multihashlist, hashgetkey, hashkeyeq, hashkeyval, userptr, keyval, key);
1798
1799 /* return element */
1800 if( h != NULL )
1801 {
1802 *multihashlist = h->next;
1803
1804 return h->element;
1805 }
1806
1807 *multihashlist = NULL;
1808
1809 return NULL;
1810}
1811
1812/** removes element from the multihash list */
1813static
1815 SCIP_MULTIHASHLIST** multihashlist, /**< pointer to hash list */
1816 BMS_BLKMEM* blkmem, /**< block memory */
1817 void* element /**< element to remove from the list */
1818 )
1819{
1820 SCIP_MULTIHASHLIST* nextlist;
1821
1822 assert(multihashlist != NULL);
1823 assert(blkmem != NULL);
1824 assert(element != NULL);
1825
1826 while( *multihashlist != NULL && (*multihashlist)->element != element )
1827 multihashlist = &(*multihashlist)->next;
1828
1829 if( *multihashlist != NULL )
1830 {
1831 nextlist = (*multihashlist)->next;
1832 BMSfreeBlockMemory(blkmem, multihashlist);
1833 *multihashlist = nextlist;
1834
1835 return TRUE;
1836 }
1837
1838 return FALSE;
1839}
1840
1841#define SCIP_MULTIHASH_MAXSIZE 33554431 /* 2^25 - 1*/
1842#define SCIP_MULTIHASH_RESIZE_PERCENTAGE 65
1843#define SCIP_MULTIHASH_GROW_FACTOR 1.31
1844
1845/** resizing(increasing) the given multihash */
1846static
1848 SCIP_MULTIHASH* multihash /**< hash table */
1849 )
1850{
1851 SCIP_MULTIHASHLIST** newlists;
1852 SCIP_MULTIHASHLIST* multihashlist;
1853 SCIP_Longint nelements;
1854 int nnewlists;
1855 int l;
1856
1857 assert(multihash != NULL);
1858 assert(multihash->lists != NULL);
1859 assert(multihash->nlists > 0);
1860 assert(multihash->hashgetkey != NULL);
1861 assert(multihash->hashkeyeq != NULL);
1862 assert(multihash->hashkeyval != NULL);
1863
1864 /* get new memeory for hash table lists */
1865 nnewlists = (int) MIN((unsigned int)(multihash->nlists * SCIP_MULTIHASH_GROW_FACTOR), SCIP_MULTIHASH_MAXSIZE);
1866 nnewlists = MAX(nnewlists, multihash->nlists);
1867
1868 SCIPdebugMessage("load = %g, nelements = %" SCIP_LONGINT_FORMAT ", nlists = %d, nnewlist = %d\n", SCIPmultihashGetLoad(multihash), multihash->nelements, multihash->nlists, nnewlists);
1869
1870 if( nnewlists > multihash->nlists )
1871 {
1872 SCIP_Bool onlyone;
1873 void* key;
1874 uint64_t keyval;
1875 unsigned int hashval;
1876
1877 SCIP_ALLOC( BMSallocClearBlockMemoryArray(multihash->blkmem, &newlists, nnewlists) );
1878
1879 /* move all lists */
1880 for( l = multihash->nlists - 1; l >= 0; --l )
1881 {
1882 multihashlist = multihash->lists[l];
1883 onlyone = TRUE;
1884
1885 /* move all elements frmm the old lists into the new lists */
1886 while( multihashlist != NULL )
1887 {
1888 /* get the hash key and its hash value */
1889 key = multihash->hashgetkey(multihash->userptr, multihashlist->element);
1890 keyval = multihash->hashkeyval(multihash->userptr, key);
1891 hashval = (unsigned int) (keyval % (unsigned) nnewlists); /*lint !e573*/
1892
1893 /* if the old hash table list consists of only one entry, we still can use this old memory block instead
1894 * of creating a new one
1895 */
1896 if( multihashlist->next == NULL && onlyone )
1897 {
1898 /* the new list is also empty, we can directly copy the entry */
1899 if( newlists[hashval] == NULL )
1900 newlists[hashval] = multihashlist;
1901 /* the new list is not empty, so we need to find the first empty spot */
1902 else
1903 {
1904 SCIP_MULTIHASHLIST* lastnext = newlists[hashval];
1905 SCIP_MULTIHASHLIST* next = lastnext->next;
1906
1907 while( next != NULL )
1908 {
1909 lastnext = next;
1910 next = next->next;
1911 }
1912
1913 lastnext->next = multihashlist;
1914 }
1915
1916 multihash->lists[l] = NULL;
1917 }
1918 else
1919 {
1920 /* append old element to the list at the hash position */
1921 SCIP_CALL( multihashlistAppend(&(newlists[hashval]), multihash->blkmem, multihashlist->element) );
1922 }
1923
1924 onlyone = FALSE;
1925 multihashlist = multihashlist->next;
1926 }
1927 }
1928
1929 /* remember number of elements */
1930 nelements = multihash->nelements;
1931 /* clear old lists */
1932 SCIPmultihashRemoveAll(multihash);
1933 /* free old lists */
1934 BMSfreeBlockMemoryArray(multihash->blkmem, &(multihash->lists), multihash->nlists);
1935
1936 /* set new data */
1937 multihash->lists = newlists;
1938 multihash->nlists = nnewlists;
1939 multihash->nelements = nelements;
1940
1941#ifdef SCIP_MORE_DEBUG
1942 {
1943 SCIP_Longint sumslotsize = 0;
1944
1945 for( l = 0; l < multihash->nlists; ++l )
1946 {
1947 multihashlist = multihash->lists[l];
1948 while( multihashlist != NULL )
1949 {
1950 sumslotsize++;
1951 multihashlist = multihashlist->next;
1952 }
1953 }
1954 assert(sumslotsize == multihash->nelements);
1955 }
1956#endif
1957 }
1958
1959 return SCIP_OKAY;
1960}
1961
1962/** creates a multihash table */
1964 SCIP_MULTIHASH** multihash, /**< pointer to store the created multihash table */
1965 BMS_BLKMEM* blkmem, /**< block memory used to store multihash table entries */
1966 int tablesize, /**< size of the hash table */
1967 SCIP_DECL_HASHGETKEY((*hashgetkey)), /**< gets the key of the given element */
1968 SCIP_DECL_HASHKEYEQ ((*hashkeyeq)), /**< returns TRUE iff both keys are equal */
1969 SCIP_DECL_HASHKEYVAL((*hashkeyval)), /**< returns the hash value of the key */
1970 void* userptr /**< user pointer */
1971 )
1972{
1973 /* only assert non negative to catch overflow errors
1974 * but not zeros due to integer divison
1975 */
1976 assert(tablesize >= 0);
1977 assert(multihash != NULL);
1978 assert(hashgetkey != NULL);
1979 assert(hashkeyeq != NULL);
1980 assert(hashkeyval != NULL);
1981
1982 SCIP_ALLOC( BMSallocBlockMemory(blkmem, multihash) );
1983 SCIP_ALLOC( BMSallocClearBlockMemoryArray(blkmem, &(*multihash)->lists, tablesize) );
1984 (*multihash)->blkmem = blkmem;
1985 (*multihash)->nlists = tablesize;
1986 (*multihash)->hashgetkey = hashgetkey;
1987 (*multihash)->hashkeyeq = hashkeyeq;
1988 (*multihash)->hashkeyval = hashkeyval;
1989 (*multihash)->userptr = userptr;
1990 (*multihash)->nelements = 0;
1991
1992 return SCIP_OKAY;
1993}
1994
1995/** frees the multihash table */
1997 SCIP_MULTIHASH** multihash /**< pointer to the multihash table */
1998 )
1999{
2000 int i;
2001 SCIP_MULTIHASH* table;
2002 BMS_BLKMEM* blkmem;
2003 SCIP_MULTIHASHLIST** lists;
2004
2005 assert(multihash != NULL);
2006 assert(*multihash != NULL);
2007
2008 table = (*multihash);
2009 blkmem = table->blkmem;
2010 lists = table->lists;
2011
2012 /* free hash lists */
2013 for( i = table->nlists - 1; i >= 0; --i )
2014 multihashlistFree(&lists[i], blkmem);
2015
2016 /* free main hash table data structure */
2017 BMSfreeBlockMemoryArray(blkmem, &table->lists, table->nlists);
2018 BMSfreeBlockMemory(blkmem, multihash);
2019}
2020
2021
2022/** inserts element in multihash table (multiple inserts of same element possible)
2023 *
2024 * @note A pointer to a multihashlist returned by SCIPmultihashRetrieveNext() might get invalid when adding an element
2025 * to the hash table, due to dynamic resizing.
2026 */
2028 SCIP_MULTIHASH* multihash, /**< multihash table */
2029 void* element /**< element to insert into the table */
2030 )
2031{
2032 void* key;
2033 uint64_t keyval;
2034 unsigned int hashval;
2035
2036 assert(multihash != NULL);
2037 assert(multihash->lists != NULL);
2038 assert(multihash->nlists > 0);
2039 assert(multihash->hashgetkey != NULL);
2040 assert(multihash->hashkeyeq != NULL);
2041 assert(multihash->hashkeyval != NULL);
2042 assert(element != NULL);
2043
2044 /* dynamically resizing the hashtables */
2046 {
2047 SCIP_CALL( multihashResize(multihash) );
2048 }
2049
2050 /* get the hash key and its hash value */
2051 key = multihash->hashgetkey(multihash->userptr, element);
2052 keyval = multihash->hashkeyval(multihash->userptr, key);
2053 hashval = (unsigned int) (keyval % (unsigned) multihash->nlists); /*lint !e573*/
2054
2055 /* append element to the list at the hash position */
2056 SCIP_CALL( multihashlistAppend(&multihash->lists[hashval], multihash->blkmem, element) );
2057
2058 ++(multihash->nelements);
2059
2060 return SCIP_OKAY;
2061}
2062
2063/** inserts element in multihash table (multiple insertion of same element is checked and results in an error)
2064 *
2065 * @note A pointer to a multihashlist returned by SCIPmultihashRetrieveNext() might get invalid when adding a new
2066 * element to the multihash table, due to dynamic resizing.
2067 */
2069 SCIP_MULTIHASH* multihash, /**< multihash table */
2070 void* element /**< element to insert into the table */
2071 )
2072{
2073 assert(multihash != NULL);
2074 assert(multihash->hashgetkey != NULL);
2075
2076 /* check, if key is already existing */
2077 if( SCIPmultihashRetrieve(multihash, multihash->hashgetkey(multihash->userptr, element)) != NULL )
2079
2080 /* insert element in hash table */
2081 SCIP_CALL( SCIPmultihashInsert(multihash, element) );
2082
2083 return SCIP_OKAY;
2084}
2085
2086/** retrieve element with key from multihash table, returns NULL if not existing */
2088 SCIP_MULTIHASH* multihash, /**< multihash table */
2089 void* key /**< key to retrieve */
2090 )
2091{
2092 uint64_t keyval;
2093 unsigned int hashval;
2094
2095 assert(multihash != NULL);
2096 assert(multihash->lists != NULL);
2097 assert(multihash->nlists > 0);
2098 assert(multihash->hashgetkey != NULL);
2099 assert(multihash->hashkeyeq != NULL);
2100 assert(multihash->hashkeyval != NULL);
2101 assert(key != NULL);
2102
2103 /* get the hash value of the key */
2104 keyval = multihash->hashkeyval(multihash->userptr, key);
2105 hashval = (unsigned int) (keyval % (unsigned) multihash->nlists); /*lint !e573*/
2106
2107 return multihashlistRetrieve(multihash->lists[hashval], multihash->hashgetkey, multihash->hashkeyeq,
2108 multihash->hashkeyval, multihash->userptr, keyval, key);
2109}
2110
2111/** retrieve element with key from multihash table, returns NULL if not existing
2112 * can be used to retrieve all entries with the same key (one-by-one)
2113 *
2114 * @note The returned multimultihashlist pointer might get invalid when adding a new element to the multihash table.
2115 */
2117 SCIP_MULTIHASH* multihash, /**< multihash table */
2118 SCIP_MULTIHASHLIST** multihashlist, /**< input: entry in hash table list from which to start searching, or NULL
2119 * output: entry in hash table list corresponding to element after
2120 * retrieved one, or NULL */
2121 void* key /**< key to retrieve */
2122 )
2123{
2124 uint64_t keyval;
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(multihashlist != NULL);
2133 assert(key != NULL);
2134
2135 keyval = multihash->hashkeyval(multihash->userptr, key);
2136
2137 if( *multihashlist == NULL )
2138 {
2139 unsigned int hashval;
2140
2141 /* get the hash value of the key */
2142 hashval = (unsigned int) (keyval % (unsigned) multihash->nlists); /*lint !e573*/
2143
2144 *multihashlist = multihash->lists[hashval];
2145 }
2146
2147 return multihashlistRetrieveNext(multihashlist, multihash->hashgetkey, multihash->hashkeyeq,
2148 multihash->hashkeyval, multihash->userptr, keyval, key);
2149}
2150
2151/** returns whether the given element exists in the multihash table */
2153 SCIP_MULTIHASH* multihash, /**< multihash table */
2154 void* element /**< element to search in the table */
2155 )
2156{
2157 void* key;
2158 uint64_t keyval;
2159 unsigned int hashval;
2160
2161 assert(multihash != NULL);
2162 assert(multihash->lists != NULL);
2163 assert(multihash->nlists > 0);
2164 assert(multihash->hashgetkey != NULL);
2165 assert(multihash->hashkeyeq != NULL);
2166 assert(multihash->hashkeyval != NULL);
2167 assert(element != NULL);
2168
2169 /* get the hash key and its hash value */
2170 key = multihash->hashgetkey(multihash->userptr, element);
2171 keyval = multihash->hashkeyval(multihash->userptr, key);
2172 hashval = (unsigned int) (keyval % (unsigned) multihash->nlists); /*lint !e573*/
2173
2174 return (multihashlistFind(multihash->lists[hashval], multihash->hashgetkey, multihash->hashkeyeq,
2175 multihash->hashkeyval, multihash->userptr, keyval, key) != NULL);
2176}
2177
2178/** removes element from the multihash table, if it exists */
2180 SCIP_MULTIHASH* multihash, /**< multihash table */
2181 void* element /**< element to remove from the table */
2182 )
2183{
2184 void* key;
2185 uint64_t keyval;
2186 unsigned int hashval;
2187
2188 assert(multihash != NULL);
2189 assert(multihash->lists != NULL);
2190 assert(multihash->nlists > 0);
2191 assert(multihash->hashgetkey != NULL);
2192 assert(multihash->hashkeyeq != NULL);
2193 assert(multihash->hashkeyval != NULL);
2194 assert(element != NULL);
2195
2196 /* get the hash key and its hash value */
2197 key = multihash->hashgetkey(multihash->userptr, element);
2198 keyval = multihash->hashkeyval(multihash->userptr, key);
2199 hashval = (unsigned int) (keyval % (unsigned) multihash->nlists); /*lint !e573*/
2200
2201 /* remove element from the list at the hash position */
2202 if( multihashlistRemove(&multihash->lists[hashval], multihash->blkmem, element) )
2203 --(multihash->nelements);
2204
2205 return SCIP_OKAY;
2206}
2207
2208/** removes all elements of the multihash table
2209 *
2210 * @note From a performance point of view you should not fill and clear a hash table too often since the clearing can
2211 * be expensive. Clearing is done by looping over all buckets and removing the hash table lists one-by-one.
2212 */
2214 SCIP_MULTIHASH* multihash /**< multihash table */
2215 )
2216{
2217 BMS_BLKMEM* blkmem;
2218 SCIP_MULTIHASHLIST** lists;
2219 int i;
2220
2221 assert(multihash != NULL);
2222
2223 blkmem = multihash->blkmem;
2224 lists = multihash->lists;
2225
2226 /* free hash lists */
2227 for( i = multihash->nlists - 1; i >= 0; --i )
2228 multihashlistFree(&lists[i], blkmem);
2229
2230 multihash->nelements = 0;
2231}
2232
2233/** returns number of multihash table elements */
2235 SCIP_MULTIHASH* multihash /**< multihash table */
2236 )
2237{
2238 assert(multihash != NULL);
2239
2240 return multihash->nelements;
2241}
2242
2243/** returns the load of the given multihash table in percentage */
2245 SCIP_MULTIHASH* multihash /**< multihash table */
2246 )
2247{
2248 assert(multihash != NULL);
2249
2250 return ((SCIP_Real)(multihash->nelements) / (multihash->nlists) * 100.0);
2251}
2252
2253/** prints statistics about multihash table usage */
2255 SCIP_MULTIHASH* multihash, /**< multihash table */
2256 SCIP_MESSAGEHDLR* messagehdlr /**< message handler */
2257 )
2258{
2259 SCIP_MULTIHASHLIST* multihashlist;
2260 int usedslots;
2261 int maxslotsize;
2262 int sumslotsize;
2263 int slotsize;
2264 int i;
2265
2266 assert(multihash != NULL);
2267
2268 usedslots = 0;
2269 maxslotsize = 0;
2270 sumslotsize = 0;
2271 for( i = 0; i < multihash->nlists; ++i )
2272 {
2273 multihashlist = multihash->lists[i];
2274 if( multihashlist != NULL )
2275 {
2276 usedslots++;
2277 slotsize = 0;
2278 while( multihashlist != NULL )
2279 {
2280 slotsize++;
2281 multihashlist = multihashlist->next;
2282 }
2283 maxslotsize = MAX(maxslotsize, slotsize);
2284 sumslotsize += slotsize;
2285 }
2286 }
2287 assert(sumslotsize == multihash->nelements);
2288 SCIP_UNUSED(sumslotsize);
2289
2290 SCIPmessagePrintInfo(messagehdlr, "%" SCIP_LONGINT_FORMAT " multihash entries, used %d/%d slots (%.1f%%)",
2291 multihash->nelements, usedslots, multihash->nlists, 100.0*(SCIP_Real)usedslots/(SCIP_Real)(multihash->nlists));
2292 if( usedslots > 0 )
2293 SCIPmessagePrintInfo(messagehdlr, ", avg. %.1f entries/used slot, max. %d entries in slot",
2294 (SCIP_Real)(multihash->nelements)/(SCIP_Real)usedslots, maxslotsize);
2295 SCIPmessagePrintInfo(messagehdlr, "\n");
2296}
2297
2298/** creates a hash table */
2300 SCIP_HASHTABLE** hashtable, /**< pointer to store the created hash table */
2301 BMS_BLKMEM* blkmem, /**< block memory used to store hash table entries */
2302 int tablesize, /**< size of the hash table */
2303 SCIP_DECL_HASHGETKEY((*hashgetkey)), /**< gets the key of the given element */
2304 SCIP_DECL_HASHKEYEQ ((*hashkeyeq)), /**< returns TRUE iff both keys are equal */
2305 SCIP_DECL_HASHKEYVAL((*hashkeyval)), /**< returns the hash value of the key */
2306 void* userptr /**< user pointer */
2307 )
2308{
2309 unsigned int nslots;
2310
2311 /* only assert non negative to catch overflow errors
2312 * but not zeros due to integer divison
2313 */
2314 assert(tablesize >= 0);
2315 assert(hashtable != NULL);
2316 assert(hashgetkey != NULL);
2317 assert(hashkeyeq != NULL);
2318 assert(hashkeyval != NULL);
2319 assert(blkmem != NULL);
2320
2321 SCIP_ALLOC( BMSallocBlockMemory(blkmem, hashtable) );
2322
2323 /* dont create too small hashtables, i.e. at least size 32, and increase
2324 * the given size by divinding it by 0.9, since then no rebuilding will
2325 * be necessary if the given number of elements are inserted. Finally round
2326 * to the next power of two.
2327 */
2328 (*hashtable)->shift = 32;
2329 (*hashtable)->shift -= (unsigned int)ceil(LOG2(MAX(32.0, tablesize / 0.9)));
2330
2331 /* compute size from shift */
2332 nslots = 1u << (32 - (*hashtable)->shift);
2333
2334 /* compute mask to do a fast modulo by nslots using bitwise and */
2335 (*hashtable)->mask = nslots - 1;
2336 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*hashtable)->slots, nslots) );
2337 SCIP_ALLOC( BMSallocClearBlockMemoryArray(blkmem, &(*hashtable)->hashes, nslots) );
2338 (*hashtable)->blkmem = blkmem;
2339 (*hashtable)->hashgetkey = hashgetkey;
2340 (*hashtable)->hashkeyeq = hashkeyeq;
2341 (*hashtable)->hashkeyval = hashkeyval;
2342 (*hashtable)->userptr = userptr;
2343 (*hashtable)->nelements = 0;
2344
2345 return SCIP_OKAY;
2346}
2347
2348/** frees the hash table */
2350 SCIP_HASHTABLE** hashtable /**< pointer to the hash table */
2351 )
2352{
2353 uint32_t nslots;
2354 SCIP_HASHTABLE* table;
2355
2356 assert(hashtable != NULL);
2357 assert(*hashtable != NULL);
2358 table = *hashtable;
2359 nslots = (*hashtable)->mask + 1;
2360#ifdef SCIP_DEBUG
2361 {
2362 uint32_t maxprobelen = 0;
2363 uint64_t probelensum = 0;
2364 uint32_t i;
2365
2366 assert(table != NULL);
2367
2368 for( i = 0; i < nslots; ++i )
2369 {
2370 if( table->hashes[i] != 0 )
2371 {
2372 uint32_t probelen = ((i + table->mask + 1 - (table->hashes[i]>>(table->shift))) & table->mask) + 1;
2373 probelensum += probelen;
2374 maxprobelen = MAX(probelen, maxprobelen);
2375 }
2376 }
2377
2378 SCIPdebugMessage("%u hash table entries, used %u/%u slots (%.1f%%)",
2379 (unsigned int)table->nelements, (unsigned int)table->nelements, (unsigned int)nslots,
2380 100.0*(SCIP_Real)table->nelements/(SCIP_Real)(nslots));
2381 if( table->nelements > 0 )
2382 SCIPdebugMessage(", avg. probe length is %.1f, max. probe length is %u",
2383 (SCIP_Real)(probelensum)/(SCIP_Real)table->nelements, (unsigned int)maxprobelen);
2384 SCIPdebugMessage("\n");
2385 }
2386#endif
2387
2388 /* free main hash table data structure */
2389 BMSfreeBlockMemoryArray((*hashtable)->blkmem, &table->hashes, nslots);
2390 BMSfreeBlockMemoryArray((*hashtable)->blkmem, &table->slots, nslots);
2391 BMSfreeBlockMemory((*hashtable)->blkmem, hashtable);
2392}
2393
2394/** removes all elements of the hash table
2395 *
2396 * @note From a performance point of view you should not fill and clear a hash table too often since the clearing can
2397 * be expensive. Clearing is done by looping over all buckets and removing the hash table lists one-by-one.
2398 *
2399 * @deprecated Please use SCIPhashtableRemoveAll()
2400 */
2402 SCIP_HASHTABLE* hashtable /**< hash table */
2403 )
2404{
2405 SCIPhashtableRemoveAll(hashtable);
2406}
2407
2408/* computes the distance from it's desired position for the element stored at pos */
2409#define ELEM_DISTANCE(pos) (((pos) + hashtable->mask + 1 - (hashtable->hashes[(pos)]>>(hashtable->shift))) & hashtable->mask)
2410
2411/** inserts element in hash table (multiple inserts of same element overrides previous one) */
2412static
2414 SCIP_HASHTABLE* hashtable, /**< hash table */
2415 void* element, /**< element to insert into the table */
2416 void* key, /**< key of element */
2417 uint32_t hashval, /**< hash value of element */
2418 SCIP_Bool override /**< should element be overridden or an error be returned if already existing */
2419 )
2420{
2421 uint32_t elemdistance;
2422 uint32_t pos;
2423#ifndef NDEBUG
2424 SCIP_Bool swapped = FALSE;
2425#endif
2426
2427 assert(hashtable != NULL);
2428 assert(hashtable->slots != NULL);
2429 assert(hashtable->hashes != NULL);
2430 assert(hashtable->mask > 0);
2431 assert(hashtable->hashgetkey != NULL);
2432 assert(hashtable->hashkeyeq != NULL);
2433 assert(hashtable->hashkeyval != NULL);
2434 assert(element != NULL);
2435
2436 pos = hashval>>(hashtable->shift);
2437 elemdistance = 0;
2438 while( TRUE ) /*lint !e716*/
2439 {
2440 uint32_t distance;
2441
2442 /* if position is empty or key equal insert element */
2443 if( hashtable->hashes[pos] == 0 )
2444 {
2445 hashtable->slots[pos] = element;
2446 hashtable->hashes[pos] = hashval;
2447 ++hashtable->nelements;
2448 return SCIP_OKAY;
2449 }
2450
2451 if( hashtable->hashes[pos] == hashval && hashtable->hashkeyeq(hashtable->userptr,
2452 hashtable->hashgetkey(hashtable->userptr, hashtable->slots[pos]), key) )
2453 {
2454 if( override )
2455 {
2456#ifndef NDEBUG
2457 assert(! swapped);
2458#endif
2459 hashtable->slots[pos] = element;
2460 hashtable->hashes[pos] = hashval;
2461 return SCIP_OKAY;
2462 }
2463 else
2464 {
2466 }
2467 }
2468
2469 /* otherwise check if the current element at this position is closer to its hashvalue */
2470 distance = ELEM_DISTANCE(pos);
2471 if( distance < elemdistance )
2472 {
2473 uint32_t tmp;
2474
2475 /* if this is the case we insert the new element here and find a new position for the old one */
2476 elemdistance = distance;
2477 SCIPswapPointers(&hashtable->slots[pos], &element);
2478 tmp = hashval;
2479 hashval = hashtable->hashes[pos];
2480 hashtable->hashes[pos] = tmp;
2481 key = hashtable->hashgetkey(hashtable->userptr, element);
2482
2483 /* after doing a swap the case that other elements are replaced must not happen anymore */
2484#ifndef NDEBUG
2485 swapped = TRUE;
2486#endif
2487 }
2488
2489 /* continue until we have found an empty position */
2490 pos = (pos + 1) & hashtable->mask;
2491 ++elemdistance;
2492 }
2493}
2494
2495/** check if the load factor of the hashtable is too high and rebuild if necessary */
2496static
2498 SCIP_HASHTABLE* hashtable /**< hash table */
2499 )
2500{
2501 assert(hashtable != NULL);
2502 assert(hashtable->shift < 32);
2503
2504 /* use integer arithmetic to approximately check if load factor is above 90% */
2505 if( ((((uint64_t)hashtable->nelements)<<10)>>(32-hashtable->shift) > 921) )
2506 {
2507 void** slots;
2508 uint32_t* hashes;
2509 uint32_t nslots;
2510 uint32_t newnslots;
2511 uint32_t i;
2512
2513 /* calculate new size (always power of two) */
2514 nslots = hashtable->mask + 1;
2515 newnslots = 2*nslots;
2516 hashtable->mask = newnslots-1;
2517 --hashtable->shift;
2518
2519 /* reallocate array */
2520 SCIP_ALLOC( BMSallocBlockMemoryArray(hashtable->blkmem, &slots, newnslots) );
2521 SCIP_ALLOC( BMSallocClearBlockMemoryArray(hashtable->blkmem, &hashes, newnslots) );
2522
2523 SCIPswapPointers((void**) &slots, (void**) &hashtable->slots);
2524 SCIPswapPointers((void**) &hashes, (void**) &hashtable->hashes);
2525 hashtable->nelements = 0;
2526
2527 /* reinsert all elements */
2528 for( i = 0; i < nslots; ++i )
2529 {
2530 /* using SCIP_CALL_ABORT since there are no allocations or duplicates
2531 * and thus no bad return codes when inserting the elements
2532 */
2533 if( hashes[i] != 0 )
2534 {
2535 SCIP_CALL_ABORT( hashtableInsert(hashtable, slots[i], hashtable->hashgetkey(hashtable->userptr, slots[i]), hashes[i], FALSE) );
2536 }
2537 }
2538 BMSfreeBlockMemoryArray(hashtable->blkmem, &hashes, nslots);
2539 BMSfreeBlockMemoryArray(hashtable->blkmem, &slots, nslots);
2540 }
2541
2542 return SCIP_OKAY;
2543}
2544
2545
2546/** inserts element in hash table
2547 *
2548 * @note multiple inserts of same element overrides previous one
2549 */
2551 SCIP_HASHTABLE* hashtable, /**< hash table */
2552 void* element /**< element to insert into the table */
2553 )
2554{
2555 void* key;
2556 uint64_t keyval;
2557 uint32_t hashval;
2558
2559 assert(hashtable != NULL);
2560 assert(hashtable->slots != NULL);
2561 assert(hashtable->hashes != NULL);
2562 assert(hashtable->mask > 0);
2563 assert(hashtable->hashgetkey != NULL);
2564 assert(hashtable->hashkeyeq != NULL);
2565 assert(hashtable->hashkeyval != NULL);
2566 assert(element != NULL);
2567
2568 SCIP_CALL( hashtableCheckLoad(hashtable) );
2569
2570 /* get the hash key and its hash value */
2571 key = hashtable->hashgetkey(hashtable->userptr, element);
2572 keyval = hashtable->hashkeyval(hashtable->userptr, key);
2573 hashval = hashvalue(keyval);
2574
2575 return hashtableInsert(hashtable, element, key, hashval, TRUE);
2576}
2577
2578/** inserts element in hash table
2579 *
2580 * @note multiple insertion of same element is checked and results in an error
2581 */
2583 SCIP_HASHTABLE* hashtable, /**< hash table */
2584 void* element /**< element to insert into the table */
2585 )
2586{
2587 void* key;
2588 uint64_t keyval;
2589 uint32_t hashval;
2590
2591 assert(hashtable != NULL);
2592 assert(hashtable->slots != NULL);
2593 assert(hashtable->hashes != NULL);
2594 assert(hashtable->mask > 0);
2595 assert(hashtable->hashgetkey != NULL);
2596 assert(hashtable->hashkeyeq != NULL);
2597 assert(hashtable->hashkeyval != NULL);
2598 assert(element != NULL);
2599
2600 SCIP_CALL( hashtableCheckLoad(hashtable) );
2601
2602 /* get the hash key and its hash value */
2603 key = hashtable->hashgetkey(hashtable->userptr, element);
2604 keyval = hashtable->hashkeyval(hashtable->userptr, key);
2605 hashval = hashvalue(keyval);
2606
2607 return hashtableInsert(hashtable, element, key, hashval, FALSE);
2608}
2609
2610/** retrieve element with key from hash table, returns NULL if not existing */
2612 SCIP_HASHTABLE* hashtable, /**< hash table */
2613 void* key /**< key to retrieve */
2614 )
2615{
2616 uint64_t keyval;
2617 uint32_t hashval;
2618 uint32_t pos;
2619 uint32_t elemdistance;
2620
2621 assert(hashtable != NULL);
2622 assert(hashtable->slots != NULL);
2623 assert(hashtable->hashes != NULL);
2624 assert(hashtable->mask > 0);
2625 assert(hashtable->hashgetkey != NULL);
2626 assert(hashtable->hashkeyeq != NULL);
2627 assert(hashtable->hashkeyval != NULL);
2628 assert(key != NULL);
2629
2630 /* get the hash value of the key */
2631 keyval = hashtable->hashkeyval(hashtable->userptr, key);
2632 hashval = hashvalue(keyval);
2633
2634 pos = hashval>>(hashtable->shift);
2635 elemdistance = 0;
2636
2637 while( TRUE ) /*lint !e716*/
2638 {
2639 uint32_t distance;
2640
2641 /* slots is empty so element cannot be contained */
2642 if( hashtable->hashes[pos] == 0 )
2643 return NULL;
2644
2645 distance = ELEM_DISTANCE(pos);
2646
2647 /* element cannot be contained since otherwise we would have swapped it with this one during insert */
2648 if( elemdistance > distance )
2649 return NULL;
2650
2651 /* found element */
2652 if( hashtable->hashes[pos] == hashval && hashtable->hashkeyeq(hashtable->userptr,
2653 hashtable->hashgetkey(hashtable->userptr, hashtable->slots[pos]), key) )
2654 return hashtable->slots[pos];
2655
2656 pos = (pos + 1) & hashtable->mask;
2657 ++elemdistance;
2658 }
2659}
2660
2661/** returns whether the given element exists in the table */
2663 SCIP_HASHTABLE* hashtable, /**< hash table */
2664 void* element /**< element to search in the table */
2665 )
2666{
2667 assert(hashtable != NULL);
2668 assert(hashtable->slots != NULL);
2669 assert(hashtable->hashes != NULL);
2670 assert(hashtable->mask > 0);
2671 assert(hashtable->hashgetkey != NULL);
2672 assert(hashtable->hashkeyeq != NULL);
2673 assert(hashtable->hashkeyval != NULL);
2674 assert(element != NULL);
2675
2676 return (SCIPhashtableRetrieve(hashtable, hashtable->hashgetkey(hashtable->userptr, element)) != NULL);
2677}
2678
2679/** removes element from the hash table, if it exists */
2681 SCIP_HASHTABLE* hashtable, /**< hash table */
2682 void* element /**< element to remove from the table */
2683 )
2684{
2685 void* key;
2686 uint64_t keyval;
2687 uint32_t hashval;
2688 uint32_t elemdistance;
2689 uint32_t distance;
2690 uint32_t pos;
2691
2692 assert(hashtable != NULL);
2693 assert(hashtable->slots != NULL);
2694 assert(hashtable->hashes != NULL);
2695 assert(hashtable->mask > 0);
2696 assert(hashtable->hashgetkey != NULL);
2697 assert(hashtable->hashkeyeq != NULL);
2698 assert(hashtable->hashkeyval != NULL);
2699 assert(element != NULL);
2700
2701 /* get the hash key and its hash value */
2702 key = hashtable->hashgetkey(hashtable->userptr, element);
2703 keyval = hashtable->hashkeyval(hashtable->userptr, key);
2704 hashval = hashvalue(keyval);
2705
2706 elemdistance = 0;
2707 pos = hashval>>(hashtable->shift);
2708 while( TRUE ) /*lint !e716*/
2709 {
2710 /* slots empty so element not contained */
2711 if( hashtable->hashes[pos] == 0 )
2712 return SCIP_OKAY;
2713
2714 distance = ELEM_DISTANCE(pos);
2715
2716 /* element can not be contained since otherwise we would have swapped it with this one */
2717 if( elemdistance > distance )
2718 return SCIP_OKAY;
2719
2720 if( hashtable->hashes[pos] == hashval && hashtable->hashkeyeq(hashtable->userptr,
2721 hashtable->hashgetkey(hashtable->userptr, hashtable->slots[pos]), key) )
2722 {
2723 /* element exists at pos so break out of loop */
2724 break;
2725 }
2726
2727 pos = (pos + 1) & hashtable->mask;
2728 ++elemdistance;
2729 }
2730
2731 /* remove element */
2732 hashtable->hashes[pos] = 0;
2733 --hashtable->nelements;
2734 while( TRUE ) /*lint !e716*/
2735 {
2736 uint32_t nextpos = (pos + 1) & hashtable->mask;
2737
2738 /* nothing to do since there is no chain that needs to be moved */
2739 if( hashtable->hashes[nextpos] == 0 )
2740 break;
2741
2742 /* check if the element is the start of a new chain and return if that is the case */
2743 if( (hashtable->hashes[nextpos]>>(hashtable->shift)) == nextpos )
2744 break;
2745
2746 /* element should be moved to the left and next element needs to be checked */
2747 hashtable->slots[pos] = hashtable->slots[nextpos];
2748 hashtable->hashes[pos] = hashtable->hashes[nextpos];
2749 hashtable->hashes[nextpos] = 0;
2750
2751 pos = nextpos;
2752 }
2753
2754 return SCIP_OKAY;
2755}
2756
2757/** removes all elements of the hash table */
2759 SCIP_HASHTABLE* hashtable /**< hash table */
2760 )
2761{
2762 assert(hashtable != NULL);
2763
2764 BMSclearMemoryArray(hashtable->hashes, hashtable->mask + 1);
2765
2766 hashtable->nelements = 0;
2767}
2768
2769/** returns number of hash table elements */
2771 SCIP_HASHTABLE* hashtable /**< hash table */
2772 )
2773{
2774 assert(hashtable != NULL);
2775
2776 return hashtable->nelements;
2777}
2778
2779/** gives the number of entries in the internal arrays of a hash table */
2781 SCIP_HASHTABLE* hashtable /**< hash table */
2782 )
2783{
2784 return (int) hashtable->mask + 1;
2785}
2786
2787/** gives the element at the given index or NULL if entry at that index has no element */
2789 SCIP_HASHTABLE* hashtable, /**< hash table */
2790 int entryidx /**< index of hash table entry */
2791 )
2792{
2793 return hashtable->hashes[entryidx] == 0 ? NULL : hashtable->slots[entryidx];
2794}
2795
2796/** returns the load of the given hash table in percentage */
2798 SCIP_HASHTABLE* hashtable /**< hash table */
2799 )
2800{
2801 assert(hashtable != NULL);
2802
2803 return ((SCIP_Real)(hashtable->nelements) / (hashtable->mask + 1) * 100.0);
2804}
2805
2806/** prints statistics about hash table usage */
2808 SCIP_HASHTABLE* hashtable, /**< hash table */
2809 SCIP_MESSAGEHDLR* messagehdlr /**< message handler */
2810 )
2811{
2812 uint32_t maxprobelen = 0;
2813 uint64_t probelensum = 0;
2814 uint32_t nslots;
2815 uint32_t i;
2816
2817 assert(hashtable != NULL);
2818
2819 nslots = hashtable->mask + 1;
2820
2821 /* compute the maximum and average probe length */
2822 for( i = 0; i < nslots; ++i )
2823 {
2824 if( hashtable->hashes[i] != 0 )
2825 {
2826 uint32_t probelen = ELEM_DISTANCE(i) + 1;
2827 probelensum += probelen;
2828 maxprobelen = MAX(probelen, maxprobelen);
2829 }
2830 }
2831
2832 /* print general hash table statistics */
2833 SCIPmessagePrintInfo(messagehdlr, "%u hash entries, used %u/%u slots (%.1f%%)",
2834 (unsigned int)hashtable->nelements, (unsigned int)hashtable->nelements,
2835 (unsigned int)nslots, 100.0*(SCIP_Real)hashtable->nelements/(SCIP_Real)(nslots));
2836
2837 /* if not empty print average and maximum probe length */
2838 if( hashtable->nelements > 0 )
2839 SCIPmessagePrintInfo(messagehdlr, ", avg. probe length is %.1f, max. probe length is %u",
2840 (SCIP_Real)(probelensum)/(SCIP_Real)hashtable->nelements, (unsigned int)maxprobelen);
2841 SCIPmessagePrintInfo(messagehdlr, "\n");
2842}
2843
2844/** returns TRUE iff both keys (i.e. strings) are equal */
2845SCIP_DECL_HASHKEYEQ(SCIPhashKeyEqString)
2846{ /*lint --e{715}*/
2847 const char* string1 = (const char*)key1;
2848 const char* string2 = (const char*)key2;
2849
2850 return (strcmp(string1, string2) == 0);
2851}
2852
2853/** returns the hash value of the key (i.e. string) */
2854SCIP_DECL_HASHKEYVAL(SCIPhashKeyValString)
2855{ /*lint --e{715}*/
2856 const char* str;
2857 uint64_t hash;
2858
2859 str = (const char*)key;
2860 hash = 37;
2861 while( *str != '\0' )
2862 {
2863 hash *= 11;
2864 hash += (unsigned int)(*str); /*lint !e571*/
2865 str++;
2866 }
2867
2868 return hash;
2869}
2870
2871
2872/** gets the element as the key */
2873SCIP_DECL_HASHGETKEY(SCIPhashGetKeyStandard)
2874{ /*lint --e{715}*/
2875 /* the key is the element itself */
2876 return elem;
2877}
2878
2879/** returns TRUE iff both keys(pointer) are equal */
2880SCIP_DECL_HASHKEYEQ(SCIPhashKeyEqPtr)
2881{ /*lint --e{715}*/
2882 return (key1 == key2);
2883}
2884
2885/** returns the hash value of the key */
2886SCIP_DECL_HASHKEYVAL(SCIPhashKeyValPtr)
2887{ /*lint --e{715}*/
2888 /* the key is used as the keyvalue too */
2889 return (uint64_t) (uintptr_t) key;
2890}
2891
2892
2893
2894/*
2895 * Hash Map
2896 */
2897
2898/* redefine ELEM_DISTANCE macro for hashmap */
2899#undef ELEM_DISTANCE
2900/* computes the distance from it's desired position for the element stored at pos */
2901#define ELEM_DISTANCE(pos) (((pos) + hashmap->mask + 1 - (hashmap->hashes[(pos)]>>(hashmap->shift))) & hashmap->mask)
2902
2903/** inserts element in hash table */
2904static
2906 SCIP_HASHMAP* hashmap, /**< hash map */
2907 void* origin, /**< element to insert into the table */
2908 SCIP_HASHMAPIMAGE image, /**< key of element */
2909 uint32_t hashval, /**< hash value of element */
2910 SCIP_Bool override /**< should element be overridden or error be returned if already existing */
2911 )
2912{
2913 uint32_t elemdistance;
2914 uint32_t pos;
2915
2916 assert(hashmap != NULL);
2917 assert(hashmap->slots != NULL);
2918 assert(hashmap->hashes != NULL);
2919 assert(hashmap->mask > 0);
2920 assert(hashval != 0);
2921
2922 pos = hashval>>(hashmap->shift);
2923 elemdistance = 0;
2924 while( TRUE ) /*lint !e716*/
2925 {
2926 uint32_t distance;
2927
2928 /* if position is empty or key equal insert element */
2929 if( hashmap->hashes[pos] == 0 )
2930 {
2931 hashmap->slots[pos].origin = origin;
2932 hashmap->slots[pos].image = image;
2933 hashmap->hashes[pos] = hashval;
2934 ++hashmap->nelements;
2935 return SCIP_OKAY;
2936 }
2937
2938 if( hashval == hashmap->hashes[pos] && origin == hashmap->slots[pos].origin )
2939 {
2940 if( override )
2941 {
2942 hashmap->slots[pos].origin = origin;
2943 hashmap->slots[pos].image = image;
2944 hashmap->hashes[pos] = hashval;
2945 return SCIP_OKAY;
2946 }
2947 else
2948 {
2950 }
2951 }
2952
2953 /* otherwise check if the current element at this position is closer to its hashvalue */
2954 distance = ELEM_DISTANCE(pos);
2955 if( distance < elemdistance )
2956 {
2958 uint32_t tmphash;
2959
2960 /* if this is the case we insert the new element here and find a new position for the old one */
2961 elemdistance = distance;
2962 tmphash = hashval;
2963 hashval = hashmap->hashes[pos];
2964 hashmap->hashes[pos] = tmphash;
2965 SCIPswapPointers(&hashmap->slots[pos].origin, &origin);
2966 tmp = image;
2967 image = hashmap->slots[pos].image;
2968 hashmap->slots[pos].image = tmp;
2969 }
2970
2971 /* continue until we have found an empty position */
2972 pos = (pos + 1) & hashmap->mask;
2973 ++elemdistance;
2974 }
2975}
2976
2977/** lookup origin in the hashmap. If element is found returns true and the position of the element,
2978 * otherwise returns FALSE.
2979 */
2980static
2982 SCIP_HASHMAP* hashmap, /**< hash table */
2983 void* origin, /**< origin to lookup */
2984 uint32_t* pos /**< pointer to store position of element, if exists */
2985 )
2986{
2987 uint32_t hashval;
2988 uint32_t elemdistance;
2989
2990 assert(hashmap != NULL);
2991 assert(hashmap->slots != NULL);
2992 assert(hashmap->hashes != NULL);
2993 assert(hashmap->mask > 0);
2994
2995 /* get the hash value */
2996 hashval = hashvalue((size_t)origin);
2997 assert(hashval != 0);
2998
2999 *pos = hashval>>(hashmap->shift);
3000 elemdistance = 0;
3001
3002 while( TRUE ) /*lint !e716*/
3003 {
3004 uint32_t distance;
3005
3006 /* slots is empty so element cannot be contained */
3007 if( hashmap->hashes[*pos] == 0 )
3008 return FALSE;
3009
3010 distance = ELEM_DISTANCE(*pos);
3011 /* element can not be contained since otherwise we would have swapped it with this one during insert */
3012 if( elemdistance > distance )
3013 return FALSE;
3014
3015 /* found element */
3016 if( hashmap->hashes[*pos] == hashval && hashmap->slots[*pos].origin == origin )
3017 return TRUE;
3018
3019 *pos = (*pos + 1) & hashmap->mask;
3020 ++elemdistance;
3021 }
3022}
3023
3024/** check if the load factor of the hashmap is too high and rebuild if necessary */
3025static
3027 SCIP_HASHMAP* hashmap /**< hash table */
3028 )
3029{
3030 assert(hashmap != NULL);
3031 assert(hashmap->shift < 32);
3032
3033 /* use integer arithmetic to approximately check if load factor is above 90% */
3034 if( ((((uint64_t)hashmap->nelements)<<10)>>(32-hashmap->shift) > 921) )
3035 {
3036 SCIP_HASHMAPENTRY* slots;
3037 uint32_t* hashes;
3038 uint32_t nslots;
3039 uint32_t newnslots;
3040 uint32_t i;
3041
3042 /* calculate new size (always power of two) */
3043 nslots = hashmap->mask + 1;
3044 --hashmap->shift;
3045 newnslots = 2*nslots;
3046 hashmap->mask = newnslots-1;
3047
3048 /* reallocate array */
3049 SCIP_ALLOC( BMSallocBlockMemoryArray(hashmap->blkmem, &slots, newnslots) );
3050 SCIP_ALLOC( BMSallocClearBlockMemoryArray(hashmap->blkmem, &hashes, newnslots) );
3051
3052 SCIPswapPointers((void**) &slots, (void**) &hashmap->slots);
3053 SCIPswapPointers((void**) &hashes, (void**) &hashmap->hashes);
3054 hashmap->nelements = 0;
3055
3056 /* reinsert all elements */
3057 for( i = 0; i < nslots; ++i )
3058 {
3059 /* using SCIP_CALL_ABORT since there are no allocations or duplicates
3060 * and thus no bad return codes when inserting the elements
3061 */
3062 if( hashes[i] != 0 )
3063 {
3064 SCIP_CALL_ABORT( hashmapInsert(hashmap, slots[i].origin, slots[i].image, hashes[i], FALSE) );
3065 }
3066 }
3067
3068 /* free old arrays */
3069 BMSfreeBlockMemoryArray(hashmap->blkmem, &hashes, nslots);
3070 BMSfreeBlockMemoryArray(hashmap->blkmem, &slots, nslots);
3071 }
3072
3073 return SCIP_OKAY;
3074}
3075
3076/** creates a hash map mapping pointers to pointers */
3078 SCIP_HASHMAP** hashmap, /**< pointer to store the created hash map */
3079 BMS_BLKMEM* blkmem, /**< block memory used to store hash map entries */
3080 int mapsize /**< size of the hash map */
3081 )
3082{
3083 uint32_t nslots;
3084
3085 assert(hashmap != NULL);
3086 assert(mapsize >= 0);
3087 assert(blkmem != NULL);
3088
3089 SCIP_ALLOC( BMSallocBlockMemory(blkmem, hashmap) );
3090
3091 /* dont create too small hashtables, i.e. at least size 32, and increase
3092 * the given size by divinding it by 0.9, since then no rebuilding will
3093 * be necessary if the given number of elements are inserted. Finally round
3094 * to the next power of two.
3095 */
3096 (*hashmap)->shift = 32;
3097 (*hashmap)->shift -= (unsigned int)ceil(log(MAX(32, mapsize / 0.9)) / log(2.0));
3098 nslots = 1u << (32 - (*hashmap)->shift);
3099 (*hashmap)->mask = nslots - 1;
3100 (*hashmap)->blkmem = blkmem;
3101 (*hashmap)->nelements = 0;
3102 (*hashmap)->hashmaptype = SCIP_HASHMAPTYPE_UNKNOWN;
3103
3104 SCIP_ALLOC( BMSallocBlockMemoryArray((*hashmap)->blkmem, &(*hashmap)->slots, nslots) );
3105 SCIP_ALLOC( BMSallocClearBlockMemoryArray((*hashmap)->blkmem, &(*hashmap)->hashes, nslots) );
3106
3107 return SCIP_OKAY;
3108}
3109
3110/** frees the hash map */
3112 SCIP_HASHMAP** hashmap /**< pointer to the hash map */
3113 )
3114{
3115 uint32_t nslots;
3116
3117 assert(hashmap != NULL);
3118 assert(*hashmap != NULL);
3119
3120 nslots = (*hashmap)->mask + 1;
3121#ifdef SCIP_DEBUG
3122 {
3123 uint32_t maxprobelen = 0;
3124 uint64_t probelensum = 0;
3125 uint32_t i;
3126
3127 assert(hashmap != NULL);
3128
3129 for( i = 0; i < nslots; ++i )
3130 {
3131 if( (*hashmap)->hashes[i] != 0 )
3132 {
3133 uint32_t probelen = ((i + (*hashmap)->mask + 1 - ((*hashmap)->hashes[i]>>((*hashmap)->shift))) & (*hashmap)->mask) + 1;
3134 probelensum += probelen;
3135 maxprobelen = MAX(probelen, maxprobelen);
3136 }
3137 }
3138
3139 SCIPdebugMessage("%u hash map entries, used %u/%u slots (%.1f%%)",
3140 (unsigned int)(*hashmap)->nelements, (unsigned int)(*hashmap)->nelements, (unsigned int)nslots,
3141 100.0*(SCIP_Real)(*hashmap)->nelements/(SCIP_Real)(nslots));
3142 if( (*hashmap)->nelements > 0 )
3143 SCIPdebugPrintf(", avg. probe length is %.1f, max. probe length is %u",
3144 (SCIP_Real)(probelensum)/(SCIP_Real)(*hashmap)->nelements, (unsigned int)maxprobelen);
3145 SCIPdebugPrintf("\n");
3146 }
3147#endif
3148
3149 /* free main hash map data structure */
3150 BMSfreeBlockMemoryArray((*hashmap)->blkmem, &(*hashmap)->hashes, nslots);
3151 BMSfreeBlockMemoryArray((*hashmap)->blkmem, &(*hashmap)->slots, nslots);
3152 BMSfreeBlockMemory((*hashmap)->blkmem, hashmap);
3153}
3154
3155/** inserts new origin->image pair in hash map
3156 *
3157 * @note multiple insertion of same element is checked and results in an error
3158 */
3160 SCIP_HASHMAP* hashmap, /**< hash map */
3161 void* origin, /**< origin to set image for */
3162 void* image /**< new image for origin */
3163 )
3164{
3165 uint32_t hashval;
3167
3168 assert(hashmap != NULL);
3169 assert(hashmap->slots != NULL);
3170 assert(hashmap->hashes != NULL);
3171 assert(hashmap->mask > 0);
3173
3174#ifndef NDEBUG
3175 if( hashmap->hashmaptype == SCIP_HASHMAPTYPE_UNKNOWN )
3177#endif
3178
3179 SCIP_CALL( hashmapCheckLoad(hashmap) );
3180
3181 /* get the hash value */
3182 hashval = hashvalue((size_t)origin);
3183
3184 /* append origin->image pair to hash map */
3185 img.ptr = image;
3186 SCIP_CALL( hashmapInsert(hashmap, origin, img, hashval, FALSE) );
3187
3188 return SCIP_OKAY;
3189}
3190
3191/** inserts new origin->image pair in hash map
3192 *
3193 * @note multiple insertion of same element is checked and results in an error
3194 */
3196 SCIP_HASHMAP* hashmap, /**< hash map */
3197 void* origin, /**< origin to set image for */
3198 int image /**< new image for origin */
3199 )
3200{
3201 uint32_t hashval;
3203
3204 assert(hashmap != NULL);
3205 assert(hashmap->slots != NULL);
3206 assert(hashmap->hashes != NULL);
3207 assert(hashmap->mask > 0);
3208 assert(hashmap->hashmaptype == SCIP_HASHMAPTYPE_UNKNOWN || hashmap->hashmaptype == SCIP_HASHMAPTYPE_INT);
3209
3210#ifndef NDEBUG
3211 if( hashmap->hashmaptype == SCIP_HASHMAPTYPE_UNKNOWN )
3213#endif
3214
3215 SCIP_CALL( hashmapCheckLoad(hashmap) );
3216
3217 /* get the hash value */
3218 hashval = hashvalue((size_t)origin);
3219
3220 /* append origin->image pair to hash map */
3221 img.integer = image;
3222 SCIP_CALL( hashmapInsert(hashmap, origin, img, hashval, FALSE) );
3223
3224 return SCIP_OKAY;
3225}
3226
3227/** inserts new origin->image pair in hash map
3228 *
3229 * @note multiple insertion of same element is checked and results in an error
3230 */
3232 SCIP_HASHMAP* hashmap, /**< hash map */
3233 void* origin, /**< origin to set image for */
3234 SCIP_Real image /**< new image for origin */
3235 )
3236{
3237 uint32_t hashval;
3239
3240 assert(hashmap != NULL);
3241 assert(hashmap->slots != NULL);
3242 assert(hashmap->hashes != NULL);
3243 assert(hashmap->mask > 0);
3244 assert(hashmap->hashmaptype == SCIP_HASHMAPTYPE_UNKNOWN || hashmap->hashmaptype == SCIP_HASHMAPTYPE_REAL);
3245
3246#ifndef NDEBUG
3247 if( hashmap->hashmaptype == SCIP_HASHMAPTYPE_UNKNOWN )
3249#endif
3250
3251 SCIP_CALL( hashmapCheckLoad(hashmap) );
3252
3253 /* get the hash value */
3254 hashval = hashvalue((size_t)origin);
3255
3256 /* append origin->image pair to hash map */
3257 img.real = image;
3258 SCIP_CALL( hashmapInsert(hashmap, origin, img, hashval, FALSE) );
3259
3260 return SCIP_OKAY;
3261}
3262
3263/** retrieves image of given origin from the hash map, or NULL if no image exists */
3265 SCIP_HASHMAP* hashmap, /**< hash map */
3266 void* origin /**< origin to retrieve image for */
3267 )
3268{
3269 uint32_t pos;
3270
3271 assert(hashmap != NULL);
3272 assert(hashmap->slots != NULL);
3273 assert(hashmap->hashes != NULL);
3274 assert(hashmap->mask > 0);
3276
3277 if( hashmapLookup(hashmap, origin, &pos) )
3278 return hashmap->slots[pos].image.ptr;
3279
3280 return NULL;
3281}
3282
3283/** retrieves image of given origin from the hash map, or INT_MAX if no image exists */
3285 SCIP_HASHMAP* hashmap, /**< hash map */
3286 void* origin /**< origin to retrieve image for */
3287 )
3288{
3289 uint32_t pos;
3290
3291 assert(hashmap != NULL);
3292 assert(hashmap->slots != NULL);
3293 assert(hashmap->hashes != NULL);
3294 assert(hashmap->mask > 0);
3295 assert(hashmap->hashmaptype == SCIP_HASHMAPTYPE_UNKNOWN || hashmap->hashmaptype == SCIP_HASHMAPTYPE_INT);
3296
3297 if( hashmapLookup(hashmap, origin, &pos) )
3298 return hashmap->slots[pos].image.integer;
3299
3300 return INT_MAX;
3301}
3302
3303/** retrieves image of given origin from the hash map, or SCIP_INVALID if no image exists */
3305 SCIP_HASHMAP* hashmap, /**< hash map */
3306 void* origin /**< origin to retrieve image for */
3307 )
3308{
3309 uint32_t pos;
3310
3311 assert(hashmap != NULL);
3312 assert(hashmap->slots != NULL);
3313 assert(hashmap->hashes != NULL);
3314 assert(hashmap->mask > 0);
3315 assert(hashmap->hashmaptype == SCIP_HASHMAPTYPE_UNKNOWN || hashmap->hashmaptype == SCIP_HASHMAPTYPE_REAL);
3316
3317 if( hashmapLookup(hashmap, origin, &pos) )
3318 return hashmap->slots[pos].image.real;
3319
3320 return SCIP_INVALID;
3321}
3322
3323/** sets image for given origin in the hash map, either by modifying existing origin->image pair
3324 * or by appending a new origin->image pair
3325 */
3327 SCIP_HASHMAP* hashmap, /**< hash map */
3328 void* origin, /**< origin to set image for */
3329 void* image /**< new image for origin */
3330 )
3331{
3332 uint32_t hashval;
3334
3335 assert(hashmap != NULL);
3336 assert(hashmap->slots != NULL);
3337 assert(hashmap->mask > 0);
3339
3340#ifndef NDEBUG
3341 if( hashmap->hashmaptype == SCIP_HASHMAPTYPE_UNKNOWN )
3343#endif
3344
3345 SCIP_CALL( hashmapCheckLoad(hashmap) );
3346
3347 /* get the hash value */
3348 hashval = hashvalue((size_t)origin);
3349
3350 /* append origin->image pair to hash map */
3351 img.ptr = image;
3352 SCIP_CALL( hashmapInsert(hashmap, origin, img, hashval, TRUE) );
3353
3354 return SCIP_OKAY;
3355}
3356
3357/** sets image for given origin in the hash map, either by modifying existing origin->image pair
3358 * or by appending a new origin->image pair
3359 */
3361 SCIP_HASHMAP* hashmap, /**< hash map */
3362 void* origin, /**< origin to set image for */
3363 int image /**< new image for origin */
3364 )
3365{
3366 uint32_t hashval;
3368
3369 assert(hashmap != NULL);
3370 assert(hashmap->slots != NULL);
3371 assert(hashmap->mask > 0);
3372 assert(hashmap->hashmaptype == SCIP_HASHMAPTYPE_UNKNOWN || hashmap->hashmaptype == SCIP_HASHMAPTYPE_INT);
3373
3374#ifndef NDEBUG
3375 if( hashmap->hashmaptype == SCIP_HASHMAPTYPE_UNKNOWN )
3377#endif
3378
3379 SCIP_CALL( hashmapCheckLoad(hashmap) );
3380
3381 /* get the hash value */
3382 hashval = hashvalue((size_t)origin);
3383
3384 /* append origin->image pair to hash map */
3385 img.integer = image;
3386 SCIP_CALL( hashmapInsert(hashmap, origin, img, hashval, TRUE) );
3387
3388 return SCIP_OKAY;
3389}
3390
3391/** sets image for given origin in the hash map, either by modifying existing origin->image pair
3392 * or by appending a new origin->image pair
3393 */
3395 SCIP_HASHMAP* hashmap, /**< hash map */
3396 void* origin, /**< origin to set image for */
3397 SCIP_Real image /**< new image for origin */
3398 )
3399{
3400 uint32_t hashval;
3402
3403 assert(hashmap != NULL);
3404 assert(hashmap->slots != NULL);
3405 assert(hashmap->mask > 0);
3406 assert(hashmap->hashmaptype == SCIP_HASHMAPTYPE_UNKNOWN || hashmap->hashmaptype == SCIP_HASHMAPTYPE_REAL);
3407
3408#ifndef NDEBUG
3409 if( hashmap->hashmaptype == SCIP_HASHMAPTYPE_UNKNOWN )
3411#endif
3412
3413 SCIP_CALL( hashmapCheckLoad(hashmap) );
3414
3415 /* get the hash value */
3416 hashval = hashvalue((size_t)origin);
3417
3418 /* append origin->image pair to hash map */
3419 img.real = image;
3420 SCIP_CALL( hashmapInsert(hashmap, origin, img, hashval, TRUE) );
3421
3422 return SCIP_OKAY;
3423}
3424
3425/** checks whether an image to the given origin exists in the hash map */
3427 SCIP_HASHMAP* hashmap, /**< hash map */
3428 void* origin /**< origin to search for */
3429 )
3430{
3431 uint32_t pos;
3432
3433 assert(hashmap != NULL);
3434 assert(hashmap->slots != NULL);
3435 assert(hashmap->hashes != NULL);
3436 assert(hashmap->mask > 0);
3437
3438 return hashmapLookup(hashmap, origin, &pos);
3439}
3440
3441/** removes origin->image pair from the hash map, if it exists */
3443 SCIP_HASHMAP* hashmap, /**< hash map */
3444 void* origin /**< origin to remove from the list */
3445 )
3446{
3447 uint32_t pos;
3448
3449 assert(hashmap != NULL);
3450 assert(hashmap->slots != NULL);
3451 assert(hashmap->mask > 0);
3452
3453 assert(origin != NULL);
3454
3455 if( hashmapLookup(hashmap, origin, &pos) )
3456 {
3457 /* remove element */
3458 hashmap->hashes[pos] = 0;
3459 --hashmap->nelements;
3460
3461 /* move other elements if necessary */
3462 while( TRUE ) /*lint !e716*/
3463 {
3464 uint32_t nextpos = (pos + 1) & hashmap->mask;
3465
3466 /* nothing to do since there is no chain that needs to be moved */
3467 if( hashmap->hashes[nextpos] == 0 )
3468 return SCIP_OKAY;
3469
3470 /* check if the element is the start of a new chain and return if that is the case */
3471 if( (hashmap->hashes[nextpos]>>(hashmap->shift)) == nextpos )
3472 return SCIP_OKAY;
3473
3474 /* element should be moved to the left and next element needs to be checked */
3475 hashmap->slots[pos].origin = hashmap->slots[nextpos].origin;
3476 hashmap->slots[pos].image = hashmap->slots[nextpos].image;
3477 hashmap->hashes[pos] = hashmap->hashes[nextpos];
3478 hashmap->hashes[nextpos] = 0;
3479
3480 pos = nextpos;
3481 }
3482 }
3483
3484 return SCIP_OKAY;
3485}
3486
3487/** prints statistics about hash map usage */
3489 SCIP_HASHMAP* hashmap, /**< hash map */
3490 SCIP_MESSAGEHDLR* messagehdlr /**< message handler */
3491 )
3492{
3493 uint32_t maxprobelen = 0;
3494 uint64_t probelensum = 0;
3495 uint32_t nslots;
3496 uint32_t i;
3497
3498 assert(hashmap != NULL);
3499
3500 nslots = hashmap->mask + 1;
3501
3502 /* compute the maximum and average probe length */
3503 for( i = 0; i < nslots; ++i )
3504 {
3505 if( hashmap->hashes[i] != 0 )
3506 {
3507 uint32_t probelen = ELEM_DISTANCE(i) + 1;
3508 probelensum += probelen;
3509 maxprobelen = MAX(probelen, maxprobelen);
3510 }
3511 }
3512
3513 /* print general hash map statistics */
3514 SCIPmessagePrintInfo(messagehdlr, "%u hash entries, used %u/%u slots (%.1f%%)",
3515 (unsigned int)hashmap->nelements, (unsigned int)hashmap->nelements,
3516 (unsigned int)nslots, 100.0*(SCIP_Real)hashmap->nelements/(SCIP_Real)(nslots));
3517
3518 /* if not empty print average and maximum probe length */
3519 if( hashmap->nelements > 0 )
3520 SCIPmessagePrintInfo(messagehdlr, ", avg. probe length is %.1f, max. probe length is %u",
3521 (SCIP_Real)(probelensum)/(SCIP_Real)hashmap->nelements, (unsigned int)maxprobelen);
3522 SCIPmessagePrintInfo(messagehdlr, "\n");
3523}
3524
3525/** indicates whether a hash map has no entries */
3527 SCIP_HASHMAP* hashmap /**< hash map */
3528 )
3529{
3530 assert(hashmap != NULL);
3531
3532 return hashmap->nelements == 0;
3533}
3534
3535/** gives the number of elements in a hash map */
3537 SCIP_HASHMAP* hashmap /**< hash map */
3538 )
3539{
3540 return (int) hashmap->nelements;
3541}
3542
3543/** gives the number of entries in the internal arrays of a hash map */
3545 SCIP_HASHMAP* hashmap /**< hash map */
3546 )
3547{
3548 return (int) hashmap->mask + 1;
3549}
3550
3551/** gives the hashmap entry at the given index or NULL if entry is empty */
3553 SCIP_HASHMAP* hashmap, /**< hash map */
3554 int entryidx /**< index of hash map entry */
3555 )
3556{
3557 assert(hashmap != NULL);
3558
3559 return hashmap->hashes[entryidx] == 0 ? NULL : &hashmap->slots[entryidx];
3560}
3561
3562/** gives the origin of the hashmap entry */
3564 SCIP_HASHMAPENTRY* entry /**< hash map entry */
3565 )
3566{
3567 assert(entry != NULL);
3568
3569 return entry->origin;
3570}
3571
3572/** gives the image of the hashmap entry */
3574 SCIP_HASHMAPENTRY* entry /**< hash map entry */
3575 )
3576{
3577 assert(entry != NULL);
3578
3579 return entry->image.ptr;
3580}
3581
3582/** gives the image of the hashmap entry */
3584 SCIP_HASHMAPENTRY* entry /**< hash map entry */
3585 )
3586{
3587 assert(entry != NULL);
3588
3589 return entry->image.integer;
3590}
3591
3592/** gives the image of the hashmap entry */
3594 SCIP_HASHMAPENTRY* entry /**< hash map entry */
3595 )
3596{
3597 assert(entry != NULL);
3598
3599 return entry->image.real;
3600}
3601
3602/** sets pointer image of a hashmap entry */
3604 SCIP_HASHMAPENTRY* entry, /**< hash map entry */
3605 void* image /**< new image */
3606 )
3607{
3608 assert(entry != NULL);
3609
3610 entry->image.ptr = image;
3611}
3612
3613/** sets integer image of a hashmap entry */
3615 SCIP_HASHMAPENTRY* entry, /**< hash map entry */
3616 int image /**< new image */
3617 )
3618{
3619 assert(entry != NULL);
3620
3621 entry->image.integer = image;
3622}
3623
3624/** sets real image of a hashmap entry */
3626 SCIP_HASHMAPENTRY* entry, /**< hash map entry */
3627 SCIP_Real image /**< new image */
3628 )
3629{
3630 assert(entry != NULL);
3631
3632 entry->image.real = image;
3633}
3634
3635/** removes all entries in a hash map. */
3637 SCIP_HASHMAP* hashmap /**< hash map */
3638 )
3639{
3640 assert(hashmap != NULL);
3641
3642 BMSclearMemoryArray(hashmap->hashes, hashmap->mask + 1);
3643
3644 hashmap->nelements = 0;
3645
3646 return SCIP_OKAY;
3647}
3648
3649
3650/*
3651 * Hash Set
3652 */
3653
3654/* redefine ELEM_DISTANCE macro for hashset */
3655#undef ELEM_DISTANCE
3656/* computes the distance from it's desired position for the element stored at pos */
3657#define ELEM_DISTANCE(pos) (((pos) + nslots - hashSetDesiredPos(hashset, hashset->slots[(pos)])) & mask)
3658
3659/* calculate desired position of element in hash set */
3660static
3662 SCIP_HASHSET* hashset, /**< the hash set */
3663 void* element /**< element to calculate position for */
3664 )
3665{
3666 return (uint32_t)((UINT64_C(0x9e3779b97f4a7c15) * (uintptr_t)element)>>(hashset->shift));
3667}
3668
3669static
3671 SCIP_HASHSET* hashset, /**< hash set */
3672 void* element /**< element to insert */
3673 )
3674{
3675 uint32_t elemdistance;
3676 uint32_t pos;
3677 uint32_t nslots;
3678 uint32_t mask;
3679
3680 assert(hashset != NULL);
3681 assert(hashset->slots != NULL);
3682 assert(element != NULL);
3683
3684 pos = hashSetDesiredPos(hashset, element);
3685 nslots = (uint32_t)SCIPhashsetGetNSlots(hashset);
3686 mask = nslots - 1;
3687
3688 elemdistance = 0;
3689 while( TRUE ) /*lint !e716*/
3690 {
3691 uint32_t distance;
3692
3693 /* if position is empty or key equal insert element */
3694 if( hashset->slots[pos] == NULL )
3695 {
3696 hashset->slots[pos] = element;
3697 ++hashset->nelements;
3698 return;
3699 }
3700
3701 if( hashset->slots[pos] == element )
3702 return;
3703
3704 /* otherwise check if the current element at this position is closer to its hashvalue */
3705 distance = ELEM_DISTANCE(pos);
3706 if( distance < elemdistance )
3707 {
3708 /* if this is the case we insert the new element here and find a new position for the old one */
3709 elemdistance = distance;
3710 SCIPswapPointers(&hashset->slots[pos], &element);
3711 }
3712
3713 /* continue until we have found an empty position */
3714 pos = (pos + 1) & mask;
3715 ++elemdistance;
3716 }
3717}
3718
3719/** check if the load factor of the hash set is too high and rebuild if necessary */
3720static
3722 SCIP_HASHSET* hashset, /**< hash set */
3723 BMS_BLKMEM* blkmem /**< block memory used to store hash set entries */
3724 )
3725{
3726 assert(hashset != NULL);
3727 assert(hashset->shift < 64);
3728
3729 /* use integer arithmetic to approximately check if load factor is above 90% */
3730 if( ((((uint64_t)hashset->nelements)<<10)>>(64-hashset->shift) > 921) )
3731 {
3732 void** slots;
3733 uint32_t nslots;
3734 uint32_t newnslots;
3735 uint32_t i;
3736
3737 /* calculate new size (always power of two) */
3738 nslots = (uint32_t)SCIPhashsetGetNSlots(hashset);
3739 newnslots = 2*nslots;
3740 --hashset->shift;
3741
3742 /* reallocate array */
3743 SCIP_ALLOC( BMSallocClearBlockMemoryArray(blkmem, &slots, newnslots) );
3744
3745 SCIPswapPointers((void**) &slots, (void**) &hashset->slots);
3746 hashset->nelements = 0;
3747
3748 /* reinsert all elements */
3749 for( i = 0; i < nslots; ++i )
3750 {
3751 if( slots[i] != NULL )
3752 hashsetInsert(hashset, slots[i]);
3753 }
3754
3755 BMSfreeBlockMemoryArray(blkmem, &slots, nslots);
3756 }
3757
3758 return SCIP_OKAY;
3759}
3760
3761/** creates a hash set of pointers */
3763 SCIP_HASHSET** hashset, /**< pointer to store the created hash set */
3764 BMS_BLKMEM* blkmem, /**< block memory used to store hash set entries */
3765 int size /**< initial size of the hash set; it is guaranteed that the set is not
3766 * resized if at most that many elements are inserted */
3767 )
3768{
3769 uint32_t nslots;
3770
3771 assert(hashset != NULL);
3772 assert(size >= 0);
3773 assert(blkmem != NULL);
3774
3775 SCIP_ALLOC( BMSallocBlockMemory(blkmem, hashset) );
3776
3777 /* do not create too small hashtables, i.e. at least size 32, and increase
3778 * the given size by dividing it by 0.9, since then no rebuilding will
3779 * be necessary if the given number of elements are inserted. Finally round
3780 * to the next power of two.
3781 */
3782 (*hashset)->shift = 64;
3783 (*hashset)->shift -= (unsigned int)ceil(log(MAX(8.0, size / 0.9)) / log(2.0));
3784 nslots = (uint32_t)SCIPhashsetGetNSlots(*hashset);
3785 (*hashset)->nelements = 0;
3786
3787 SCIP_ALLOC( BMSallocClearBlockMemoryArray(blkmem, &(*hashset)->slots, nslots) );
3788
3789 return SCIP_OKAY;
3790}
3791
3792/** frees the hash set */
3794 SCIP_HASHSET** hashset, /**< pointer to the hash set */
3795 BMS_BLKMEM* blkmem /**< block memory used to store hash set entries */
3796 )
3797{
3798 BMSfreeBlockMemoryArray(blkmem, &(*hashset)->slots, SCIPhashsetGetNSlots(*hashset));
3799 BMSfreeBlockMemory(blkmem, hashset);
3800}
3801
3802/** inserts new element into the hash set */
3804 SCIP_HASHSET* hashset, /**< hash set */
3805 BMS_BLKMEM* blkmem, /**< block memory used to store hash set entries */
3806 void* element /**< element to insert */
3807 )
3808{
3809 assert(hashset != NULL);
3810 assert(hashset->slots != NULL);
3811
3812 SCIP_CALL( hashsetCheckLoad(hashset, blkmem) );
3813
3814 hashsetInsert(hashset, element);
3815
3816 return SCIP_OKAY;
3817}
3818
3819/** checks whether an element exists in the hash set */
3821 SCIP_HASHSET* hashset, /**< hash set */
3822 void* element /**< element to search for */
3823 )
3824{
3825 uint32_t pos;
3826 uint32_t nslots;
3827 uint32_t mask;
3828 uint32_t elemdistance;
3829
3830 assert(hashset != NULL);
3831 assert(hashset->slots != NULL);
3832
3833 pos = hashSetDesiredPos(hashset, element);
3834 nslots = (uint32_t)SCIPhashsetGetNSlots(hashset);
3835 mask = nslots - 1;
3836 elemdistance = 0;
3837
3838 while( TRUE ) /*lint !e716*/
3839 {
3840 uint32_t distance;
3841
3842 /* found element */
3843 if( hashset->slots[pos] == element )
3844 return TRUE;
3845
3846 /* slots is empty so element cannot be contained */
3847 if( hashset->slots[pos] == NULL )
3848 return FALSE;
3849
3850 distance = ELEM_DISTANCE(pos);
3851 /* element can not be contained since otherwise we would have swapped it with this one during insert */
3852 if( elemdistance > distance )
3853 return FALSE;
3854
3855 pos = (pos + 1) & mask;
3856 ++elemdistance;
3857 }
3858}
3859
3860/** removes an element from the hash set, if it exists */
3862 SCIP_HASHSET* hashset, /**< hash set */
3863 void* element /**< origin to remove from the list */
3864 )
3865{
3866 uint32_t pos;
3867 uint32_t nslots;
3868 uint32_t mask;
3869 uint32_t elemdistance;
3870
3871 assert(hashset != NULL);
3872 assert(hashset->slots != NULL);
3873 assert(element != NULL);
3874
3875 pos = hashSetDesiredPos(hashset, element);
3876 nslots = (uint32_t)SCIPhashsetGetNSlots(hashset);
3877 mask = nslots - 1;
3878 elemdistance = 0;
3879
3880 while( TRUE ) /*lint !e716*/
3881 {
3882 uint32_t distance;
3883
3884 /* found element */
3885 if( hashset->slots[pos] == element )
3886 break;
3887
3888 /* slots is empty so element cannot be contained */
3889 if( hashset->slots[pos] == NULL )
3890 return SCIP_OKAY;
3891
3892 distance = ELEM_DISTANCE(pos);
3893 /* element can not be contained since otherwise we would have swapped it with this one during insert */
3894 if( elemdistance > distance )
3895 return SCIP_OKAY;
3896
3897 pos = (pos + 1) & mask;
3898 ++elemdistance;
3899 }
3900
3901 assert(hashset->slots[pos] == element);
3902 assert(SCIPhashsetExists(hashset, element));
3903
3904 /* remove element */
3905 --hashset->nelements;
3906
3907 /* move other elements if necessary */
3908 while( TRUE ) /*lint !e716*/
3909 {
3910 uint32_t nextpos = (pos + 1) & mask;
3911
3912 /* nothing to do since there is no chain that needs to be moved */
3913 if( hashset->slots[nextpos] == NULL )
3914 {
3915 hashset->slots[pos] = NULL;
3916 assert(!SCIPhashsetExists(hashset, element));
3917 return SCIP_OKAY;
3918 }
3919
3920 /* check if the element is the start of a new chain and return if that is the case */
3921 if( hashSetDesiredPos(hashset, hashset->slots[nextpos]) == nextpos )
3922 {
3923 hashset->slots[pos] = NULL;
3924 assert(!SCIPhashsetExists(hashset, element));
3925 return SCIP_OKAY;
3926 }
3927
3928 /* element should be moved to the left and next element needs to be checked */
3929 hashset->slots[pos] = hashset->slots[nextpos];
3930
3931 pos = nextpos;
3932 }
3933}
3934
3935/** prints statistics about hash set usage */
3937 SCIP_HASHSET* hashset, /**< hash set */
3938 SCIP_MESSAGEHDLR* messagehdlr /**< message handler */
3939 )
3940{
3941 uint32_t maxprobelen = 0;
3942 uint64_t probelensum = 0;
3943 uint32_t nslots;
3944 uint32_t mask;
3945 uint32_t i;
3946
3947 assert(hashset != NULL);
3948
3949 nslots = (uint32_t)SCIPhashsetGetNSlots(hashset);
3950 mask = nslots - 1;
3951
3952 /* compute the maximum and average probe length */
3953 for( i = 0; i < nslots; ++i )
3954 {
3955 if( hashset->slots[i] != NULL )
3956 {
3957 uint32_t probelen = ((hashSetDesiredPos(hashset, hashset->slots[i]) + nslots - i) & mask) + 1;
3958 probelensum += probelen;
3959 maxprobelen = MAX(probelen, maxprobelen);
3960 }
3961 }
3962
3963 /* print general hash set statistics */
3964 SCIPmessagePrintInfo(messagehdlr, "%u hash entries, used %u/%u slots (%.1f%%)",
3965 (unsigned int)hashset->nelements, (unsigned int)hashset->nelements,
3966 (unsigned int)nslots, 100.0*(SCIP_Real)hashset->nelements/(SCIP_Real)(nslots));
3967
3968 /* if not empty print average and maximum probe length */
3969 if( hashset->nelements > 0 )
3970 SCIPmessagePrintInfo(messagehdlr, ", avg. probe length is %.1f, max. probe length is %u",
3971 (SCIP_Real)(probelensum)/(SCIP_Real)hashset->nelements, (unsigned int)maxprobelen);
3972 SCIPmessagePrintInfo(messagehdlr, "\n");
3973}
3974
3975/* In debug mode, the following methods are implemented as function calls to ensure
3976 * type validity.
3977 * In optimized mode, the methods are implemented as defines to improve performance.
3978 * However, we want to have them in the library anyways, so we have to undef the defines.
3979 */
3980
3981#undef SCIPhashsetIsEmpty
3982#undef SCIPhashsetGetNElements
3983#undef SCIPhashsetGetNSlots
3984#undef SCIPhashsetGetSlots
3985
3986/** indicates whether a hash set has no entries */
3988 SCIP_HASHSET* hashset /**< hash set */
3989 )
3990{
3991 return hashset->nelements == 0;
3992}
3993
3994/** gives the number of elements in a hash set */
3996 SCIP_HASHSET* hashset /**< hash set */
3997 )
3998{
3999 return (int)hashset->nelements;
4000}
4001
4002/** gives the number of slots of a hash set */
4004 SCIP_HASHSET* hashset /**< hash set */
4005 )
4006{
4007 return (int) (1u << (64 - hashset->shift));
4008}
4009
4010/** gives the array of hash set slots; contains all elements in indetermined order and may contain NULL values */
4012 SCIP_HASHSET* hashset /**< hash set */
4013 )
4014{
4015 return hashset->slots;
4016}
4017
4018/** removes all entries in a hash set. */
4020 SCIP_HASHSET* hashset /**< hash set */
4021 )
4022{
4024
4025 hashset->nelements = 0;
4026}
4027
4028/*
4029 * Dynamic Arrays
4030 */
4031
4032/** creates a dynamic array of real values */
4034 SCIP_REALARRAY** realarray, /**< pointer to store the real array */
4035 BMS_BLKMEM* blkmem /**< block memory */
4036 )
4037{
4038 assert(realarray != NULL);
4039 assert(blkmem != NULL);
4040
4041 SCIP_ALLOC( BMSallocBlockMemory(blkmem, realarray) );
4042 (*realarray)->blkmem = blkmem;
4043 (*realarray)->vals = NULL;
4044 (*realarray)->valssize = 0;
4045 (*realarray)->firstidx = -1;
4046 (*realarray)->minusedidx = INT_MAX;
4047 (*realarray)->maxusedidx = INT_MIN;
4048
4049 return SCIP_OKAY;
4050}
4051
4052/** creates a copy of a dynamic array of real values */
4054 SCIP_REALARRAY** realarray, /**< pointer to store the copied real array */
4055 BMS_BLKMEM* blkmem, /**< block memory */
4056 SCIP_REALARRAY* sourcerealarray /**< dynamic real array to copy */
4057 )
4058{
4059 assert(realarray != NULL);
4060 assert(sourcerealarray != NULL);
4061
4062 SCIP_CALL( SCIPrealarrayCreate(realarray, blkmem) );
4063 if( sourcerealarray->valssize > 0 )
4064 {
4065 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*realarray)->vals, sourcerealarray->vals, \
4066 sourcerealarray->valssize) );
4067 }
4068 (*realarray)->valssize = sourcerealarray->valssize;
4069 (*realarray)->firstidx = sourcerealarray->firstidx;
4070 (*realarray)->minusedidx = sourcerealarray->minusedidx;
4071 (*realarray)->maxusedidx = sourcerealarray->maxusedidx;
4072
4073 return SCIP_OKAY;
4074}
4075
4076/** frees a dynamic array of real values */
4078 SCIP_REALARRAY** realarray /**< pointer to the real array */
4079 )
4080{
4081 assert(realarray != NULL);
4082 assert(*realarray != NULL);
4083
4084 BMSfreeBlockMemoryArrayNull((*realarray)->blkmem, &(*realarray)->vals, (*realarray)->valssize);
4085 BMSfreeBlockMemory((*realarray)->blkmem, realarray);
4086
4087 return SCIP_OKAY;
4088}
4089
4090/** extends dynamic array to be able to store indices from minidx to maxidx */
4092 SCIP_REALARRAY* realarray, /**< dynamic real array */
4093 int arraygrowinit, /**< initial size of array */
4094 SCIP_Real arraygrowfac, /**< growing factor of array */
4095 int minidx, /**< smallest index to allocate storage for */
4096 int maxidx /**< largest index to allocate storage for */
4097 )
4098{
4099 int nused;
4100 int nfree;
4101 int newfirstidx;
4102 int i;
4103
4104 assert(realarray != NULL);
4105 assert(realarray->minusedidx == INT_MAX || realarray->firstidx >= 0);
4106 assert(realarray->maxusedidx == INT_MIN || realarray->firstidx >= 0);
4107 assert(realarray->minusedidx == INT_MAX || realarray->minusedidx >= realarray->firstidx);
4108 assert(realarray->maxusedidx == INT_MIN || realarray->maxusedidx < realarray->firstidx + realarray->valssize);
4109 assert(0 <= minidx);
4110 assert(minidx <= maxidx);
4111
4112 minidx = MIN(minidx, realarray->minusedidx);
4113 maxidx = MAX(maxidx, realarray->maxusedidx);
4114 assert(0 <= minidx);
4115 assert(minidx <= maxidx);
4116
4117 SCIPdebugMessage("extending realarray %p (firstidx=%d, size=%d, range=[%d,%d]) to range [%d,%d]\n",
4118 (void*)realarray, realarray->firstidx, realarray->valssize, realarray->minusedidx, realarray->maxusedidx, minidx, maxidx);
4119
4120 /* check, whether we have to allocate additional memory, or shift the array */
4121 nused = maxidx - minidx + 1;
4122 if( nused > realarray->valssize )
4123 {
4124 SCIP_Real* newvals;
4125 int newvalssize;
4126
4127 /* allocate new memory storage */
4128 newvalssize = calcGrowSize(arraygrowinit, arraygrowfac, nused);
4129 SCIP_ALLOC( BMSallocBlockMemoryArray(realarray->blkmem, &newvals, newvalssize) );
4130 nfree = newvalssize - nused;
4131 newfirstidx = minidx - nfree/2;
4132 newfirstidx = MAX(newfirstidx, 0);
4133 assert(newfirstidx <= minidx);
4134 assert(maxidx < newfirstidx + newvalssize);
4135
4136 /* initialize memory array by copying old values and setting new values to zero */
4137 if( realarray->firstidx != -1 )
4138 {
4139 for( i = 0; i < realarray->minusedidx - newfirstidx; ++i )
4140 newvals[i] = 0.0;
4141
4142 /* check for possible overflow or negative value */
4143 assert(realarray->maxusedidx - realarray->minusedidx + 1 > 0);
4144
4145 BMScopyMemoryArray(&newvals[realarray->minusedidx - newfirstidx],
4146 &(realarray->vals[realarray->minusedidx - realarray->firstidx]),
4147 realarray->maxusedidx - realarray->minusedidx + 1); /*lint !e866 !e776*/
4148 for( i = realarray->maxusedidx - newfirstidx + 1; i < newvalssize; ++i )
4149 newvals[i] = 0.0;
4150 }
4151 else
4152 {
4153 for( i = 0; i < newvalssize; ++i )
4154 newvals[i] = 0.0;
4155 }
4156
4157 /* free old memory storage, and set the new array parameters */
4158 BMSfreeBlockMemoryArrayNull(realarray->blkmem, &realarray->vals, realarray->valssize);
4159 realarray->vals = newvals;
4160 realarray->valssize = newvalssize;
4161 realarray->firstidx = newfirstidx;
4162 }
4163 else if( realarray->firstidx == -1 )
4164 {
4165 /* a sufficiently large memory storage exists, but it was cleared */
4166 nfree = realarray->valssize - nused;
4167 assert(nfree >= 0);
4168 realarray->firstidx = minidx - nfree/2;
4169 assert(realarray->firstidx <= minidx);
4170 assert(maxidx < realarray->firstidx + realarray->valssize);
4171#ifndef NDEBUG
4172 for( i = 0; i < realarray->valssize; ++i )
4173 assert(realarray->vals[i] == 0.0);
4174#endif
4175 }
4176 else if( minidx < realarray->firstidx )
4177 {
4178 /* a sufficiently large memory storage exists, but it has to be shifted to the right */
4179 nfree = realarray->valssize - nused;
4180 assert(nfree >= 0);
4181 newfirstidx = minidx - nfree/2;
4182 newfirstidx = MAX(newfirstidx, 0);
4183 assert(newfirstidx <= minidx);
4184 assert(maxidx < newfirstidx + realarray->valssize);
4185
4186 if( realarray->minusedidx <= realarray->maxusedidx )
4187 {
4188 int shift;
4189
4190 assert(realarray->firstidx <= realarray->minusedidx);
4191 assert(realarray->maxusedidx < realarray->firstidx + realarray->valssize);
4192
4193 /* shift used part of array to the right */
4194 shift = realarray->firstidx - newfirstidx;
4195 assert(shift > 0);
4196 for( i = realarray->maxusedidx - realarray->firstidx; i >= realarray->minusedidx - realarray->firstidx; --i )
4197 {
4198 assert(0 <= i + shift && i + shift < realarray->valssize);
4199 realarray->vals[i + shift] = realarray->vals[i];
4200 }
4201 /* clear the formerly used head of the array */
4202 for( i = 0; i < shift; ++i )
4203 realarray->vals[realarray->minusedidx - realarray->firstidx + i] = 0.0;
4204 }
4205 realarray->firstidx = newfirstidx;
4206 }
4207 else if( maxidx >= realarray->firstidx + realarray->valssize )
4208 {
4209 /* a sufficiently large memory storage exists, but it has to be shifted to the left */
4210 nfree = realarray->valssize - nused;
4211 assert(nfree >= 0);
4212 newfirstidx = minidx - nfree/2;
4213 newfirstidx = MAX(newfirstidx, 0);
4214 assert(newfirstidx <= minidx);
4215 assert(maxidx < newfirstidx + realarray->valssize);
4216
4217 if( realarray->minusedidx <= realarray->maxusedidx )
4218 {
4219 int shift;
4220
4221 assert(realarray->firstidx <= realarray->minusedidx);
4222 assert(realarray->maxusedidx < realarray->firstidx + realarray->valssize);
4223
4224 /* shift used part of array to the left */
4225 shift = newfirstidx - realarray->firstidx;
4226 assert(shift > 0);
4227 for( i = realarray->minusedidx - realarray->firstidx; i <= realarray->maxusedidx - realarray->firstidx; ++i )
4228 {
4229 assert(0 <= i - shift && i - shift < realarray->valssize);
4230 realarray->vals[i - shift] = realarray->vals[i];
4231 }
4232 /* clear the formerly used tail of the array */
4233 for( i = 0; i < shift; ++i )
4234 realarray->vals[realarray->maxusedidx - realarray->firstidx - i] = 0.0;
4235 }
4236 realarray->firstidx = newfirstidx;
4237 }
4238
4239 assert(minidx >= realarray->firstidx);
4240 assert(maxidx < realarray->firstidx + realarray->valssize);
4241
4242 return SCIP_OKAY;
4243}
4244
4245/** clears a dynamic real array */
4247 SCIP_REALARRAY* realarray /**< dynamic real array */
4248 )
4249{
4250 assert(realarray != NULL);
4251
4252 SCIPdebugMessage("clearing realarray %p (firstidx=%d, size=%d, range=[%d,%d])\n",
4253 (void*)realarray, realarray->firstidx, realarray->valssize, realarray->minusedidx, realarray->maxusedidx);
4254
4255 if( realarray->minusedidx <= realarray->maxusedidx )
4256 {
4257 assert(realarray->firstidx <= realarray->minusedidx);
4258 assert(realarray->maxusedidx < realarray->firstidx + realarray->valssize);
4259 assert(realarray->firstidx != -1);
4260 assert(realarray->valssize > 0);
4261
4262 /* clear the used part of array */
4263 BMSclearMemoryArray(&realarray->vals[realarray->minusedidx - realarray->firstidx],
4264 realarray->maxusedidx - realarray->minusedidx + 1); /*lint !e866*/
4265
4266 /* mark the array cleared */
4267 realarray->minusedidx = INT_MAX;
4268 realarray->maxusedidx = INT_MIN;
4269 }
4270 assert(realarray->minusedidx == INT_MAX);
4271 assert(realarray->maxusedidx == INT_MIN);
4272
4273 return SCIP_OKAY;
4274}
4275
4276/** gets value of entry in dynamic array */
4278 SCIP_REALARRAY* realarray, /**< dynamic real array */
4279 int idx /**< array index to get value for */
4280 )
4281{
4282 assert(realarray != NULL);
4283 assert(idx >= 0);
4284
4285 if( idx < realarray->minusedidx || idx > realarray->maxusedidx )
4286 return 0.0;
4287 else
4288 {
4289 assert(realarray->vals != NULL);
4290 assert(idx - realarray->firstidx >= 0);
4291 assert(idx - realarray->firstidx < realarray->valssize);
4292
4293 return realarray->vals[idx - realarray->firstidx];
4294 }
4295}
4296
4297/** sets value of entry in dynamic array */
4299 SCIP_REALARRAY* realarray, /**< dynamic real array */
4300 int arraygrowinit, /**< initial size of array */
4301 SCIP_Real arraygrowfac, /**< growing factor of array */
4302 int idx, /**< array index to set value for */
4303 SCIP_Real val /**< value to set array index to */
4304 )
4305{
4306 assert(realarray != NULL);
4307 assert(idx >= 0);
4308
4309 SCIPdebugMessage("setting realarray %p (firstidx=%d, size=%d, range=[%d,%d]) index %d to %g\n",
4310 (void*)realarray, realarray->firstidx, realarray->valssize, realarray->minusedidx, realarray->maxusedidx, idx, val);
4311
4312 if( val != 0.0 )
4313 {
4314 /* extend array to be able to store the index */
4315 SCIP_CALL( SCIPrealarrayExtend(realarray, arraygrowinit, arraygrowfac, idx, idx) );
4316 assert(idx >= realarray->firstidx);
4317 assert(idx < realarray->firstidx + realarray->valssize);
4318
4319 /* set the array value of the index */
4320 realarray->vals[idx - realarray->firstidx] = val;
4321
4322 /* update min/maxusedidx */
4323 realarray->minusedidx = MIN(realarray->minusedidx, idx);
4324 realarray->maxusedidx = MAX(realarray->maxusedidx, idx);
4325 }
4326 else if( idx >= realarray->firstidx && idx < realarray->firstidx + realarray->valssize )
4327 {
4328 /* set the array value of the index to zero */
4329 realarray->vals[idx - realarray->firstidx] = 0.0;
4330
4331 /* check, if we can tighten the min/maxusedidx */
4332 if( idx == realarray->minusedidx )
4333 {
4334 assert(realarray->maxusedidx >= 0);
4335 assert(realarray->maxusedidx < realarray->firstidx + realarray->valssize);
4336 do
4337 {
4338 realarray->minusedidx++;
4339 }
4340 while( realarray->minusedidx <= realarray->maxusedidx
4341 && realarray->vals[realarray->minusedidx - realarray->firstidx] == 0.0 );
4342
4343 if( realarray->minusedidx > realarray->maxusedidx )
4344 {
4345 realarray->minusedidx = INT_MAX;
4346 realarray->maxusedidx = INT_MIN;
4347 }
4348 }
4349 else if( idx == realarray->maxusedidx )
4350 {
4351 assert(realarray->minusedidx >= 0);
4352 assert(realarray->minusedidx < realarray->maxusedidx);
4353 assert(realarray->maxusedidx < realarray->firstidx + realarray->valssize);
4354 do
4355 {
4356 realarray->maxusedidx--;
4357 assert(realarray->minusedidx <= realarray->maxusedidx);
4358 }
4359 while( realarray->vals[realarray->maxusedidx - realarray->firstidx] == 0.0 );
4360 }
4361 }
4362
4363 return SCIP_OKAY;
4364}
4365
4366/** increases value of entry in dynamic array */
4368 SCIP_REALARRAY* realarray, /**< dynamic real array */
4369 int arraygrowinit, /**< initial size of array */
4370 SCIP_Real arraygrowfac, /**< growing factor of array */
4371 int idx, /**< array index to increase value for */
4372 SCIP_Real incval /**< value to increase array index */
4373 )
4374{
4375 SCIP_Real oldval;
4376
4377 oldval = SCIPrealarrayGetVal(realarray, idx);
4378 if( oldval != SCIP_INVALID ) /*lint !e777*/
4379 return SCIPrealarraySetVal(realarray, arraygrowinit, arraygrowfac, idx, oldval + incval);
4380 else
4381 return SCIP_OKAY;
4382}
4383
4384/** returns the minimal index of all stored non-zero elements */
4386 SCIP_REALARRAY* realarray /**< dynamic real array */
4387 )
4388{
4389 assert(realarray != NULL);
4390
4391 return realarray->minusedidx;
4392}
4393
4394/** returns the maximal index of all stored non-zero elements */
4396 SCIP_REALARRAY* realarray /**< dynamic real array */
4397 )
4398{
4399 assert(realarray != NULL);
4400
4401 return realarray->maxusedidx;
4402}
4403
4404/** creates a dynamic array of int values */
4406 SCIP_INTARRAY** intarray, /**< pointer to store the int array */
4407 BMS_BLKMEM* blkmem /**< block memory */
4408 )
4409{
4410 assert(intarray != NULL);
4411 assert(blkmem != NULL);
4412
4413 SCIP_ALLOC( BMSallocBlockMemory(blkmem, intarray) );
4414 (*intarray)->blkmem = blkmem;
4415 (*intarray)->vals = NULL;
4416 (*intarray)->valssize = 0;
4417 (*intarray)->firstidx = -1;
4418 (*intarray)->minusedidx = INT_MAX;
4419 (*intarray)->maxusedidx = INT_MIN;
4420
4421 return SCIP_OKAY;
4422}
4423
4424/** creates a copy of a dynamic array of int values */
4426 SCIP_INTARRAY** intarray, /**< pointer to store the copied int array */
4427 BMS_BLKMEM* blkmem, /**< block memory */
4428 SCIP_INTARRAY* sourceintarray /**< dynamic int array to copy */
4429 )
4430{
4431 assert(intarray != NULL);
4432 assert(sourceintarray != NULL);
4433
4434 SCIP_CALL( SCIPintarrayCreate(intarray, blkmem) );
4435 if( sourceintarray->valssize > 0 )
4436 {
4437 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*intarray)->vals, sourceintarray->vals, sourceintarray->valssize) );
4438 }
4439 (*intarray)->valssize = sourceintarray->valssize;
4440 (*intarray)->firstidx = sourceintarray->firstidx;
4441 (*intarray)->minusedidx = sourceintarray->minusedidx;
4442 (*intarray)->maxusedidx = sourceintarray->maxusedidx;
4443
4444 return SCIP_OKAY;
4445}
4446
4447/** frees a dynamic array of int values */
4449 SCIP_INTARRAY** intarray /**< pointer to the int array */
4450 )
4451{
4452 assert(intarray != NULL);
4453 assert(*intarray != NULL);
4454
4455 BMSfreeBlockMemoryArrayNull((*intarray)->blkmem, &(*intarray)->vals, (*intarray)->valssize);
4456 BMSfreeBlockMemory((*intarray)->blkmem, intarray);
4457
4458 return SCIP_OKAY;
4459}
4460
4461/** extends dynamic array to be able to store indices from minidx to maxidx */
4463 SCIP_INTARRAY* intarray, /**< dynamic int array */
4464 int arraygrowinit, /**< initial size of array */
4465 SCIP_Real arraygrowfac, /**< growing factor of array */
4466 int minidx, /**< smallest index to allocate storage for */
4467 int maxidx /**< largest index to allocate storage for */
4468 )
4469{
4470 int nused;
4471 int nfree;
4472 int newfirstidx;
4473 int i;
4474
4475 assert(intarray != NULL);
4476 assert(intarray->minusedidx == INT_MAX || intarray->firstidx >= 0);
4477 assert(intarray->maxusedidx == INT_MIN || intarray->firstidx >= 0);
4478 assert(intarray->minusedidx == INT_MAX || intarray->minusedidx >= intarray->firstidx);
4479 assert(intarray->maxusedidx == INT_MIN || intarray->maxusedidx < intarray->firstidx + intarray->valssize);
4480 assert(0 <= minidx);
4481 assert(minidx <= maxidx);
4482
4483 minidx = MIN(minidx, intarray->minusedidx);
4484 maxidx = MAX(maxidx, intarray->maxusedidx);
4485 assert(0 <= minidx);
4486 assert(minidx <= maxidx);
4487
4488 SCIPdebugMessage("extending intarray %p (firstidx=%d, size=%d, range=[%d,%d]) to range [%d,%d]\n",
4489 (void*)intarray, intarray->firstidx, intarray->valssize, intarray->minusedidx, intarray->maxusedidx, minidx, maxidx);
4490
4491 /* check, whether we have to allocate additional memory, or shift the array */
4492 nused = maxidx - minidx + 1;
4493 if( nused > intarray->valssize )
4494 {
4495 int* newvals;
4496 int newvalssize;
4497
4498 /* allocate new memory storage */
4499 newvalssize = calcGrowSize(arraygrowinit, arraygrowfac, nused);
4500 SCIP_ALLOC( BMSallocBlockMemoryArray(intarray->blkmem, &newvals, newvalssize) );
4501 nfree = newvalssize - nused;
4502 newfirstidx = minidx - nfree/2;
4503 newfirstidx = MAX(newfirstidx, 0);
4504 assert(newfirstidx <= minidx);
4505 assert(maxidx < newfirstidx + newvalssize);
4506
4507 /* initialize memory array by copying old values and setting new values to zero */
4508 if( intarray->firstidx != -1 )
4509 {
4510 for( i = 0; i < intarray->minusedidx - newfirstidx; ++i )
4511 newvals[i] = 0;
4512
4513 /* check for possible overflow or negative value */
4514 assert(intarray->maxusedidx - intarray->minusedidx + 1 > 0);
4515
4516 BMScopyMemoryArray(&newvals[intarray->minusedidx - newfirstidx],
4517 &intarray->vals[intarray->minusedidx - intarray->firstidx],
4518 intarray->maxusedidx - intarray->minusedidx + 1); /*lint !e866 !e776*/
4519 for( i = intarray->maxusedidx - newfirstidx + 1; i < newvalssize; ++i )
4520 newvals[i] = 0;
4521 }
4522 else
4523 {
4524 for( i = 0; i < newvalssize; ++i )
4525 newvals[i] = 0;
4526 }
4527
4528 /* free old memory storage, and set the new array parameters */
4529 BMSfreeBlockMemoryArrayNull(intarray->blkmem, &intarray->vals, intarray->valssize);
4530 intarray->vals = newvals;
4531 intarray->valssize = newvalssize;
4532 intarray->firstidx = newfirstidx;
4533 }
4534 else if( intarray->firstidx == -1 )
4535 {
4536 /* a sufficiently large memory storage exists, but it was cleared */
4537 nfree = intarray->valssize - nused;
4538 assert(nfree >= 0);
4539 intarray->firstidx = minidx - nfree/2;
4540 assert(intarray->firstidx <= minidx);
4541 assert(maxidx < intarray->firstidx + intarray->valssize);
4542#ifndef NDEBUG
4543 for( i = 0; i < intarray->valssize; ++i )
4544 assert(intarray->vals[i] == 0);
4545#endif
4546 }
4547 else if( minidx < intarray->firstidx )
4548 {
4549 /* a sufficiently large memory storage exists, but it has to be shifted to the right */
4550 nfree = intarray->valssize - nused;
4551 assert(nfree >= 0);
4552 newfirstidx = minidx - nfree/2;
4553 newfirstidx = MAX(newfirstidx, 0);
4554 assert(newfirstidx <= minidx);
4555 assert(maxidx < newfirstidx + intarray->valssize);
4556
4557 if( intarray->minusedidx <= intarray->maxusedidx )
4558 {
4559 int shift;
4560
4561 assert(intarray->firstidx <= intarray->minusedidx);
4562 assert(intarray->maxusedidx < intarray->firstidx + intarray->valssize);
4563
4564 /* shift used part of array to the right */
4565 shift = intarray->firstidx - newfirstidx;
4566 assert(shift > 0);
4567 for( i = intarray->maxusedidx - intarray->firstidx; i >= intarray->minusedidx - intarray->firstidx; --i )
4568 {
4569 assert(0 <= i + shift && i + shift < intarray->valssize);
4570 intarray->vals[i + shift] = intarray->vals[i];
4571 }
4572 /* clear the formerly used head of the array */
4573 for( i = 0; i < shift; ++i )
4574 intarray->vals[intarray->minusedidx - intarray->firstidx + i] = 0;
4575 }
4576 intarray->firstidx = newfirstidx;
4577 }
4578 else if( maxidx >= intarray->firstidx + intarray->valssize )
4579 {
4580 /* a sufficiently large memory storage exists, but it has to be shifted to the left */
4581 nfree = intarray->valssize - nused;
4582 assert(nfree >= 0);
4583 newfirstidx = minidx - nfree/2;
4584 newfirstidx = MAX(newfirstidx, 0);
4585 assert(newfirstidx <= minidx);
4586 assert(maxidx < newfirstidx + intarray->valssize);
4587
4588 if( intarray->minusedidx <= intarray->maxusedidx )
4589 {
4590 int shift;
4591
4592 assert(intarray->firstidx <= intarray->minusedidx);
4593 assert(intarray->maxusedidx < intarray->firstidx + intarray->valssize);
4594
4595 /* shift used part of array to the left */
4596 shift = newfirstidx - intarray->firstidx;
4597 assert(shift > 0);
4598 for( i = intarray->minusedidx - intarray->firstidx; i <= intarray->maxusedidx - intarray->firstidx; ++i )
4599 {
4600 assert(0 <= i - shift && i - shift < intarray->valssize);
4601 intarray->vals[i - shift] = intarray->vals[i];
4602 }
4603 /* clear the formerly used tail of the array */
4604 for( i = 0; i < shift; ++i )
4605 intarray->vals[intarray->maxusedidx - intarray->firstidx - i] = 0;
4606 }
4607 intarray->firstidx = newfirstidx;
4608 }
4609
4610 assert(minidx >= intarray->firstidx);
4611 assert(maxidx < intarray->firstidx + intarray->valssize);
4612
4613 return SCIP_OKAY;
4614}
4615
4616/** clears a dynamic int array */
4618 SCIP_INTARRAY* intarray /**< dynamic int array */
4619 )
4620{
4621 assert(intarray != NULL);
4622
4623 SCIPdebugMessage("clearing intarray %p (firstidx=%d, size=%d, range=[%d,%d])\n",
4624 (void*)intarray, intarray->firstidx, intarray->valssize, intarray->minusedidx, intarray->maxusedidx);
4625
4626 if( intarray->minusedidx <= intarray->maxusedidx )
4627 {
4628 assert(intarray->firstidx <= intarray->minusedidx);
4629 assert(intarray->maxusedidx < intarray->firstidx + intarray->valssize);
4630 assert(intarray->firstidx != -1);
4631 assert(intarray->valssize > 0);
4632
4633 /* clear the used part of array */
4634 BMSclearMemoryArray(&intarray->vals[intarray->minusedidx - intarray->firstidx],
4635 intarray->maxusedidx - intarray->minusedidx + 1); /*lint !e866*/
4636
4637 /* mark the array cleared */
4638 intarray->minusedidx = INT_MAX;
4639 intarray->maxusedidx = INT_MIN;
4640 }
4641 assert(intarray->minusedidx == INT_MAX);
4642 assert(intarray->maxusedidx == INT_MIN);
4643
4644 return SCIP_OKAY;
4645}
4646
4647/** gets value of entry in dynamic array */
4649 SCIP_INTARRAY* intarray, /**< dynamic int array */
4650 int idx /**< array index to get value for */
4651 )
4652{
4653 assert(intarray != NULL);
4654 assert(idx >= 0);
4655
4656 if( idx < intarray->minusedidx || idx > intarray->maxusedidx )
4657 return 0;
4658 else
4659 {
4660 assert(intarray->vals != NULL);
4661 assert(idx - intarray->firstidx >= 0);
4662 assert(idx - intarray->firstidx < intarray->valssize);
4663
4664 return intarray->vals[idx - intarray->firstidx];
4665 }
4666}
4667
4668/** sets value of entry in dynamic array */
4670 SCIP_INTARRAY* intarray, /**< dynamic int array */
4671 int arraygrowinit, /**< initial size of array */
4672 SCIP_Real arraygrowfac, /**< growing factor of array */
4673 int idx, /**< array index to set value for */
4674 int val /**< value to set array index to */
4675 )
4676{
4677 assert(intarray != NULL);
4678 assert(idx >= 0);
4679
4680 SCIPdebugMessage("setting intarray %p (firstidx=%d, size=%d, range=[%d,%d]) index %d to %d\n",
4681 (void*)intarray, intarray->firstidx, intarray->valssize, intarray->minusedidx, intarray->maxusedidx, idx, val);
4682
4683 if( val != 0 )
4684 {
4685 /* extend array to be able to store the index */
4686 SCIP_CALL( SCIPintarrayExtend(intarray, arraygrowinit, arraygrowfac, idx, idx) );
4687 assert(idx >= intarray->firstidx);
4688 assert(idx < intarray->firstidx + intarray->valssize);
4689
4690 /* set the array value of the index */
4691 intarray->vals[idx - intarray->firstidx] = val;
4692
4693 /* update min/maxusedidx */
4694 intarray->minusedidx = MIN(intarray->minusedidx, idx);
4695 intarray->maxusedidx = MAX(intarray->maxusedidx, idx);
4696 }
4697 else if( idx >= intarray->firstidx && idx < intarray->firstidx + intarray->valssize )
4698 {
4699 /* set the array value of the index to zero */
4700 intarray->vals[idx - intarray->firstidx] = 0;
4701
4702 /* check, if we can tighten the min/maxusedidx */
4703 if( idx == intarray->minusedidx )
4704 {
4705 assert(intarray->maxusedidx >= 0);
4706 assert(intarray->maxusedidx < intarray->firstidx + intarray->valssize);
4707 do
4708 {
4709 intarray->minusedidx++;
4710 }
4711 while( intarray->minusedidx <= intarray->maxusedidx
4712 && intarray->vals[intarray->minusedidx - intarray->firstidx] == 0 );
4713 if( intarray->minusedidx > intarray->maxusedidx )
4714 {
4715 intarray->minusedidx = INT_MAX;
4716 intarray->maxusedidx = INT_MIN;
4717 }
4718 }
4719 else if( idx == intarray->maxusedidx )
4720 {
4721 assert(intarray->minusedidx >= 0);
4722 assert(intarray->minusedidx < intarray->maxusedidx);
4723 assert(intarray->maxusedidx < intarray->firstidx + intarray->valssize);
4724 do
4725 {
4726 intarray->maxusedidx--;
4727 assert(intarray->minusedidx <= intarray->maxusedidx);
4728 }
4729 while( intarray->vals[intarray->maxusedidx - intarray->firstidx] == 0 );
4730 }
4731 }
4732
4733 return SCIP_OKAY;
4734}
4735
4736/** increases value of entry in dynamic array */
4738 SCIP_INTARRAY* intarray, /**< dynamic int array */
4739 int arraygrowinit, /**< initial size of array */
4740 SCIP_Real arraygrowfac, /**< growing factor of array */
4741 int idx, /**< array index to increase value for */
4742 int incval /**< value to increase array index */
4743 )
4744{
4745 return SCIPintarraySetVal(intarray, arraygrowinit, arraygrowfac, idx, SCIPintarrayGetVal(intarray, idx) + incval);
4746}
4747
4748/** returns the minimal index of all stored non-zero elements */
4750 SCIP_INTARRAY* intarray /**< dynamic int array */
4751 )
4752{
4753 assert(intarray != NULL);
4754
4755 return intarray->minusedidx;
4756}
4757
4758/** returns the maximal index of all stored non-zero elements */
4760 SCIP_INTARRAY* intarray /**< dynamic int array */
4761 )
4762{
4763 assert(intarray != NULL);
4764
4765 return intarray->maxusedidx;
4766}
4767
4768
4769/** creates a dynamic array of bool values */
4771 SCIP_BOOLARRAY** boolarray, /**< pointer to store the bool array */
4772 BMS_BLKMEM* blkmem /**< block memory */
4773 )
4774{
4775 assert(boolarray != NULL);
4776 assert(blkmem != NULL);
4777
4778 SCIP_ALLOC( BMSallocBlockMemory(blkmem, boolarray) );
4779 (*boolarray)->blkmem = blkmem;
4780 (*boolarray)->vals = NULL;
4781 (*boolarray)->valssize = 0;
4782 (*boolarray)->firstidx = -1;
4783 (*boolarray)->minusedidx = INT_MAX;
4784 (*boolarray)->maxusedidx = INT_MIN;
4785
4786 return SCIP_OKAY;
4787}
4788
4789/** creates a copy of a dynamic array of bool values */
4791 SCIP_BOOLARRAY** boolarray, /**< pointer to store the copied bool array */
4792 BMS_BLKMEM* blkmem, /**< block memory */
4793 SCIP_BOOLARRAY* sourceboolarray /**< dynamic bool array to copy */
4794 )
4795{
4796 assert(boolarray != NULL);
4797 assert(sourceboolarray != NULL);
4798
4799 SCIP_CALL( SCIPboolarrayCreate(boolarray, blkmem) );
4800 if( sourceboolarray->valssize > 0 )
4801 {
4802 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*boolarray)->vals, sourceboolarray->vals, \
4803 sourceboolarray->valssize) );
4804 }
4805 (*boolarray)->valssize = sourceboolarray->valssize;
4806 (*boolarray)->firstidx = sourceboolarray->firstidx;
4807 (*boolarray)->minusedidx = sourceboolarray->minusedidx;
4808 (*boolarray)->maxusedidx = sourceboolarray->maxusedidx;
4809
4810 return SCIP_OKAY;
4811}
4812
4813/** frees a dynamic array of bool values */
4815 SCIP_BOOLARRAY** boolarray /**< pointer to the bool array */
4816 )
4817{
4818 assert(boolarray != NULL);
4819 assert(*boolarray != NULL);
4820
4821 BMSfreeBlockMemoryArrayNull((*boolarray)->blkmem, &(*boolarray)->vals, (*boolarray)->valssize);
4822 BMSfreeBlockMemory((*boolarray)->blkmem, boolarray);
4823
4824 return SCIP_OKAY;
4825}
4826
4827/** extends dynamic array to be able to store indices from minidx to maxidx */
4829 SCIP_BOOLARRAY* boolarray, /**< dynamic bool array */
4830 int arraygrowinit, /**< initial size of array */
4831 SCIP_Real arraygrowfac, /**< growing factor of array */
4832 int minidx, /**< smallest index to allocate storage for */
4833 int maxidx /**< largest index to allocate storage for */
4834 )
4835{
4836 int nused;
4837 int nfree;
4838 int newfirstidx;
4839 int i;
4840
4841 assert(boolarray != NULL);
4842 assert(boolarray->minusedidx == INT_MAX || boolarray->firstidx >= 0);
4843 assert(boolarray->maxusedidx == INT_MIN || boolarray->firstidx >= 0);
4844 assert(boolarray->minusedidx == INT_MAX || boolarray->minusedidx >= boolarray->firstidx);
4845 assert(boolarray->maxusedidx == INT_MIN || boolarray->maxusedidx < boolarray->firstidx + boolarray->valssize);
4846 assert(0 <= minidx);
4847 assert(minidx <= maxidx);
4848
4849 minidx = MIN(minidx, boolarray->minusedidx);
4850 maxidx = MAX(maxidx, boolarray->maxusedidx);
4851 assert(0 <= minidx);
4852 assert(minidx <= maxidx);
4853
4854 SCIPdebugMessage("extending boolarray %p (firstidx=%d, size=%d, range=[%d,%d]) to range [%d,%d]\n",
4855 (void*)boolarray, boolarray->firstidx, boolarray->valssize, boolarray->minusedidx, boolarray->maxusedidx, minidx, maxidx);
4856
4857 /* check, whether we have to allocate additional memory, or shift the array */
4858 nused = maxidx - minidx + 1;
4859 if( nused > boolarray->valssize )
4860 {
4861 SCIP_Bool* newvals;
4862 int newvalssize;
4863
4864 /* allocate new memory storage */
4865 newvalssize = calcGrowSize(arraygrowinit, arraygrowfac, nused);
4866 SCIP_ALLOC( BMSallocBlockMemoryArray(boolarray->blkmem, &newvals, newvalssize) );
4867 nfree = newvalssize - nused;
4868 newfirstidx = minidx - nfree/2;
4869 newfirstidx = MAX(newfirstidx, 0);
4870 assert(newfirstidx <= minidx);
4871 assert(maxidx < newfirstidx + newvalssize);
4872
4873 /* initialize memory array by copying old values and setting new values to zero */
4874 if( boolarray->firstidx != -1 )
4875 {
4876 for( i = 0; i < boolarray->minusedidx - newfirstidx; ++i )
4877 newvals[i] = FALSE;
4878
4879 /* check for possible overflow or negative value */
4880 assert(boolarray->maxusedidx - boolarray->minusedidx + 1 > 0);
4881
4882 BMScopyMemoryArray(&newvals[boolarray->minusedidx - newfirstidx],
4883 &boolarray->vals[boolarray->minusedidx - boolarray->firstidx],
4884 boolarray->maxusedidx - boolarray->minusedidx + 1); /*lint !e866 !e776*/
4885 for( i = boolarray->maxusedidx - newfirstidx + 1; i < newvalssize; ++i )
4886 newvals[i] = FALSE;
4887 }
4888 else
4889 {
4890 for( i = 0; i < newvalssize; ++i )
4891 newvals[i] = FALSE;
4892 }
4893
4894 /* free old memory storage, and set the new array parameters */
4895 BMSfreeBlockMemoryArrayNull(boolarray->blkmem, &boolarray->vals, boolarray->valssize);
4896 boolarray->vals = newvals;
4897 boolarray->valssize = newvalssize;
4898 boolarray->firstidx = newfirstidx;
4899 }
4900 else if( boolarray->firstidx == -1 )
4901 {
4902 /* a sufficiently large memory storage exists, but it was cleared */
4903 nfree = boolarray->valssize - nused;
4904 assert(nfree >= 0);
4905 boolarray->firstidx = minidx - nfree/2;
4906 assert(boolarray->firstidx <= minidx);
4907 assert(maxidx < boolarray->firstidx + boolarray->valssize);
4908#ifndef NDEBUG
4909 for( i = 0; i < boolarray->valssize; ++i )
4910 assert(boolarray->vals[i] == FALSE);
4911#endif
4912 }
4913 else if( minidx < boolarray->firstidx )
4914 {
4915 /* a sufficiently large memory storage exists, but it has to be shifted to the right */
4916 nfree = boolarray->valssize - nused;
4917 assert(nfree >= 0);
4918 newfirstidx = minidx - nfree/2;
4919 newfirstidx = MAX(newfirstidx, 0);
4920 assert(newfirstidx <= minidx);
4921 assert(maxidx < newfirstidx + boolarray->valssize);
4922
4923 if( boolarray->minusedidx <= boolarray->maxusedidx )
4924 {
4925 int shift;
4926
4927 assert(boolarray->firstidx <= boolarray->minusedidx);
4928 assert(boolarray->maxusedidx < boolarray->firstidx + boolarray->valssize);
4929
4930 /* shift used part of array to the right */
4931 shift = boolarray->firstidx - newfirstidx;
4932 assert(shift > 0);
4933 for( i = boolarray->maxusedidx - boolarray->firstidx; i >= boolarray->minusedidx - boolarray->firstidx; --i )
4934 {
4935 assert(0 <= i + shift && i + shift < boolarray->valssize);
4936 boolarray->vals[i + shift] = boolarray->vals[i];
4937 }
4938 /* clear the formerly used head of the array */
4939 for( i = 0; i < shift; ++i )
4940 boolarray->vals[boolarray->minusedidx - boolarray->firstidx + i] = FALSE;
4941 }
4942 boolarray->firstidx = newfirstidx;
4943 }
4944 else if( maxidx >= boolarray->firstidx + boolarray->valssize )
4945 {
4946 /* a sufficiently large memory storage exists, but it has to be shifted to the left */
4947 nfree = boolarray->valssize - nused;
4948 assert(nfree >= 0);
4949 newfirstidx = minidx - nfree/2;
4950 newfirstidx = MAX(newfirstidx, 0);
4951 assert(newfirstidx <= minidx);
4952 assert(maxidx < newfirstidx + boolarray->valssize);
4953
4954 if( boolarray->minusedidx <= boolarray->maxusedidx )
4955 {
4956 int shift;
4957
4958 assert(boolarray->firstidx <= boolarray->minusedidx);
4959 assert(boolarray->maxusedidx < boolarray->firstidx + boolarray->valssize);
4960
4961 /* shift used part of array to the left */
4962 shift = newfirstidx - boolarray->firstidx;
4963 assert(shift > 0);
4964
4965 assert(0 <= boolarray->minusedidx - boolarray->firstidx - shift);
4966 assert(boolarray->maxusedidx - boolarray->firstidx - shift < boolarray->valssize);
4967 BMSmoveMemoryArray(&(boolarray->vals[boolarray->minusedidx - boolarray->firstidx - shift]),
4968 &(boolarray->vals[boolarray->minusedidx - boolarray->firstidx]),
4969 boolarray->maxusedidx - boolarray->minusedidx + 1); /*lint !e866*/
4970
4971 /* clear the formerly used tail of the array */
4972 for( i = 0; i < shift; ++i )
4973 boolarray->vals[boolarray->maxusedidx - boolarray->firstidx - i] = FALSE;
4974 }
4975 boolarray->firstidx = newfirstidx;
4976 }
4977
4978 assert(minidx >= boolarray->firstidx);
4979 assert(maxidx < boolarray->firstidx + boolarray->valssize);
4980
4981 return SCIP_OKAY;
4982}
4983
4984/** clears a dynamic bool array */
4986 SCIP_BOOLARRAY* boolarray /**< dynamic bool array */
4987 )
4988{
4989 assert(boolarray != NULL);
4990
4991 SCIPdebugMessage("clearing boolarray %p (firstidx=%d, size=%d, range=[%d,%d])\n",
4992 (void*)boolarray, boolarray->firstidx, boolarray->valssize, boolarray->minusedidx, boolarray->maxusedidx);
4993
4994 if( boolarray->minusedidx <= boolarray->maxusedidx )
4995 {
4996 assert(boolarray->firstidx <= boolarray->minusedidx);
4997 assert(boolarray->maxusedidx < boolarray->firstidx + boolarray->valssize);
4998 assert(boolarray->firstidx != -1);
4999 assert(boolarray->valssize > 0);
5000
5001 /* clear the used part of array */
5002 BMSclearMemoryArray(&boolarray->vals[boolarray->minusedidx - boolarray->firstidx],
5003 boolarray->maxusedidx - boolarray->minusedidx + 1); /*lint !e866*/
5004
5005 /* mark the array cleared */
5006 boolarray->minusedidx = INT_MAX;
5007 boolarray->maxusedidx = INT_MIN;
5008 }
5009 assert(boolarray->minusedidx == INT_MAX);
5010 assert(boolarray->maxusedidx == INT_MIN);
5011
5012 return SCIP_OKAY;
5013}
5014
5015/** gets value of entry in dynamic array */
5017 SCIP_BOOLARRAY* boolarray, /**< dynamic bool array */
5018 int idx /**< array index to get value for */
5019 )
5020{
5021 assert(boolarray != NULL);
5022 assert(idx >= 0);
5023
5024 if( idx < boolarray->minusedidx || idx > boolarray->maxusedidx )
5025 return FALSE;
5026 else
5027 {
5028 assert(boolarray->vals != NULL);
5029 assert(idx - boolarray->firstidx >= 0);
5030 assert(idx - boolarray->firstidx < boolarray->valssize);
5031
5032 return boolarray->vals[idx - boolarray->firstidx];
5033 }
5034}
5035
5036/** sets value of entry in dynamic array */
5038 SCIP_BOOLARRAY* boolarray, /**< dynamic bool array */
5039 int arraygrowinit, /**< initial size of array */
5040 SCIP_Real arraygrowfac, /**< growing factor of array */
5041 int idx, /**< array index to set value for */
5042 SCIP_Bool val /**< value to set array index to */
5043 )
5044{
5045 assert(boolarray != NULL);
5046 assert(idx >= 0);
5047
5048 SCIPdebugMessage("setting boolarray %p (firstidx=%d, size=%d, range=[%d,%d]) index %d to %u\n",
5049 (void*)boolarray, boolarray->firstidx, boolarray->valssize, boolarray->minusedidx, boolarray->maxusedidx, idx, val);
5050
5051 if( val != FALSE )
5052 {
5053 /* extend array to be able to store the index */
5054 SCIP_CALL( SCIPboolarrayExtend(boolarray, arraygrowinit, arraygrowfac, idx, idx) );
5055 assert(idx >= boolarray->firstidx);
5056 assert(idx < boolarray->firstidx + boolarray->valssize);
5057
5058 /* set the array value of the index */
5059 boolarray->vals[idx - boolarray->firstidx] = val;
5060
5061 /* update min/maxusedidx */
5062 boolarray->minusedidx = MIN(boolarray->minusedidx, idx);
5063 boolarray->maxusedidx = MAX(boolarray->maxusedidx, idx);
5064 }
5065 else if( idx >= boolarray->firstidx && idx < boolarray->firstidx + boolarray->valssize )
5066 {
5067 /* set the array value of the index to zero */
5068 boolarray->vals[idx - boolarray->firstidx] = FALSE;
5069
5070 /* check, if we can tighten the min/maxusedidx */
5071 if( idx == boolarray->minusedidx )
5072 {
5073 assert(boolarray->maxusedidx >= 0);
5074 assert(boolarray->maxusedidx < boolarray->firstidx + boolarray->valssize);
5075 do
5076 {
5077 boolarray->minusedidx++;
5078 }
5079 while( boolarray->minusedidx <= boolarray->maxusedidx
5080 && boolarray->vals[boolarray->minusedidx - boolarray->firstidx] == FALSE );
5081 if( boolarray->minusedidx > boolarray->maxusedidx )
5082 {
5083 boolarray->minusedidx = INT_MAX;
5084 boolarray->maxusedidx = INT_MIN;
5085 }
5086 }
5087 else if( idx == boolarray->maxusedidx )
5088 {
5089 assert(boolarray->minusedidx >= 0);
5090 assert(boolarray->minusedidx < boolarray->maxusedidx);
5091 assert(boolarray->maxusedidx < boolarray->firstidx + boolarray->valssize);
5092 do
5093 {
5094 boolarray->maxusedidx--;
5095 assert(boolarray->minusedidx <= boolarray->maxusedidx);
5096 }
5097 while( boolarray->vals[boolarray->maxusedidx - boolarray->firstidx] == FALSE );
5098 }
5099 }
5100
5101 return SCIP_OKAY;
5102}
5103
5104/** returns the minimal index of all stored non-zero elements */
5106 SCIP_BOOLARRAY* boolarray /**< dynamic bool array */
5107 )
5108{
5109 assert(boolarray != NULL);
5110
5111 return boolarray->minusedidx;
5112}
5113
5114/** returns the maximal index of all stored non-zero elements */
5116 SCIP_BOOLARRAY* boolarray /**< dynamic bool array */
5117 )
5118{
5119 assert(boolarray != NULL);
5120
5121 return boolarray->maxusedidx;
5122}
5123
5124
5125/** creates a dynamic array of pointer values */
5127 SCIP_PTRARRAY** ptrarray, /**< pointer to store the ptr array */
5128 BMS_BLKMEM* blkmem /**< block memory */
5129 )
5130{
5131 assert(ptrarray != NULL);
5132 assert(blkmem != NULL);
5133
5134 SCIP_ALLOC( BMSallocBlockMemory(blkmem, ptrarray) );
5135 (*ptrarray)->blkmem = blkmem;
5136 (*ptrarray)->vals = NULL;
5137 (*ptrarray)->valssize = 0;
5138 (*ptrarray)->firstidx = -1;
5139 (*ptrarray)->minusedidx = INT_MAX;
5140 (*ptrarray)->maxusedidx = INT_MIN;
5141
5142 return SCIP_OKAY;
5143}
5144
5145/** creates a copy of a dynamic array of pointer values */
5147 SCIP_PTRARRAY** ptrarray, /**< pointer to store the copied ptr array */
5148 BMS_BLKMEM* blkmem, /**< block memory */
5149 SCIP_PTRARRAY* sourceptrarray /**< dynamic ptr array to copy */
5150 )
5151{
5152 assert(ptrarray != NULL);
5153 assert(sourceptrarray != NULL);
5154
5155 SCIP_CALL( SCIPptrarrayCreate(ptrarray, blkmem) );
5156 if( sourceptrarray->valssize > 0 )
5157 {
5158 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*ptrarray)->vals, sourceptrarray->vals, sourceptrarray->valssize) );
5159 }
5160 (*ptrarray)->valssize = sourceptrarray->valssize;
5161 (*ptrarray)->firstidx = sourceptrarray->firstidx;
5162 (*ptrarray)->minusedidx = sourceptrarray->minusedidx;
5163 (*ptrarray)->maxusedidx = sourceptrarray->maxusedidx;
5164
5165 return SCIP_OKAY;
5166}
5167
5168/** frees a dynamic array of pointer values */
5170 SCIP_PTRARRAY** ptrarray /**< pointer to the ptr array */
5171 )
5172{
5173 assert(ptrarray != NULL);
5174 assert(*ptrarray != NULL);
5175
5176 BMSfreeBlockMemoryArrayNull((*ptrarray)->blkmem, &(*ptrarray)->vals, (*ptrarray)->valssize);
5177 BMSfreeBlockMemory((*ptrarray)->blkmem, ptrarray);
5178
5179 return SCIP_OKAY;
5180}
5181
5182/** extends dynamic array to be able to store indices from minidx to maxidx */
5184 SCIP_PTRARRAY* ptrarray, /**< dynamic ptr array */
5185 int arraygrowinit, /**< initial size of array */
5186 SCIP_Real arraygrowfac, /**< growing factor of array */
5187 int minidx, /**< smallest index to allocate storage for */
5188 int maxidx /**< largest index to allocate storage for */
5189 )
5190{
5191 int nused;
5192 int nfree;
5193 int newfirstidx;
5194 int i;
5195
5196 assert(ptrarray != NULL);
5197 assert(ptrarray->minusedidx == INT_MAX || ptrarray->firstidx >= 0);
5198 assert(ptrarray->maxusedidx == INT_MIN || ptrarray->firstidx >= 0);
5199 assert(ptrarray->minusedidx == INT_MAX || ptrarray->minusedidx >= ptrarray->firstidx);
5200 assert(ptrarray->maxusedidx == INT_MIN || ptrarray->maxusedidx < ptrarray->firstidx + ptrarray->valssize);
5201 assert(0 <= minidx);
5202 assert(minidx <= maxidx);
5203
5204 minidx = MIN(minidx, ptrarray->minusedidx);
5205 maxidx = MAX(maxidx, ptrarray->maxusedidx);
5206 assert(0 <= minidx);
5207 assert(minidx <= maxidx);
5208
5209 SCIPdebugMessage("extending ptrarray %p (firstidx=%d, size=%d, range=[%d,%d]) to range [%d,%d]\n",
5210 (void*)ptrarray, ptrarray->firstidx, ptrarray->valssize, ptrarray->minusedidx, ptrarray->maxusedidx, minidx, maxidx);
5211
5212 /* check, whether we have to allocate additional memory, or shift the array */
5213 nused = maxidx - minidx + 1;
5214 if( nused > ptrarray->valssize )
5215 {
5216 void** newvals;
5217 int newvalssize;
5218
5219 /* allocate new memory storage */
5220 newvalssize = calcGrowSize(arraygrowinit, arraygrowfac, nused);
5221 SCIP_ALLOC( BMSallocBlockMemoryArray(ptrarray->blkmem, &newvals, newvalssize) );
5222 nfree = newvalssize - nused;
5223 newfirstidx = minidx - nfree/2;
5224 newfirstidx = MAX(newfirstidx, 0);
5225 assert(newfirstidx <= minidx);
5226 assert(maxidx < newfirstidx + newvalssize);
5227
5228 /* initialize memory array by copying old values and setting new values to zero */
5229 if( ptrarray->firstidx != -1 )
5230 {
5231 for( i = 0; i < ptrarray->minusedidx - newfirstidx; ++i )
5232 newvals[i] = NULL;
5233
5234 /* check for possible overflow or negative value */
5235 assert(ptrarray->maxusedidx - ptrarray->minusedidx + 1 > 0);
5236
5237 BMScopyMemoryArray(&newvals[ptrarray->minusedidx - newfirstidx],
5238 &(ptrarray->vals[ptrarray->minusedidx - ptrarray->firstidx]),
5239 ptrarray->maxusedidx - ptrarray->minusedidx + 1); /*lint !e866 !e776*/
5240 for( i = ptrarray->maxusedidx - newfirstidx + 1; i < newvalssize; ++i )
5241 newvals[i] = NULL;
5242 }
5243 else
5244 {
5245 for( i = 0; i < newvalssize; ++i )
5246 newvals[i] = NULL;
5247 }
5248
5249 /* free old memory storage, and set the new array parameters */
5250 BMSfreeBlockMemoryArrayNull(ptrarray->blkmem, &ptrarray->vals, ptrarray->valssize);
5251 ptrarray->vals = newvals;
5252 ptrarray->valssize = newvalssize;
5253 ptrarray->firstidx = newfirstidx;
5254 }
5255 else if( ptrarray->firstidx == -1 )
5256 {
5257 /* a sufficiently large memory storage exists, but it was cleared */
5258 nfree = ptrarray->valssize - nused;
5259 assert(nfree >= 0);
5260 ptrarray->firstidx = minidx - nfree/2;
5261 assert(ptrarray->firstidx <= minidx);
5262 assert(maxidx < ptrarray->firstidx + ptrarray->valssize);
5263#ifndef NDEBUG
5264 for( i = 0; i < ptrarray->valssize; ++i )
5265 assert(ptrarray->vals[i] == NULL);
5266#endif
5267 }
5268 else if( minidx < ptrarray->firstidx )
5269 {
5270 /* a sufficiently large memory storage exists, but it has to be shifted to the right */
5271 nfree = ptrarray->valssize - nused;
5272 assert(nfree >= 0);
5273 newfirstidx = minidx - nfree/2;
5274 newfirstidx = MAX(newfirstidx, 0);
5275 assert(newfirstidx <= minidx);
5276 assert(maxidx < newfirstidx + ptrarray->valssize);
5277
5278 if( ptrarray->minusedidx <= ptrarray->maxusedidx )
5279 {
5280 int shift;
5281
5282 assert(ptrarray->firstidx <= ptrarray->minusedidx);
5283 assert(ptrarray->maxusedidx < ptrarray->firstidx + ptrarray->valssize);
5284
5285 /* shift used part of array to the right */
5286 shift = ptrarray->firstidx - newfirstidx;
5287 assert(shift > 0);
5288 for( i = ptrarray->maxusedidx - ptrarray->firstidx; i >= ptrarray->minusedidx - ptrarray->firstidx; --i )
5289 {
5290 assert(0 <= i + shift && i + shift < ptrarray->valssize);
5291 ptrarray->vals[i + shift] = ptrarray->vals[i];
5292 }
5293 /* clear the formerly used head of the array */
5294 for( i = 0; i < shift; ++i )
5295 ptrarray->vals[ptrarray->minusedidx - ptrarray->firstidx + i] = NULL;
5296 }
5297 ptrarray->firstidx = newfirstidx;
5298 }
5299 else if( maxidx >= ptrarray->firstidx + ptrarray->valssize )
5300 {
5301 /* a sufficiently large memory storage exists, but it has to be shifted to the left */
5302 nfree = ptrarray->valssize - nused;
5303 assert(nfree >= 0);
5304 newfirstidx = minidx - nfree/2;
5305 newfirstidx = MAX(newfirstidx, 0);
5306 assert(newfirstidx <= minidx);
5307 assert(maxidx < newfirstidx + ptrarray->valssize);
5308
5309 if( ptrarray->minusedidx <= ptrarray->maxusedidx )
5310 {
5311 int shift;
5312
5313 assert(ptrarray->firstidx <= ptrarray->minusedidx);
5314 assert(ptrarray->maxusedidx < ptrarray->firstidx + ptrarray->valssize);
5315
5316 /* shift used part of array to the left */
5317 shift = newfirstidx - ptrarray->firstidx;
5318 assert(shift > 0);
5319 for( i = ptrarray->minusedidx - ptrarray->firstidx; i <= ptrarray->maxusedidx - ptrarray->firstidx; ++i )
5320 {
5321 assert(0 <= i - shift && i - shift < ptrarray->valssize);
5322 ptrarray->vals[i - shift] = ptrarray->vals[i];
5323 }
5324 /* clear the formerly used tail of the array */
5325 for( i = 0; i < shift; ++i )
5326 ptrarray->vals[ptrarray->maxusedidx - ptrarray->firstidx - i] = NULL;
5327 }
5328 ptrarray->firstidx = newfirstidx;
5329 }
5330
5331 assert(minidx >= ptrarray->firstidx);
5332 assert(maxidx < ptrarray->firstidx + ptrarray->valssize);
5333
5334 return SCIP_OKAY;
5335}
5336
5337/** clears a dynamic pointer array */
5339 SCIP_PTRARRAY* ptrarray /**< dynamic ptr array */
5340 )
5341{
5342 assert(ptrarray != NULL);
5343
5344 SCIPdebugMessage("clearing ptrarray %p (firstidx=%d, size=%d, range=[%d,%d])\n",
5345 (void*)ptrarray, ptrarray->firstidx, ptrarray->valssize, ptrarray->minusedidx, ptrarray->maxusedidx);
5346
5347 if( ptrarray->minusedidx <= ptrarray->maxusedidx )
5348 {
5349 assert(ptrarray->firstidx <= ptrarray->minusedidx);
5350 assert(ptrarray->maxusedidx < ptrarray->firstidx + ptrarray->valssize);
5351 assert(ptrarray->firstidx != -1);
5352 assert(ptrarray->valssize > 0);
5353
5354 /* clear the used part of array */
5355 BMSclearMemoryArray(&ptrarray->vals[ptrarray->minusedidx - ptrarray->firstidx],
5356 ptrarray->maxusedidx - ptrarray->minusedidx + 1); /*lint !e866*/
5357
5358 /* mark the array cleared */
5359 ptrarray->minusedidx = INT_MAX;
5360 ptrarray->maxusedidx = INT_MIN;
5361 }
5362 assert(ptrarray->minusedidx == INT_MAX);
5363 assert(ptrarray->maxusedidx == INT_MIN);
5364
5365 return SCIP_OKAY;
5366}
5367
5368/** gets value of entry in dynamic array */
5370 SCIP_PTRARRAY* ptrarray, /**< dynamic ptr array */
5371 int idx /**< array index to get value for */
5372 )
5373{
5374 assert(ptrarray != NULL);
5375 assert(idx >= 0);
5376
5377 if( idx < ptrarray->minusedidx || idx > ptrarray->maxusedidx )
5378 return NULL;
5379 else
5380 {
5381 assert(ptrarray->vals != NULL);
5382 assert(idx - ptrarray->firstidx >= 0);
5383 assert(idx - ptrarray->firstidx < ptrarray->valssize);
5384
5385 return ptrarray->vals[idx - ptrarray->firstidx];
5386 }
5387}
5388
5389/** sets value of entry in dynamic array */
5391 SCIP_PTRARRAY* ptrarray, /**< dynamic ptr array */
5392 int arraygrowinit, /**< initial size of array */
5393 SCIP_Real arraygrowfac, /**< growing factor of array */
5394 int idx, /**< array index to set value for */
5395 void* val /**< value to set array index to */
5396 )
5397{
5398 assert(ptrarray != NULL);
5399 assert(idx >= 0);
5400
5401 SCIPdebugMessage("setting ptrarray %p (firstidx=%d, size=%d, range=[%d,%d]) index %d to %p\n",
5402 (void*)ptrarray, ptrarray->firstidx, ptrarray->valssize, ptrarray->minusedidx, ptrarray->maxusedidx, idx, val);
5403
5404 if( val != NULL )
5405 {
5406 /* extend array to be able to store the index */
5407 SCIP_CALL( SCIPptrarrayExtend(ptrarray, arraygrowinit, arraygrowfac, idx, idx) );
5408 assert(idx >= ptrarray->firstidx);
5409 assert(idx < ptrarray->firstidx + ptrarray->valssize);
5410
5411 /* set the array value of the index */
5412 ptrarray->vals[idx - ptrarray->firstidx] = val;
5413
5414 /* update min/maxusedidx */
5415 ptrarray->minusedidx = MIN(ptrarray->minusedidx, idx);
5416 ptrarray->maxusedidx = MAX(ptrarray->maxusedidx, idx);
5417 }
5418 else if( idx >= ptrarray->firstidx && idx < ptrarray->firstidx + ptrarray->valssize )
5419 {
5420 /* set the array value of the index to zero */
5421 ptrarray->vals[idx - ptrarray->firstidx] = NULL;
5422
5423 /* check, if we can tighten the min/maxusedidx */
5424 if( idx == ptrarray->minusedidx )
5425 {
5426 assert(ptrarray->maxusedidx >= 0);
5427 assert(ptrarray->maxusedidx < ptrarray->firstidx + ptrarray->valssize);
5428 do
5429 {
5430 ptrarray->minusedidx++;
5431 }
5432 while( ptrarray->minusedidx <= ptrarray->maxusedidx
5433 && ptrarray->vals[ptrarray->minusedidx - ptrarray->firstidx] == NULL );
5434 if( ptrarray->minusedidx > ptrarray->maxusedidx )
5435 {
5436 ptrarray->minusedidx = INT_MAX;
5437 ptrarray->maxusedidx = INT_MIN;
5438