Scippy

SCIP

Solving Constraint Integer Programs

history.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-2014 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file history.c
17  * @brief methods for branching and inference history
18  * @author Tobias Achterberg
19  */
20 
21 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
22 
23 #include <assert.h>
24 
25 #include "scip/def.h"
26 #include "scip/set.h"
27 #include "scip/history.h"
28 #include "scip/pub_misc.h"
29 #include "scip/pub_history.h"
30 
31 #ifndef NDEBUG
32 #include "scip/struct_history.h"
33 #endif
34 
35 /*
36  * methods for branching and inference history
37  */
38 
39 /** creates an empty history entry */
41  SCIP_HISTORY** history, /**< pointer to store branching and inference history */
42  BMS_BLKMEM* blkmem /**< block memory */
43  )
44 {
45  assert(history != NULL);
46 
47  SCIP_ALLOC( BMSallocBlockMemory(blkmem, history) );
48 
49  SCIPhistoryReset(*history);
50 
51  return SCIP_OKAY;
52 }
53 
54 /** frees a history entry */
56  SCIP_HISTORY** history, /**< pointer to branching and inference history */
57  BMS_BLKMEM* blkmem /**< block memory */
58  )
59 {
60  assert(history != NULL);
61  assert(*history != NULL);
62 
63  BMSfreeBlockMemory(blkmem, history);
64 }
65 
66 /** resets history entry to zero */
68  SCIP_HISTORY* history /**< branching and inference history */
69  )
70 {
71  assert(history != NULL);
72 
73  history->pscostcount[0] = 0.0;
74  history->pscostcount[1] = 0.0;
75  history->pscostsum[0] = 0.0;
76  history->pscostsum[1] = 0.0;
77  history->vsids[0] = 0.0;
78  history->vsids[1] = 0.0;
79  history->conflengthsum[0] = 0.0;
80  history->conflengthsum[1] = 0.0;
81  history->inferencesum[0] = 0.0;
82  history->inferencesum[1] = 0.0;
83  history->cutoffsum[0] = 0.0;
84  history->cutoffsum[1] = 0.0;
85  history->nactiveconflicts[0] = 0;
86  history->nactiveconflicts[1] = 0;
87  history->nbranchings[0] = 0;
88  history->nbranchings[1] = 0;
89  history->branchdepthsum[0] = 0;
90  history->branchdepthsum[1] = 0;
91 }
92 
93 /** unites two history entries by adding the values of the second one to the first one */
95  SCIP_HISTORY* history, /**< branching and inference history */
96  SCIP_HISTORY* addhistory, /**< history values to add to history */
97  SCIP_Bool switcheddirs /**< should the history entries be united with switched directories */
98  )
99 {
100  int d;
101 
102  assert(history != NULL);
103  assert(addhistory != NULL);
104 
105  d = switcheddirs ? 1 : 0;
106 
107  history->pscostcount[0] += addhistory->pscostcount[d];
108  history->pscostcount[1] += addhistory->pscostcount[1-d];
109  history->pscostsum[0] += addhistory->pscostsum[d];
110  history->pscostsum[1] += addhistory->pscostsum[1-d];
111  history->vsids[0] += addhistory->vsids[d];
112  history->vsids[1] += addhistory->vsids[1-d];
113  history->conflengthsum[0] += addhistory->conflengthsum[d];
114  history->conflengthsum[1] += addhistory->conflengthsum[1-d];
115  history->inferencesum[0] += addhistory->inferencesum[d];
116  history->inferencesum[1] += addhistory->inferencesum[1-d];
117  history->cutoffsum[0] += addhistory->cutoffsum[d];
118  history->cutoffsum[1] += addhistory->cutoffsum[1-d];
119  history->nactiveconflicts[0] += addhistory->nactiveconflicts[d];
120  history->nactiveconflicts[1] += addhistory->nactiveconflicts[1-d];
121  history->nbranchings[0] += addhistory->nbranchings[d];
122  history->nbranchings[1] += addhistory->nbranchings[1-d];
123  history->branchdepthsum[0] += addhistory->branchdepthsum[d];
124  history->branchdepthsum[1] += addhistory->branchdepthsum[1-d];
125 }
126 
127 /** updates the pseudo costs for a change of "solvaldelta" in the variable's LP solution value and a change of "objdelta"
128  * in the LP's objective value
129  */
131  SCIP_HISTORY* history, /**< branching and inference history */
132  SCIP_SET* set, /**< global SCIP settings */
133  SCIP_Real solvaldelta, /**< difference of variable's new LP value - old LP value */
134  SCIP_Real objdelta, /**< difference of new LP's objective value - old LP's objective value */
135  SCIP_Real weight /**< weight of this update in pseudo cost sum (added to pscostcount) */
136  )
137 {
138  SCIP_Real distance;
139  SCIP_Real eps;
140  int dir;
141 
142  assert(history != NULL);
143  assert(set != NULL);
144  assert(!SCIPsetIsInfinity(set, REALABS(solvaldelta)));
145  assert(!SCIPsetIsInfinity(set, objdelta));
146  assert(!SCIPsetIsNegative(set, objdelta));
147  assert(0.0 < weight && weight <= 1.0);
148 
149  if( SCIPsetIsPositive(set, solvaldelta) )
150  {
151  /* variable's solution value moved upwards */
152  dir = 1;
153  distance = solvaldelta;
154  }
155  else if( SCIPsetIsNegative(set, solvaldelta) )
156  {
157  /* variable's solution value moved downwards */
158  dir = 0;
159  distance = -solvaldelta;
160  }
161  else
162  {
163  /* the variable's solution value didn't change, and the pseudo costs cannot be updated */
164  return;
165  }
166  assert(dir == 0 || dir == 1);
167  assert(SCIPsetIsPositive(set, distance));
168 
169  /* apply a lower limit on the distance to avoid numerical instabilities due to very large summands */
170  eps = SCIPsetPseudocosteps(set);
171  distance = MAX(distance, eps);
172 
173  /* slightly increase objective delta, s.t. pseudo cost values are not zero, and fractionalities are
174  * always used at least a bit
175  */
176  objdelta += SCIPsetPseudocostdelta(set);
177 
178  /* update the pseudo cost values */
179  history->pscostcount[dir] += weight;
180  history->pscostsum[dir] += weight * objdelta/distance;
181 
182  SCIPdebugMessage("updated pseudo costs of history %p: dir=%d, distance=%g, objdelta=%g, weight=%g -> %g/%g\n",
183  (void*)history, dir, distance, objdelta, weight, history->pscostcount[dir], history->pscostsum[dir]);
184 }
185 
186 /**@name Value based history
187  *
188  * Value based history methods
189  *
190  * @{
191  */
192 
193 /** creates an empty value history */
195  SCIP_VALUEHISTORY** valuehistory, /**< pointer to store the value based branching and inference histories */
196  BMS_BLKMEM* blkmem /**< block memory */
197  )
198 {
199  assert(valuehistory != NULL);
200 
201  SCIP_ALLOC( BMSallocBlockMemory(blkmem, valuehistory) );
202 
203  (*valuehistory)->nvalues = 0;
204  (*valuehistory)->sizevalues = 5;
205 
206  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*valuehistory)->histories, (*valuehistory)->sizevalues) );
207  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*valuehistory)->values, (*valuehistory)->sizevalues) );
208 
209  return SCIP_OKAY;
210 }
211 
212 /** frees a value history */
214  SCIP_VALUEHISTORY** valuehistory, /**< pointer to value based history */
215  BMS_BLKMEM* blkmem /**< block memory */
216  )
217 {
218  assert(valuehistory != NULL);
219 
220  if( *valuehistory != NULL )
221  {
222  int i;
223 
224  for( i = (*valuehistory)->nvalues-1; i >= 0; --i )
225  SCIPhistoryFree(&(*valuehistory)->histories[i], blkmem);
226 
227  BMSfreeBlockMemoryArray(blkmem, &(*valuehistory)->histories, (*valuehistory)->sizevalues);
228  BMSfreeBlockMemoryArray(blkmem, &(*valuehistory)->values, (*valuehistory)->sizevalues);
229 
230  BMSfreeBlockMemory(blkmem, valuehistory);
231  }
232 }
233 
234 /** finds for the given domain value the history if it does not exist yet it will be created */
236  SCIP_VALUEHISTORY* valuehistory, /**< value based history */
237  BMS_BLKMEM* blkmem, /**< block memory */
238  SCIP_SET* set, /**< global SCIP settings */
239  SCIP_Real value, /**< domain value of interest */
240  SCIP_HISTORY** history /**< pointer to store the history for the given domain value */
241  )
242 {
243  int pos;
244 
245  assert(valuehistory != NULL);
246  assert(blkmem != NULL);
247  assert(set != NULL);
248  assert(history != NULL);
249 
250  *history = NULL;
251 
252  if( valuehistory->nvalues == 0 || !SCIPsortedvecFindReal(valuehistory->values, value, valuehistory->nvalues, &pos) )
253  {
254  /* check if we need to resize the history array */
255  if( valuehistory->nvalues == valuehistory->sizevalues )
256  {
257  int newsize;
258 
259  newsize = SCIPsetCalcMemGrowSize(set, valuehistory->sizevalues + 1);
260  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &valuehistory->histories, valuehistory->nvalues, newsize) );
261  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &valuehistory->values, valuehistory->nvalues, newsize) );
262  valuehistory->sizevalues = newsize;
263  }
264 
265  /* create new empty history entry */
266  SCIP_CALL( SCIPhistoryCreate(history, blkmem) );
267 
268  /* insert new history into the value based history array */
269  SCIPsortedvecInsertRealPtr(valuehistory->values, (void**)valuehistory->histories, value, (void*)(*history), &valuehistory->nvalues, NULL);
270  }
271  else
272  (*history) = valuehistory->histories[pos];
273 
274  assert(*history != NULL);
275 
276  return SCIP_OKAY;
277 }
278 
279 /** scales the conflict score values with the given scalar for each value history entry */
281  SCIP_VALUEHISTORY* valuehistory, /**< value based history */
282  SCIP_Real scalar /**< scalar to multiply the conflict scores with */
283  )
284 {
285  if( valuehistory != NULL )
286  {
287  int i;
288 
289  for( i = valuehistory->nvalues-1; i >= 0; --i )
290  {
291  SCIPhistoryScaleVSIDS(valuehistory->histories[i], scalar);
292  }
293  }
294 }
295 
296 
297 /*
298  * simple functions implemented as defines
299  */
300 
301 #ifndef NDEBUG
302 
303 /* In debug mode, the following methods are implemented as function calls to ensure
304  * type validity.
305  * In optimized mode, the methods are implemented as defines to improve performance.
306  * However, we want to have them in the library anyways, so we have to undef the defines.
307  */
308 
309 #undef SCIPvaluehistoryGetNValues
310 #undef SCIPvaluehistoryGetHistories
311 #undef SCIPvaluehistoryGetValues
312 
313 /** return the number of (domain) values for which a history exists */
315  SCIP_VALUEHISTORY* valuehistory /**< value based history */
316  )
317 {
318  assert(valuehistory != NULL);
319 
320  return valuehistory->nvalues;
321 }
322 
323 /** return the array containing the histories for the individual (domain) values */
325  SCIP_VALUEHISTORY* valuehistory /**< value based history */
326  )
327 {
328  assert(valuehistory != NULL);
329 
330  return valuehistory->histories;
331 }
332 
333 /** return the array containing the (domain) values for which a history exists */
335  SCIP_VALUEHISTORY* valuehistory /**< value based history */
336  )
337 {
338  assert(valuehistory != NULL);
339 
340  return valuehistory->values;
341 }
342 
343 #endif
344 
345 /**@} */
346 
347 /*
348  * simple functions implemented as defines
349  */
350 
351 #ifndef NDEBUG
352 
353 /* In debug mode, the following methods are implemented as function calls to ensure
354  * type validity.
355  * In optimized mode, the methods are implemented as defines to improve performance.
356  * However, we want to have them in the library anyways, so we have to undef the defines.
357  */
358 
359 #undef SCIPbranchdirOpposite
360 #undef SCIPhistoryGetPseudocost
361 #undef SCIPhistoryGetPseudocostCount
362 #undef SCIPhistoryIsPseudocostEmpty
363 #undef SCIPhistoryIncVSIDS
364 #undef SCIPhistoryScaleVSIDS
365 #undef SCIPhistoryGetVSIDS
366 #undef SCIPhistoryIncNActiveConflicts
367 #undef SCIPhistoryGetNActiveConflicts
368 #undef SCIPhistoryGetAvgConflictlength
369 #undef SCIPhistoryIncNBranchings
370 #undef SCIPhistoryIncInferenceSum
371 #undef SCIPhistoryIncCutoffSum
372 #undef SCIPhistoryGetNBranchings
373 #undef SCIPhistoryGetInferenceSum
374 #undef SCIPhistoryGetAvgInferences
375 #undef SCIPhistoryGetCutoffSum
376 #undef SCIPhistoryGetAvgCutoffs
377 #undef SCIPhistoryGetAvgBranchdepth
378 
379 /** returns the opposite direction of the given branching direction */
381  SCIP_BRANCHDIR dir /**< branching direction */
382  )
383 {
386 }
387 
388 /** returns the expected dual gain for moving the corresponding variable by "solvaldelta" */
390  SCIP_HISTORY* history, /**< branching and inference history */
391  SCIP_Real solvaldelta /**< difference of variable's new LP value - old LP value */
392  )
393 {
394  assert(history != NULL);
395 
396  if( solvaldelta >= 0.0 )
397  return solvaldelta * (history->pscostcount[1] > 0.0 ? history->pscostsum[1] / history->pscostcount[1] : 1.0);
398  else
399  return -solvaldelta * (history->pscostcount[0] > 0.0 ? history->pscostsum[0] / history->pscostcount[0] : 1.0);
400 }
401 
402 /** returns the (possible fractional) number of (partial) pseudo cost updates performed on this pseudo cost entry in
403  * the given branching direction
404  */
406  SCIP_HISTORY* history, /**< branching and inference history */
407  SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
408  )
409 {
410  assert(history != NULL);
411  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
412  assert((int)dir == 0 || (int)dir == 1);
413 
414  return history->pscostcount[dir];
415 }
416 
417 /** returns whether the pseudo cost entry is empty in the given branching direction (whether no value was added yet) */
419  SCIP_HISTORY* history, /**< branching and inference history */
420  SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
421  )
422 {
423  assert(history != NULL);
424  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
425  assert((int)dir == 0 || (int)dir == 1);
426 
427  return (history->pscostcount[dir] == 0.0);
428 }
429 
430 /** increases the conflict score of the history entry by the given weight */
432  SCIP_HISTORY* history, /**< branching and inference history */
433  SCIP_BRANCHDIR dir, /**< branching direction */
434  SCIP_Real weight /**< weight of this update in conflict score */
435  )
436 {
437  assert(history != NULL);
438  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
439  assert((int)dir == 0 || (int)dir == 1);
440 
441  history->vsids[dir] += weight;
442 }
443 
444 /** scales the conflict score values with the given scalar */
446  SCIP_HISTORY* history, /**< branching and inference history */
447  SCIP_Real scalar /**< scalar to multiply the conflict scores with */
448  )
449 {
450  assert(history != NULL);
451 
452  history->vsids[0] *= scalar;
453  history->vsids[1] *= scalar;
454 }
455 
456 /** gets the conflict score of the history entry */
458  SCIP_HISTORY* history, /**< branching and inference history */
459  SCIP_BRANCHDIR dir /**< branching direction */
460  )
461 {
462  assert(history != NULL);
463  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
464  assert((int)dir == 0 || (int)dir == 1);
465 
466  return history->vsids[dir];
467 }
468 
469 /** increases the number of active conflicts by one and the overall length of the history entry by the given weight */
471  SCIP_HISTORY* history, /**< branching and inference history */
472  SCIP_BRANCHDIR dir, /**< branching direction */
473  SCIP_Real length /**< length of the conflict */
474  )
475 {
476  assert(history != NULL);
477  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
478  assert((int)dir == 0 || (int)dir == 1);
479  assert(length >= 0.0);
480 
481  history->nactiveconflicts[dir]++;
482  history->conflengthsum[dir] += length;
483 }
484 
485 /** gets the number of active conflicts of the history entry */
487  SCIP_HISTORY* history, /**< branching and inference history */
488  SCIP_BRANCHDIR dir /**< branching direction */
489  )
490 {
491  assert(history != NULL);
492  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
493  assert((int)dir == 0 || (int)dir == 1);
494 
495  return history->nactiveconflicts[dir];
496 }
497 
498 /** gets the average conflict length of the history entry */
500  SCIP_HISTORY* history, /**< branching and inference history */
501  SCIP_BRANCHDIR dir /**< branching direction */
502  )
503 {
504  assert(history != NULL);
505  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
506  assert((int)dir == 0 || (int)dir == 1);
507 
508  return history->conflengthsum[dir] > 0.0 ? (SCIP_Real)history->nactiveconflicts[dir]/(SCIP_Real)history->conflengthsum[dir] : 0.0;
509 }
510 
511 /** increases the number of branchings counter */
513  SCIP_HISTORY* history, /**< branching and inference history */
514  SCIP_BRANCHDIR dir, /**< branching direction (downwards, or upwards) */
515  int depth /**< depth at which the bound change took place */
516  )
517 {
518  assert(history != NULL);
519  assert(depth >= 1);
520  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
521  assert((int)dir == 0 || (int)dir == 1);
522 
523  history->nbranchings[dir]++;
524  history->branchdepthsum[dir] += depth;
525 }
526 
527 /** increases the number of inferences counter by a certain value */
529  SCIP_HISTORY* history, /**< branching and inference history */
530  SCIP_BRANCHDIR dir, /**< branching direction (downwards, or upwards) */
531  SCIP_Real weight /**< weight of this update in inference score */
532  )
533 {
534  assert(history != NULL);
535  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
536  assert((int)dir == 0 || (int)dir == 1);
537  assert(history->nbranchings[dir] >= 1);
538  assert(weight >= 0.0);
539 
540  history->inferencesum[dir] += weight;
541 }
542 
543 /** increases the number of cutoffs counter */
545  SCIP_HISTORY* history, /**< branching and inference history */
546  SCIP_BRANCHDIR dir, /**< branching direction (downwards, or upwards) */
547  SCIP_Real weight /**< weight of this update in cutoff score */
548  )
549 {
550  assert(history != NULL);
551  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
552  assert((int)dir == 0 || (int)dir == 1);
553  assert(history->nbranchings[dir] >= 1);
554  assert(weight >= 0.0);
555 
556  history->cutoffsum[dir] += weight;
557 }
558 
559 /** get number of branchings counter */
561  SCIP_HISTORY* history, /**< branching and inference history */
562  SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
563  )
564 {
565  assert(history != NULL);
566  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
567  assert((int)dir == 0 || (int)dir == 1);
568 
569  return history->nbranchings[dir];
570 }
571 
572 /** get number of inferences counter */
574  SCIP_HISTORY* history, /**< branching and inference history */
575  SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
576  )
577 {
578  assert(history != NULL);
579  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
580  assert((int)dir == 0 || (int)dir == 1);
581 
582  return history->inferencesum[dir];
583 }
584 
585 /** returns the average number of inferences per branching */
587  SCIP_HISTORY* history, /**< branching and inference history */
588  SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
589  )
590 {
591  assert(history != NULL);
592  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
593  assert((int)dir == 0 || (int)dir == 1);
594 
595  return history->nbranchings[dir] > 0 ? (SCIP_Real)history->inferencesum[dir]/(SCIP_Real)history->nbranchings[dir] : 0.0;
596 }
597 
598 /** get number of cutoffs counter */
600  SCIP_HISTORY* history, /**< branching and inference history */
601  SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
602  )
603 {
604  assert(history != NULL);
605  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
606  assert((int)dir == 0 || (int)dir == 1);
607 
608  return history->cutoffsum[dir];
609 }
610 
611 /** returns the average number of cutoffs per branching */
613  SCIP_HISTORY* history, /**< branching and inference history */
614  SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
615  )
616 {
617  assert(history != NULL);
618  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
619  assert((int)dir == 0 || (int)dir == 1);
620 
621  return history->nbranchings[dir] > 0 ? (SCIP_Real)history->cutoffsum[dir]/(SCIP_Real)history->nbranchings[dir] : 0.0;
622 }
623 
624 /** returns the average depth of bound changes due to branching */
626  SCIP_HISTORY* history, /**< branching and inference history */
627  SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
628  )
629 {
630  assert(history != NULL);
631  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
632  assert((int)dir == 0 || (int)dir == 1);
633 
634  return history->nbranchings[dir] > 0 ? (SCIP_Real)history->branchdepthsum[dir]/(SCIP_Real)history->nbranchings[dir] : 1.0;
635 }
636 
637 #endif
638