SCIP Doxygen Documentation
Loading...
Searching...
No Matches
prop_probing.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-2026 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 prop_probing.c
26 * @ingroup DEFPLUGINS_PROP
27 * @brief probing propagator
28 * @author Tobias Achterberg
29 * @author Matthias Miltenberger
30 * @author Michael Winkler
31 */
32
33/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
34
36#include "scip/prop_probing.h"
37#include "scip/pub_message.h"
38#include "scip/pub_misc.h"
39#include "scip/pub_misc_sort.h"
40#include "scip/pub_prop.h"
41#include "scip/pub_tree.h"
42#include "scip/pub_var.h"
43#include "scip/scip_branch.h"
44#include "scip/scip_general.h"
45#include "scip/scip_lp.h"
46#include "scip/scip_mem.h"
47#include "scip/scip_message.h"
48#include "scip/scip_numerics.h"
49#include "scip/scip_param.h"
50#include "scip/scip_prob.h"
51#include "scip/scip_probing.h"
52#include "scip/scip_prop.h"
55#include "scip/scip_timing.h"
56#include "scip/scip_tree.h"
57#include "scip/scip_var.h"
58
59
60#define PROP_NAME "probing"
61#define PROP_DESC "probing propagator on binary variables"
62#define PROP_TIMING SCIP_PROPTIMING_AFTERLPLOOP
63#define PROP_PRIORITY -100000 /**< propagation priority */
64#define PROP_FREQ -1 /**< propagation frequency */
65#define PROP_DELAY TRUE /**< should propagation method be delayed, if other propagators found
66 * reductions? */
67#define PROP_PRESOL_PRIORITY -100000 /**< priority of the presolving method (>= 0: before, < 0: after constraint handlers); combined with presolvers */
68#define PROP_PRESOLTIMING SCIP_PRESOLTIMING_EXHAUSTIVE /* timing of the presolving method (fast, medium, or exhaustive) */
69#define PROP_PRESOL_MAXROUNDS -1 /**< maximal number of presolving rounds the presolver participates in (-1: no
70 * limit) */
71#define MAXDNOM 10000LL /**< maximal denominator for simple rational fixed values */
72
73
74/* @todo check for restricting the maximal number of implications that can be added by probing */
75
76/* sorting of probing variables, two different variants are implemeneted */
77/* #define VARIANT_B */
78
79
80/*
81 * Default parameter settings
82 */
83
84#define DEFAULT_MAXRUNS 1 /**< maximal number of runs, probing participates in (-1: no limit) */
85#define DEFAULT_PROPROUNDS -1 /**< maximal number of propagation rounds in probing subproblems */
86#define DEFAULT_MAXFIXINGS 25 /**< maximal number of fixings found, until probing is interrupted
87 * (0: don't interrupt) */
88#define DEFAULT_MAXUSELESS 1000 /**< maximal number of successive probings without fixings,
89 * until probing is aborted (0: don't abort) */
90#define DEFAULT_MAXTOTALUSELESS 50 /**< maximal number of successive probings without fixings, bound changes,
91 * and implications, until probing is aborted (0: don't abort) */
92#define DEFAULT_MAXSUMUSELESS 0 /**< maximal number of probings without fixings, until probing is aborted
93 * (0: don't abort) */
94#define DEFAULT_MAXDEPTH -1 /**< maximal depth until propagation is executed(-1: no limit) */
95#define DEFAULT_RANDSEED 59 /**< random initial seed */
96
97/*
98 * Data structures
99 */
100
101/** propagator data */
102struct SCIP_PropData
103{
104 SCIP_VAR** sortedvars; /**< problem variables sorted by number of rounding locks, used in presolving */
105 int* nprobed; /**< array of numbers how often we already probed on each variables */
106 int noldtotalvars; /**< number of total variables in problem */
107 int nsortedvars; /**< number of problem variables, used in presolving */
108 int nsortedbinvars; /**< number of binary problem variables, used in presolving */
109 int maxruns; /**< maximal number of runs, probing participates in (-1: no limit) */
110 int proprounds; /**< maximal number of propagation rounds in probing subproblems */
111 int maxfixings; /**< maximal number of fixings found, until probing is interrupted
112 * (0: don't interrupt) */
113 int maxuseless; /**< maximal number of successive probings without fixings,
114 * until probing is aborted (0: don't abort) */
115 int maxtotaluseless; /**< maximal number of successive probings without fixings, bound changes,
116 * and implications, until probing is aborted (0: don't abort) */
117 int maxsumuseless; /**< maximal number of probings without fixings, until probing is aborted
118 * (0: don't abort) */
119 int startidx; /**< starting variable index of next call, used in presolving */
120 int lastsortstartidx; /**< last starting variable index where the variables have been sorted, used in presolving */
121 int nfixings; /**< total number of fixings found in probing */
122 int naggregations; /**< total number of aggregations found in probing */
123 int nimplications; /**< total number of implications found in probing */
124 int nbdchgs; /**< total number of bound changes found in probing */
125 int nuseless; /**< current number of successive useless probings */
126 int ntotaluseless; /**< current number of successive totally useless probings */
127 int nsumuseless; /**< current number of useless probings */
128 int maxdepth; /**< maximal depth until propagation is executed */
129 SCIP_Longint lastnode; /**< last node where probing was applied, or -1 for presolving, and -2 for not applied yet */
130 SCIP_RANDNUMGEN* randnumgen; /**< random number generator */
131};
132
133
134/*
135 * Local methods
136 */
137/** initializes the propagator data */
138static
140 SCIP_PROPDATA* propdata /**< propagator data */
141 )
142{
143 assert(propdata != NULL);
144
145 propdata->sortedvars = NULL;
146 propdata->nprobed = NULL;
147 propdata->noldtotalvars = 0;
148 propdata->nsortedvars = 0;
149 propdata->nsortedbinvars = 0;
150 propdata->startidx = 0;
151 propdata->lastsortstartidx = -1;
152 propdata->nfixings = 0;
153 propdata->naggregations = 0;
154 propdata->nimplications = 0;
155 propdata->nbdchgs = 0;
156 propdata->nuseless = 0;
157 propdata->ntotaluseless = 0;
158 propdata->nsumuseless = 0;
159 propdata->lastnode = -2;
160 propdata->randnumgen = NULL;
161
162 return SCIP_OKAY;
163}
164
165/** frees the sorted vars array */
166static
168 SCIP* scip, /**< SCIP data structure */
169 SCIP_PROPDATA* propdata /**< propagator data */
170 )
171{
172 assert(propdata != NULL);
173
174 if( propdata->sortedvars != NULL )
175 {
176 int i;
177
178 /* release variables */
179 for( i = 0; i < propdata->nsortedvars; ++i )
180 {
181 SCIP_CALL( SCIPreleaseVar(scip, &propdata->sortedvars[i]) );
182 }
183 SCIPfreeMemoryArray(scip, &propdata->sortedvars);
184 propdata->nsortedvars = 0;
185 propdata->nsortedbinvars = 0;
186 }
187
188 SCIPfreeMemoryArrayNull(scip, &propdata->nprobed);
189 propdata->noldtotalvars = 0;
190
191 return SCIP_OKAY;
192}
193
194/** sorts the binary variables starting with the given index by rounding locks and implications */
195static
197 SCIP* scip, /**< SCIP data structure */
198 SCIP_PROPDATA* propdata, /**< propagator data */
199 SCIP_VAR** vars, /**< problem variables to be sorted */
200 int nvars, /**< number of problem variables to be sorted */
201 int firstidx /**< first index that should be subject to sorting */
202 )
203{
204 SCIP_VAR** sortedvars;
205 int nsortedvars;
206 SCIP_Real* scores;
207 int i;
208 int minnprobings;
209 SCIP_Real maxscore;
210 int nlocksdown;
211 int nlocksup;
212 int nimplzero;
213 int nimplone;
214 int nclqzero;
215 int nclqone;
216
217 assert(propdata != NULL);
218 assert(propdata->nprobed != NULL);
219
220 assert(vars != NULL || nvars == 0);
221
222 nsortedvars = nvars - firstidx;
223 if( nsortedvars <= 0 )
224 return SCIP_OKAY;
225
226 assert(vars != NULL);
227
228 sortedvars = &(vars[firstidx]);
229
230 SCIPdebugMsg(scip, "resorting probing variables %d to %d\n", firstidx, nvars-1);
231
232 /* sort the variables by number of rounding locks and implications */
233 SCIP_CALL( SCIPallocBufferArray(scip, &scores, nsortedvars) );
234
235 maxscore = -1.0;
236 minnprobings = INT_MAX;
237
238 /* determine maximal possible score and minimal number of probings over all variables */
239 for( i = 0; i < nvars; ++i )
240 {
241 SCIP_VAR* var;
242 SCIP_Real tmp;
243
244 var = vars[i];
245
247 assert(propdata->noldtotalvars > SCIPvarGetIndex(var));
248 assert(propdata->nprobed[SCIPvarGetIndex(var)] >= 0);
249
250 if( SCIPvarIsActive(var) )
251 {
254 nimplzero = SCIPvarGetNImpls(var, FALSE);
255 nimplone = SCIPvarGetNImpls(var, TRUE);
256 nclqzero = SCIPvarGetNCliques(var, FALSE);
257 nclqone = SCIPvarGetNCliques(var, TRUE);
258
259#ifndef VARIANT_B
260 tmp = -MAX(nlocksdown, nlocksup)
261 + 10.0 * MIN(nimplzero, nimplone)
262 + 100.0 * MIN(nclqzero, nclqone);
263#else
264 tmp = - ABS(nlocksdown - nlocksup)
265 + MIN(nlocksdown, nlocksup)
266 + 500.0 * nimplzero + 50.0 * nimplone
267 + 50000.0 * nclqzero + 5000.0 * nclqone;
268#endif
269
270 if( tmp > maxscore )
271 maxscore = tmp;
272 if( propdata->nprobed[SCIPvarGetIndex(var)] < minnprobings )
273 minnprobings = propdata->nprobed[SCIPvarGetIndex(var)];
274 }
275 }
276
277 /* correct number of probings on each variable by minimal number of probings */
278 if( minnprobings > 0 )
279 {
280 for( i = 0; i < nvars; ++i )
281 {
282 SCIP_VAR* var;
283
284 var = vars[i];
285
286 if( SCIPvarIsActive(var) )
287 propdata->nprobed[SCIPvarGetIndex(var)] -= minnprobings;
288 }
289 }
290
291 for( i = 0; i < nsortedvars; ++i )
292 {
293 SCIP_VAR* var;
294 var = sortedvars[i];
295
297
298 /* prefer variables that we did not already probe on */
299 if( SCIPvarIsActive(var) )
300 {
301 SCIP_Real randomoffset;
304 nimplzero = SCIPvarGetNImpls(var, FALSE);
305 nimplone = SCIPvarGetNImpls(var, TRUE);
306 nclqzero = SCIPvarGetNCliques(var, FALSE);
307 nclqone = SCIPvarGetNCliques(var, TRUE);
308
309 assert(propdata->noldtotalvars > SCIPvarGetIndex(var));
310 assert(propdata->nprobed[SCIPvarGetIndex(var)] >= 0);
311
312 /* use a random offset to break possible ties arbitrarily */
313 randomoffset = SCIPrandomGetReal(propdata->randnumgen, 0.0, 0.5);
314
315#ifndef VARIANT_B
316 scores[i] = -maxscore * propdata->nprobed[SCIPvarGetIndex(var)]
317 - MAX(nlocksdown, nlocksup)
318 + 10.0 * MIN(nimplzero, nimplone)
319 + 100.0 * MIN(nclqzero, nclqone) /*lint !e790*/
320 - randomoffset; /* to break ties randomly */
321#else
322 scores[i] = -maxscore * propdata->nprobed[SCIPvarGetIndex(var)]
323 - ABS(nlocksdown - nlocksup)
324 + MIN(nlocksdown, nlocksup)
325 + 500.0 * nimplzero + 50.0 * nimplone /*lint !e790*/
326 + 50000.0 * nclqzero + 5000.0 * nclqone /*lint !e790*/
327 - randomoffset; /* to break ties randomly */
328#endif
329 }
330 else
331 scores[i] = -SCIPinfinity(scip);
332 }
333
334 SCIPsortDownRealPtr(scores, (void**) sortedvars, nsortedvars);
335
336 SCIPfreeBufferArray(scip, &scores);
337
338 return SCIP_OKAY;
339}
340
341/** the main probing loop */
342static
344 SCIP* scip, /**< SCIP data structure */
345 SCIP_PROPDATA* propdata, /**< propagator data */
346 SCIP_VAR** vars, /**< problem variables */
347 int nvars, /**< number of problem variables */
348 int nbinvars, /**< number of binary variables */
349 int* startidx, /**< pointer to store starting variable index of next call */
350 int* nfixedvars, /**< pointer to store number of fixed variables */
351 int* naggrvars, /**< pointer to store number of aggregated variables */
352 int* nchgbds, /**< pointer to store number of changed bounds */
353 int oldnfixedvars, /**< number of previously fixed variables */
354 int oldnaggrvars, /**< number of previously aggregated variables */
355 SCIP_Bool* delay, /**< pointer to store whether propagator should be delayed */
356 SCIP_Bool* cutoff /**< pointer to store whether cutoff occurred */
357 )
358{
359 SCIP_Real* zeroimpllbs;
360 SCIP_Real* zeroimplubs;
361 SCIP_Real* zeroproplbs;
362 SCIP_Real* zeropropubs;
363 SCIP_Real* oneimpllbs;
364 SCIP_Real* oneimplubs;
365 SCIP_Real* oneproplbs;
366 SCIP_Real* onepropubs;
367 int localnfixedvars;
368 int localnaggrvars;
369 int localnchgbds;
370 int localnimplications;
371 int maxfixings;
372 int maxuseless;
373 int maxtotaluseless;
374 int maxsumuseless;
375 int i;
376 int oldstartidx;
377 SCIP_Bool aborted;
378 SCIP_Bool looped;
379
380 assert(vars != NULL);
381 assert(nbinvars > 0);
382
383 maxfixings = (propdata->maxfixings > 0 ? propdata->maxfixings : INT_MAX);
384 maxuseless = (propdata->maxuseless > 0 ? propdata->maxuseless : INT_MAX);
385 maxtotaluseless = (propdata->maxtotaluseless > 0 ? propdata->maxtotaluseless : INT_MAX);
386 maxsumuseless = (propdata->maxsumuseless > 0 ? propdata->maxsumuseless : INT_MAX);
387 aborted = FALSE;
388 looped = FALSE;
389 oldstartidx = *startidx;
390 i = *startidx;
391
392 /* get temporary memory for storing probing results */
393 SCIP_CALL( SCIPallocBufferArray(scip, &zeroimpllbs, nvars) );
394 SCIP_CALL( SCIPallocBufferArray(scip, &zeroimplubs, nvars) );
395 SCIP_CALL( SCIPallocBufferArray(scip, &zeroproplbs, nvars) );
396 SCIP_CALL( SCIPallocBufferArray(scip, &zeropropubs, nvars) );
397 SCIP_CALL( SCIPallocBufferArray(scip, &oneimpllbs, nvars) );
398 SCIP_CALL( SCIPallocBufferArray(scip, &oneimplubs, nvars) );
399 SCIP_CALL( SCIPallocBufferArray(scip, &oneproplbs, nvars) );
400 SCIP_CALL( SCIPallocBufferArray(scip, &onepropubs, nvars) );
401
402 /* for each binary variable, probe fixing the variable to zero and one */
403 *delay = FALSE;
404 *cutoff = FALSE;
405 do
406 {
407 for( ; i < nbinvars && !(*cutoff); ++i )
408 {
409 SCIP_Bool localcutoff;
410 SCIP_Bool probingzero;
411 SCIP_Bool probingone;
412
413 /* check whether probing should be aborted */
414 if( propdata->nuseless >= maxuseless || propdata->ntotaluseless >= maxtotaluseless || propdata->nsumuseless >= maxsumuseless || SCIPisStopped(scip) )
415 {
417 " (%.1fs) probing: %d/%d (%.1f%%) - %d fixings, %d aggregations, %d implications, %d bound changes\n",
418 SCIPgetSolvingTime(scip), i+1, nbinvars, 100.0*(SCIP_Real)(i+1)/(SCIP_Real)nbinvars,
419 propdata->nfixings, propdata->naggregations, propdata->nimplications, propdata->nbdchgs);
420
421 aborted = TRUE;
422
423 if( propdata->nuseless >= maxuseless )
424 {
426 " (%.1fs) probing aborted: %d/%d successive useless probings\n", SCIPgetSolvingTime(scip),
427 propdata->nuseless, maxuseless);
428 }
429 else if( propdata->ntotaluseless >= maxtotaluseless )
430 {
432 " (%.1fs) probing aborted: %d/%d successive totally useless probings\n", SCIPgetSolvingTime(scip),
433 propdata->ntotaluseless, maxtotaluseless);
434 }
435 else if( propdata->nsumuseless >= maxsumuseless )
436 {
438 " (%.1fs) probing aborted: %d/%d useless probings in total\n", SCIPgetSolvingTime(scip),
439 propdata->nsumuseless, maxsumuseless);
440 }
441 else
442 {
445 " (%.1fs) probing aborted: solving stopped\n", SCIPgetSolvingTime(scip));
446 }
447 break;
448 }
449
450 /* check if we already fixed enough variables for this round, or probed on all variables */
451 if( *nfixedvars - oldnfixedvars + *naggrvars - oldnaggrvars >= maxfixings || (looped && oldstartidx == i) )
452 {
453 if( *nfixedvars - oldnfixedvars + *naggrvars - oldnaggrvars > 0 )
454 *delay = TRUE;
455 else
456 aborted = TRUE;
457 break;
458 }
459
460 /* display probing status */
461 if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && (i+1) % 100 == 0 )
462 {
463 SCIP_VERBLEVEL verblevel;
464
465 verblevel = ((i+1) % 1000 == 0 ? SCIP_VERBLEVEL_HIGH : SCIP_VERBLEVEL_FULL);
466 SCIPverbMessage(scip, verblevel, NULL,
467 " (%.1fs) probing: %d/%d (%.1f%%) - %d fixings, %d aggregations, %d implications, %d bound changes\n",
468 SCIPgetSolvingTime(scip), i+1, nbinvars, 100.0*(SCIP_Real)(i+1)/(SCIP_Real)nbinvars,
469 propdata->nfixings, propdata->naggregations, propdata->nimplications, propdata->nbdchgs);
470 }
471
472 /* ignore variables, that were fixed, aggregated, or deleted in prior probings */
474 || SCIPvarGetLbLocal(vars[i]) > 0.5 || SCIPvarGetUbLocal(vars[i]) < 0.5 )
475 continue;
476
477 if( propdata->nuseless > 0 )
478 propdata->nsumuseless++;
479 else
480 propdata->nsumuseless = MAX(propdata->nsumuseless-1, 0);
481 propdata->nuseless++;
482 propdata->ntotaluseless++;
483
484 /* determine whether one probing should happen */
485 probingone = TRUE;
487 probingone = FALSE;
488
489 if( probingone )
490 {
491 /* apply probing for fixing the variable to one */
492 SCIP_CALL( SCIPapplyProbingVar(scip, vars, nvars, i, SCIP_BOUNDTYPE_LOWER, 1.0, propdata->proprounds,
493 oneimpllbs, oneimplubs, oneproplbs, onepropubs, &localcutoff) );
494
495 if( localcutoff )
496 {
497 SCIP_Bool fixed;
498
500 {
501 /* the variable can be fixed to FALSE */
502 SCIP_CALL( SCIPfixVar(scip, vars[i], 0.0, cutoff, &fixed) );
503 assert(fixed);
504 }
505 else
506 {
507 SCIP_CALL( SCIPtightenVarUb(scip, vars[i], 0.0, TRUE, cutoff, &fixed) );
508 }
509
510 if( fixed )
511 {
512 SCIPdebugMsg(scip, "fixed probing variable <%s> to 0.0, nlocks=(%d/%d)\n",
515 (*nfixedvars)++;
516 propdata->nfixings++;
517 propdata->nuseless = 0;
518 propdata->ntotaluseless = 0;
519 }
520 else if( *cutoff )
521 {
522 SCIPdebugMsg(scip, "tightening upper bound of probing variable <%s> to 0.0 led to a cutoff\n",
524 }
525 continue; /* don't try downwards direction, because the variable is already fixed */
526 }
527
528 /* ignore variables, that were fixed, aggregated, or deleted in prior probings
529 * (propagators in one-probe might have found global fixings but did not trigger the localcutoff)
530 */
532 || SCIPvarGetLbLocal(vars[i]) > 0.5 || SCIPvarGetUbLocal(vars[i]) < 0.5 )
533 continue;
534 }
535
536 /* determine whether zero probing should happen */
537 probingzero = TRUE;
539 probingzero = FALSE;
540
541 if( probingzero )
542 {
543 /* apply probing for fixing the variable to zero */
544 SCIP_CALL( SCIPapplyProbingVar(scip, vars, nvars, i, SCIP_BOUNDTYPE_UPPER, 0.0, propdata->proprounds,
545 zeroimpllbs, zeroimplubs, zeroproplbs, zeropropubs, &localcutoff) );
546
547 if( localcutoff )
548 {
549 SCIP_Bool fixed;
550
552 {
553 /* the variable can be fixed to TRUE */
554 SCIP_CALL( SCIPfixVar(scip, vars[i], 1.0, cutoff, &fixed) );
555 }
556 else
557 {
558 SCIP_CALL( SCIPtightenVarLb(scip, vars[i], 1.0, TRUE, cutoff, &fixed) );
559 }
560
561 if( fixed )
562 {
563 SCIPdebugMsg(scip, "fixed probing variable <%s> to 1.0, nlocks=(%d/%d)\n",
566 (*nfixedvars)++;
567 propdata->nfixings++;
568 propdata->nuseless = 0;
569 propdata->ntotaluseless = 0;
570 }
571 else if( *cutoff )
572 {
573 SCIPdebugMsg(scip, "tightening lower bound of probing variable <%s> to 1.0 led to a cutoff\n",
575 }
576 continue; /* don't analyze probing deductions, because the variable is already fixed */
577 }
578 }
579
580 /* not have to check deductions if only one probing direction has been checked */
581 if( !probingzero || !probingone )
582 continue;
583
584 assert(propdata->noldtotalvars > SCIPvarGetIndex(vars[i]));
585
586 /* count number of probings on each variable */
587 propdata->nprobed[SCIPvarGetIndex(vars[i])] += 1;
588
589 /* analyze probing deductions */
590 localnfixedvars = 0;
591 localnaggrvars = 0;
592 localnimplications = 0;
593 localnchgbds = 0;
595 nvars, vars, zeroimpllbs, zeroimplubs, zeroproplbs, zeropropubs, oneimpllbs, oneimplubs, oneproplbs, onepropubs,
596 &localnfixedvars, &localnaggrvars, &localnimplications, &localnchgbds, cutoff) );
597
598 *nfixedvars += localnfixedvars;
599 *naggrvars += localnaggrvars;
600 *nchgbds += localnchgbds;
601 propdata->nfixings += localnfixedvars;
602 propdata->naggregations += localnaggrvars;
603 propdata->nbdchgs += localnchgbds;
604 propdata->nimplications += localnimplications;
605
606 if( localnfixedvars > 0 || localnaggrvars > 0 )
607 {
608 SCIPdebugMsg(scip, "probing on <%s> led to %d fixed and %d aggregated variables\n", SCIPvarGetName(vars[i]),
609 localnfixedvars, localnaggrvars);
610 propdata->nuseless = 0;
611 propdata->ntotaluseless = 0;
612 }
613 if( localnimplications > 0 || localnchgbds > 0 )
614 propdata->ntotaluseless = 0;
615 }
616
617 looped = TRUE;
618
619 /* check if we reached the end of all binary variables but did not stop, so we start from the beginning */
620 if( i == nbinvars && !(*cutoff) && !(*delay) && !aborted )
621 {
623 " (%.1fs) probing cycle finished: starting next cycle\n", SCIPgetSolvingTime(scip));
624 i = 0;
625
627 {
628 SCIP_VAR** newvars;
629 int nnewvars;
630 int nnewbinvars;
631 int nnewintvars;
632 int nnewimplvars;
633 int lastidx;
634 int v;
635
636 assert(vars == propdata->sortedvars);
637 assert(nbinvars == propdata->nsortedbinvars);
638
639 /* release old variables and free memory */
640 for( v = propdata->nsortedvars - 1; v >= 0; --v )
641 {
642 SCIP_CALL( SCIPreleaseVar(scip, &propdata->sortedvars[v]) );
643 }
644 SCIPfreeMemoryArray(scip, &propdata->sortedvars);
645 propdata->nsortedvars = 0;
646 propdata->nsortedbinvars = 0;
647
648 /* get new variables */
649 nnewvars = SCIPgetNVars(scip);
650 newvars = SCIPgetVars(scip);
651 SCIP_CALL( SCIPduplicateMemoryArray(scip, &(propdata->sortedvars), newvars, nnewvars) ); /*lint !e666*/
652 propdata->nsortedvars = nnewvars;
653
654 nnewbinvars = SCIPgetNBinVars(scip);
655 nnewintvars = SCIPgetNIntVars(scip);
656 nnewimplvars = SCIPgetNImplVars(scip);
657
658 /* determine implicit binary variables */
659 lastidx = nnewbinvars + nnewintvars + nnewimplvars;
660 for( v = nnewbinvars; v < lastidx; ++v )
661 {
662 if( SCIPvarIsBinary(propdata->sortedvars[v]) )
663 {
664 SCIPswapPointers((void**) &(propdata->sortedvars[nnewbinvars]), (void**) &(propdata->sortedvars[v]));
665 ++nnewbinvars;
666 }
667 }
668 propdata->nsortedbinvars = nnewbinvars;
669
670 nbinvars = nnewbinvars;
671 vars = propdata->sortedvars;
672 nvars = propdata->nsortedvars;
673
674 SCIP_CALL( SCIPreallocBufferArray(scip, &zeroimpllbs, nvars) );
675 SCIP_CALL( SCIPreallocBufferArray(scip, &zeroimplubs, nvars) );
676 SCIP_CALL( SCIPreallocBufferArray(scip, &zeroproplbs, nvars) );
677 SCIP_CALL( SCIPreallocBufferArray(scip, &zeropropubs, nvars) );
678 SCIP_CALL( SCIPreallocBufferArray(scip, &oneimpllbs, nvars) );
679 SCIP_CALL( SCIPreallocBufferArray(scip, &oneimplubs, nvars) );
680 SCIP_CALL( SCIPreallocBufferArray(scip, &oneproplbs, nvars) );
681 SCIP_CALL( SCIPreallocBufferArray(scip, &onepropubs, nvars) );
682
683 /* correct oldstartidx which is used for early termination */
684 if( oldstartidx >= nbinvars )
685 oldstartidx = nbinvars - 1;
686
687 /* capture variables to make sure, the variables are not deleted */
688 for( v = propdata->nsortedvars - 1; v >= 0; --v )
689 {
690 SCIP_CALL( SCIPcaptureVar(scip, propdata->sortedvars[v]) );
691 }
692
693 if( nnewbinvars == 0 )
694 {
695 *startidx = 0;
696 propdata->lastsortstartidx = -1;
697 propdata->nuseless = 0;
698 propdata->ntotaluseless = 0;
699
700 goto TERMINATE;
701 }
702
703 /* resorting here might lead to probing a second time on the same variable */
704 SCIP_CALL( sortVariables(scip, propdata, propdata->sortedvars, propdata->nsortedbinvars, 0) );
705 propdata->lastsortstartidx = 0;
706 }
707 }
708 }
709 while( i == 0 && !(*cutoff) && !(*delay) && !aborted );
710
711 *startidx = i;
712
713 TERMINATE:
714 /* free temporary memory */
715 SCIPfreeBufferArray(scip, &onepropubs);
716 SCIPfreeBufferArray(scip, &oneproplbs);
717 SCIPfreeBufferArray(scip, &oneimplubs);
718 SCIPfreeBufferArray(scip, &oneimpllbs);
719 SCIPfreeBufferArray(scip, &zeropropubs);
720 SCIPfreeBufferArray(scip, &zeroproplbs);
721 SCIPfreeBufferArray(scip, &zeroimplubs);
722 SCIPfreeBufferArray(scip, &zeroimpllbs);
723
724 return SCIP_OKAY;
725}
726
727
728/*
729 * Callback methods of propagator
730 */
731
732/** copy method for constraint handler plugins (called when SCIP copies plugins) */
733static
734SCIP_DECL_PROPCOPY(propCopyProbing)
735{ /*lint --e{715}*/
736 assert(scip != NULL);
737 assert(prop != NULL);
738
740
741 /* call inclusion method for propagator */
743
744 return SCIP_OKAY;
745}
746
747
748/** destructor of propagator to free user data (called when SCIP is exiting) */
749static
750SCIP_DECL_PROPFREE(propFreeProbing)
751{ /*lint --e{715}*/
752 SCIP_PROPDATA* propdata;
753
754 /* free propagator data */
755 propdata = SCIPpropGetData(prop);
756 assert(propdata != NULL);
757 assert(propdata->sortedvars == NULL);
758 assert(propdata->nsortedvars == 0);
759 assert(propdata->nsortedbinvars == 0);
760
761 SCIPfreeBlockMemory(scip, &propdata);
762 SCIPpropSetData(prop, NULL);
763
764 return SCIP_OKAY;
765}
766
767
768/** initialization method of propagator (called after problem was transformed) */
769static
770SCIP_DECL_PROPINIT(propInitProbing)
771{ /*lint --e{715}*/
772 SCIP_PROPDATA* propdata;
773
774 propdata = SCIPpropGetData(prop);
775 assert(propdata != NULL);
776
777 SCIP_CALL( initPropdata(propdata) );
778
779 /* create random number generator */
780 SCIP_CALL( SCIPcreateRandom(scip, &propdata->randnumgen,
782
783 return SCIP_OKAY;
784}
785
786
787/** deinitialization method of propagator (called before transformed problem is freed) */
788static
789SCIP_DECL_PROPEXIT(propExitProbing)
790{ /*lint --e{715}*/
791 SCIP_PROPDATA* propdata;
792
793 propdata = SCIPpropGetData(prop);
794 assert(propdata != NULL);
795
796 SCIP_CALL( freeSortedvars(scip, propdata) );
797 assert(propdata->sortedvars == NULL);
798 assert(propdata->nsortedvars == 0);
799 assert(propdata->nsortedbinvars == 0);
800
801 /* free random number generator */
802 SCIPfreeRandom(scip, &propdata->randnumgen);
803
804 return SCIP_OKAY;
805}
806
807/** presolving initialization method of propagator (called when presolving is about to begin) */
808static
809SCIP_DECL_PROPINITPRE(propInitpreProbing)
810{ /*lint --e{715}*/
811 SCIP_PROPDATA* propdata;
812
813 propdata = SCIPpropGetData(prop);
814 assert(propdata != NULL);
815
816 propdata->lastnode = -2;
817
818 return SCIP_OKAY;
819}
820
821
822/** presolving deinitialization method of propagator (called after presolving has been finished) */
823static
824SCIP_DECL_PROPEXITPRE(propExitpreProbing)
825{ /*lint --e{715}*/
826 SCIP_PROPDATA* propdata;
827
828 propdata = SCIPpropGetData(prop);
829 assert(propdata != NULL);
830
831 /* delete the vars array, if the maximal number of runs are exceeded */
832 if( propdata->maxruns >= 0 && SCIPgetNRuns(scip) >= propdata->maxruns )
833 {
834 SCIP_CALL( freeSortedvars(scip, propdata) );
835 assert(propdata->sortedvars == NULL);
836 assert(propdata->nsortedvars == 0);
837 assert(propdata->nsortedbinvars == 0);
838 }
839
840 return SCIP_OKAY;
841}
842
843
844/** solving process initialization method of propagator (called when branch and bound process is about to begin) */
845static
846SCIP_DECL_PROPINITSOL(propInitsolProbing)
847{
848 /*lint --e{715}*/
849 SCIP_PROPDATA* propdata;
850
851 propdata = SCIPpropGetData(prop);
852 assert(propdata != NULL);
853
854 /* reset all propdata elements for stopping propagation earlier */
855 propdata->nuseless = 0;
856 propdata->ntotaluseless = 0;
857 propdata->nsumuseless = 0;
858
859 return SCIP_OKAY;
860}
861
862
863/** presolve method of propagator */
864static
865SCIP_DECL_PROPPRESOL(propPresolProbing)
866{ /*lint --e{715}*/
867 SCIP_PROPDATA* propdata;
868 int nvars;
869 int nbinvars;
870 int nintvars;
871 int nimplvars;
872 int oldnfixedvars;
873 int oldnaggrvars;
874 int oldnchgbds;
875 int oldnimplications;
876 int ntotalvars;
877 SCIP_Bool delay;
879
880 assert(result != NULL);
881
883
884 nbinvars = SCIPgetNBinVars(scip);
885 nintvars = SCIPgetNIntVars(scip);
886 nimplvars = SCIPgetNImplVars(scip);
887
888 /* if we have no binary variable anymore, we stop probing */
889 if( nbinvars + nintvars + nimplvars == 0 )
890 return SCIP_OKAY;
891
892 /* get propagator data */
893 propdata = SCIPpropGetData(prop);
894 assert(propdata != NULL);
895
896 /* check, if probing should be applied in the current run */
897 if( propdata->maxruns >= 0 && SCIPgetNRuns(scip) > propdata->maxruns )
898 return SCIP_OKAY;
899
900 /* if no domains changed since the last call, we don't need to probe */
901 if( propdata->lastnode == -1 && nnewfixedvars == 0 && nnewaggrvars == 0 && nnewchgbds == 0 && nnewholes == 0 )
902 return SCIP_OKAY;
903
904 SCIPdebugMsg(scip, "executing probing (used %.1f sec)\n", SCIPpropGetTime(prop));
905
907
908 /* allow some additional probings */
909 propdata->nuseless -= propdata->nuseless/10;
910 propdata->ntotaluseless -= propdata->ntotaluseless/10;
911
912 /* get variable data */
913 if( propdata->sortedvars == NULL )
914 {
916 int lastidx;
917 int v;
918
919 assert(propdata->startidx == 0);
920
922
923 SCIP_CALL( SCIPduplicateMemoryArray(scip, &(propdata->sortedvars), vars, nvars) );
924 propdata->nsortedvars = nvars;
925
926 /* determine implicit binary variables */
927 lastidx = nbinvars + nintvars + nimplvars;
928 for( v = nbinvars; v < lastidx; ++v )
929 {
930 if( SCIPvarIsBinary(propdata->sortedvars[v]) )
931 {
932 SCIPswapPointers((void**) &(propdata->sortedvars[nbinvars]), (void**) &(propdata->sortedvars[v]));
933 ++nbinvars;
934 }
935 }
936 propdata->nsortedbinvars = nbinvars;
937
938 /* capture variables to make sure, the variables are not deleted */
939 for( v = propdata->nsortedvars - 1; v >= 0 ; --v )
940 {
941 SCIP_CALL( SCIPcaptureVar(scip, propdata->sortedvars[v]) );
942 }
943 }
944
945 if( propdata->nsortedbinvars == 0 )
946 return SCIP_OKAY;
947
948 /* number of total variables is not decreasing, and we can identify every variable by their index, so allocate
949 * enough space
950 */
951 ntotalvars = SCIPgetNTotalVars(scip);
952 if( propdata->noldtotalvars < ntotalvars )
953 {
954 SCIP_CALL( SCIPreallocMemoryArray(scip, &propdata->nprobed, ntotalvars) );
955 BMSclearMemoryArray(&(propdata->nprobed[propdata->noldtotalvars]), ntotalvars - propdata->noldtotalvars); /*lint !e866*/
956 propdata->noldtotalvars = ntotalvars;
957 }
958
959 propdata->lastnode = -1;
960
961 /* sort the binary variables by number of rounding locks, if at least 100 variables were probed since last sort */
962 if( propdata->lastsortstartidx < 0 || propdata->startidx - propdata->lastsortstartidx >= 100 )
963 {
964 SCIP_CALL( sortVariables(scip, propdata, propdata->sortedvars, propdata->nsortedbinvars, propdata->startidx) );
965 propdata->lastsortstartidx = propdata->startidx;
966 }
967
968 oldnfixedvars = *nfixedvars;
969 oldnaggrvars = *naggrvars;
970 oldnchgbds = *nchgbds;
971 oldnimplications = propdata->nimplications;
972
973 /* start probing on variables */
974 SCIP_CALL( applyProbing(scip, propdata, propdata->sortedvars, propdata->nsortedvars, propdata->nsortedbinvars,
975 &(propdata->startidx), nfixedvars, naggrvars, nchgbds, oldnfixedvars, oldnaggrvars, &delay, &cutoff) );
976
977 /* adjust result code */
978 if( cutoff )
980 else
981 {
982 if( delay )
983 {
984 /* probing was interrupted because it reached the maximal fixings parameter, so we want to rerun it at the next call */
985 propdata->lastnode = -2;
986 }
987
988 if( *nfixedvars > oldnfixedvars || *naggrvars > oldnaggrvars || *nchgbds > oldnchgbds
989 || propdata->nimplications > oldnimplications )
991 }
992
993 return SCIP_OKAY;
994}
995
996
997/** execution method of propagator */
998static
999SCIP_DECL_PROPEXEC(propExecProbing)
1000{ /*lint --e{715}*/
1001 SCIP_PROPDATA* propdata;
1002 SCIP_VAR** vars;
1003 SCIP_VAR** binvars;
1004 int nvars;
1005 int nbinvars;
1006 int i;
1007 int nfixedvars;
1008 int naggrvars;
1009 int nchgbds;
1010 int oldnfixedvars;
1011 int oldnaggrvars;
1012 int oldnchgbds;
1013 SCIPdebug( int oldnimplications; )
1014 int startidx;
1015 int ntotalvars;
1016 SCIP_Bool delay;
1018
1019 assert(result != NULL);
1020
1022
1023 /* avoid recursive infinity loop */
1024 if( SCIPinProbing(scip) )
1025 return SCIP_OKAY;
1026
1027 /* only call propagation on branching candidates, if an optimal LP solution is at hand */
1029 return SCIP_OKAY;
1030
1031 /* get propagator data */
1032 propdata = SCIPpropGetData(prop);
1033 assert(propdata != NULL);
1034
1035 /* if already called stop */
1036 if( propdata->lastnode == SCIPnodeGetNumber(SCIPgetCurrentNode(scip)) )
1037 return SCIP_OKAY;
1038
1039 /* if maximal depth for propagation is reached, stop */
1040 if( propdata->maxdepth >= 0 && propdata->maxdepth < SCIPgetDepth(scip) )
1041 return SCIP_OKAY;
1042
1043 propdata->lastnode = SCIPnodeGetNumber(SCIPgetCurrentNode(scip));
1044
1045 /* get (number of) fractional variables that should be integral */
1046 /* todo check if integrating fractional implicit integer variables is beneficial for probing */
1048 nbinvars = 0;
1049
1050 /* alloc array for fractional binary variables */
1052
1053 /* copy binary variables to array binvars */
1054 for( i = 0; i < nvars; ++i )
1055 {
1056 SCIP_VAR* var;
1057 var = vars[i];
1058
1059 assert(var != NULL);
1060 if( SCIPvarIsBinary(var) )
1061 {
1064
1065 binvars[nbinvars] = var;
1066 ++nbinvars;
1067 }
1068 }
1069 SCIPdebugMsg(scip, "problem <%s> node %" SCIP_LONGINT_FORMAT " probing propagation found %d of %d possible probing candidates\n", SCIPgetProbName(scip), SCIPnodeGetNumber(SCIPgetCurrentNode(scip)), nbinvars, nvars);
1070
1071 if( nbinvars == 0 )
1072 {
1074 goto TERMINATE;
1075 }
1076
1077 /* number of total variables is not decreasing, and we can identify every variable by their index, so allocate
1078 * enough space
1079 */
1080 ntotalvars = SCIPgetNTotalVars(scip);
1081 if( propdata->noldtotalvars < ntotalvars )
1082 {
1083 SCIP_CALL( SCIPreallocMemoryArray(scip, &propdata->nprobed, ntotalvars) );
1084 BMSclearMemoryArray(&(propdata->nprobed[propdata->noldtotalvars]), ntotalvars - propdata->noldtotalvars); /*lint !e866*/
1085 propdata->noldtotalvars = ntotalvars;
1086 }
1087
1088 /* sort binary variables */
1089 SCIP_CALL( sortVariables(scip, propdata, binvars, nbinvars, 0) );
1090
1091 oldnfixedvars = 0;
1092 oldnaggrvars = 0;
1093 oldnchgbds = 0;
1094 nfixedvars = 0;
1095 naggrvars = 0;
1096 nchgbds = 0;
1097 startidx = 0;
1098 SCIPdebug( oldnimplications = propdata->nimplications; )
1099
1100 /* start probing on found variables */
1101 SCIP_CALL( applyProbing(scip, propdata, binvars, nbinvars, nbinvars, &startidx, &nfixedvars, &naggrvars, &nchgbds, oldnfixedvars, oldnaggrvars, &delay, &cutoff) );
1102 SCIPdebug( SCIPdebugMsg(scip, "probing propagation found %d fixings, %d aggregation, %d nchgbds, and %d implications\n",
1103 nfixedvars, naggrvars, nchgbds, (propdata->nimplications) - oldnimplications); )
1104
1105 if( delay )
1106 {
1107 /* probing was interrupted because it reached the maximal fixings parameter, so we want to rerun it at the next call */
1108 propdata->lastnode = -2;
1109 }
1110
1111 /* adjust result code */
1112 if( cutoff )
1114 else if( nfixedvars > oldnfixedvars || naggrvars > oldnaggrvars || nchgbds > oldnchgbds )
1116
1117 TERMINATE:
1118 SCIPfreeBufferArray(scip, &binvars);
1119
1120 return SCIP_OKAY; /*lint !e438*/
1121}
1122
1123
1124/** propagation conflict resolving method of propagator */
1125static
1126SCIP_DECL_PROPRESPROP(propRespropProbing)
1127{ /*lint --e{715}*/
1129
1130 return SCIP_OKAY;
1131}
1132
1133
1134/*
1135 * propagator specific interface methods
1136 */
1137
1138/** creates the probing propagator and includes it in SCIP */
1140 SCIP* scip /**< SCIP data structure */
1141 )
1142{
1143 SCIP_PROPDATA* propdata;
1144 SCIP_PROP* prop;
1145
1146 /* create probing propagator data */
1147 SCIP_CALL( SCIPallocBlockMemory(scip, &propdata) );
1148 SCIP_CALL( initPropdata(propdata) );
1149
1150 /* include propagator */
1152 propExecProbing, propdata) );
1153
1154 assert(prop != NULL);
1155
1156 /* set optional callbacks via setter functions */
1157 SCIP_CALL( SCIPsetPropCopy(scip, prop, propCopyProbing) );
1158 SCIP_CALL( SCIPsetPropFree(scip, prop, propFreeProbing) );
1159 SCIP_CALL( SCIPsetPropInit(scip, prop, propInitProbing) );
1160 SCIP_CALL( SCIPsetPropExit(scip, prop, propExitProbing) );
1161 SCIP_CALL( SCIPsetPropInitsol(scip, prop, propInitsolProbing) );
1162 SCIP_CALL( SCIPsetPropInitpre(scip, prop, propInitpreProbing) );
1163 SCIP_CALL( SCIPsetPropExitpre(scip, prop, propExitpreProbing) );
1166 SCIP_CALL( SCIPsetPropResprop(scip, prop, propRespropProbing) );
1167
1168 /* add probing propagator parameters */
1170 "propagating/" PROP_NAME "/maxruns",
1171 "maximal number of runs, probing participates in (-1: no limit)",
1172 &propdata->maxruns, FALSE, DEFAULT_MAXRUNS, -1, INT_MAX, NULL, NULL) );
1174 "propagating/" PROP_NAME "/proprounds",
1175 "maximal number of propagation rounds in probing subproblems (-1: no limit, 0: auto)",
1176 &propdata->proprounds, TRUE, DEFAULT_PROPROUNDS, -1, INT_MAX, NULL, NULL) );
1178 "propagating/" PROP_NAME "/maxfixings",
1179 "maximal number of fixings found, until probing is interrupted (0: don't iterrupt)",
1180 &propdata->maxfixings, TRUE, DEFAULT_MAXFIXINGS, 0, INT_MAX, NULL, NULL) );
1182 "propagating/" PROP_NAME "/maxuseless",
1183 "maximal number of successive probings without fixings, until probing is aborted (0: don't abort)",
1184 &propdata->maxuseless, TRUE, DEFAULT_MAXUSELESS, 0, INT_MAX, NULL, NULL) );
1186 "propagating/" PROP_NAME "/maxtotaluseless",
1187 "maximal number of successive probings without fixings, bound changes, and implications, until probing is aborted (0: don't abort)",
1188 &propdata->maxtotaluseless, TRUE, DEFAULT_MAXTOTALUSELESS, 0, INT_MAX, NULL, NULL) );
1190 "propagating/" PROP_NAME "/maxsumuseless",
1191 "maximal number of probings without fixings, until probing is aborted (0: don't abort)",
1192 &propdata->maxsumuseless, TRUE, DEFAULT_MAXSUMUSELESS, 0, INT_MAX, NULL, NULL) );
1194 "propagating/" PROP_NAME "/maxdepth",
1195 "maximal depth until propagation is executed(-1: no limit)",
1196 &propdata->maxdepth, TRUE, DEFAULT_MAXDEPTH, -1, INT_MAX, NULL, NULL) );
1197
1198 return SCIP_OKAY;
1199}
1200
1201
1202/** applies and evaluates probing of a single variable in the given direction and bound */
1204 SCIP* scip, /**< SCIP data structure */
1205 SCIP_VAR** vars, /**< problem variables */
1206 int nvars, /**< number of problem variables */
1207 int probingpos, /**< variable number to apply probing on */
1208 SCIP_BOUNDTYPE boundtype, /**< which bound should be changed */
1209 SCIP_Real bound, /**< which bound should be set */
1210 int maxproprounds, /**< maximal number of propagation rounds (-1: no limit, 0: parameter settings) */
1211 SCIP_Real* impllbs, /**< array to store lower bounds after applying implications and cliques */
1212 SCIP_Real* implubs, /**< array to store upper bounds after applying implications and cliques */
1213 SCIP_Real* proplbs, /**< array to store lower bounds after full propagation */
1214 SCIP_Real* propubs, /**< array to store upper bounds after full propagation */
1215 SCIP_Bool* cutoff /**< pointer to store whether the probing direction is infeasible */
1216 )
1217{
1218 assert(impllbs != NULL);
1219 assert(implubs != NULL);
1220 assert(proplbs != NULL);
1221 assert(propubs != NULL);
1222 assert(cutoff != NULL);
1223 assert(0 <= probingpos && probingpos < nvars);
1226
1227 SCIPdebugMsg(scip, "applying probing on variable <%s> %s %g (nlocks=%d/%d, impls=%d/%d, clqs=%d/%d)\n",
1228 SCIPvarGetName(vars[probingpos]), boundtype == SCIP_BOUNDTYPE_UPPER ? "<=" : ">=", bound,
1231 SCIPvarGetNImpls(vars[probingpos], FALSE), SCIPvarGetNImpls(vars[probingpos], TRUE),
1232 SCIPvarGetNCliques(vars[probingpos], FALSE), SCIPvarGetNCliques(vars[probingpos], TRUE));
1233
1234 /* in debug mode we assert above that this trivial infeasibility does not occur (for performance reasons), but in
1235 * optimized mode we return safely
1236 */
1237 if( SCIPisLT(scip, bound, SCIPvarGetLbLocal(vars[probingpos]))
1238 || SCIPisGT(scip, bound, SCIPvarGetUbLocal(vars[probingpos])) )
1239 {
1240 SCIPdebugMsg(scip, " -> trivial infeasibility detected\n");
1241 *cutoff = TRUE;
1242 return SCIP_OKAY;
1243 }
1244
1245 /* start probing mode */
1247
1248 /* enables collection of variable statistics during probing */
1250
1251 /* fix variable */
1252 if( boundtype == SCIP_BOUNDTYPE_UPPER )
1253 {
1254 SCIP_CALL( SCIPchgVarUbProbing(scip, vars[probingpos], bound) );
1255 }
1256 else
1257 {
1258 assert(boundtype == SCIP_BOUNDTYPE_LOWER);
1259 SCIP_CALL( SCIPchgVarLbProbing(scip, vars[probingpos], bound) );
1260 }
1261
1262 /* @todo it might pay off to catch the bounds-tightened event on all variables and then only get the implied and
1263 * propagated bounds on those variables which where really changed on propagation
1264 */
1265
1266 /* apply propagation of implication graph and clique table */
1268 if( !(*cutoff) )
1269 {
1270 int i;
1271
1272 for( i = 0; i < nvars; ++i )
1273 {
1274 impllbs[i] = SCIPvarGetLbLocal(vars[i]);
1275 implubs[i] = SCIPvarGetUbLocal(vars[i]);
1276 }
1277
1278 /* apply propagation */
1279 SCIP_CALL( SCIPpropagateProbing(scip, maxproprounds, cutoff, NULL) );
1280 }
1281 else
1282 {
1283 SCIPdebugMsg(scip, "propagating probing implications after <%s> to %g led to a cutoff\n",
1284 SCIPvarGetName(vars[probingpos]), bound);
1285 }
1286
1287 /* evaluate propagation */
1288 if( !(*cutoff) )
1289 {
1290 int i;
1291
1292 for( i = 0; i < nvars; ++i )
1293 {
1294 proplbs[i] = SCIPvarGetLbLocal(vars[i]);
1295 propubs[i] = SCIPvarGetUbLocal(vars[i]);
1296 }
1297 }
1298
1299 /* exit probing mode */
1301
1302 return SCIP_OKAY;
1303}
1304
1305/** analyses boundchanges resulting from probing on a variable and performs deduced fixations, aggregations, and domain tightenings
1306 * Given a variable probingvar with domain [l,u] and bound tightening results from reducing the domain
1307 * once to [l,leftub] and once to [rightlb,u], the method computes and applies resulting variable fixations, aggregations,
1308 * implications, and bound changes. Variable probingvar does not need to be binary.
1309 * The whole domain of probingvar need to be covered by the left and right branches, i.e.,
1310 * we assume leftub >= rightlb for continuous variables or floor(leftub) >= ceil(rightlb)-1 for discrete variables.
1311 * Bounds after applying implications and cliques do not need to be provided, but if they are omitted and probingvar is a binary variable,
1312 * then already existing implications may be added.
1313 */
1315 SCIP* scip, /**< SCIP data structure */
1316 SCIP_VAR* probingvar, /**< the probing variable */
1317 SCIP_Real leftub, /**< upper bound of probing variable in left branch */
1318 SCIP_Real rightlb, /**< lower bound of probing variable in right branch */
1319 int nvars, /**< number of variables which bound changes should be analyzed */
1320 SCIP_VAR** vars, /**< variables which bound changes should be analyzed */
1321 SCIP_Real* leftimpllbs, /**< lower bounds after applying implications and cliques in left branch, or NULL */
1322 SCIP_Real* leftimplubs, /**< upper bounds after applying implications and cliques in left branch, or NULL */
1323 SCIP_Real* leftproplbs, /**< lower bounds after applying domain propagation in left branch */
1324 SCIP_Real* leftpropubs, /**< upper bounds after applying domain propagation in left branch */
1325 SCIP_Real* rightimpllbs, /**< lower bounds after applying implications and cliques in right branch, or NULL */
1326 SCIP_Real* rightimplubs, /**< upper bounds after applying implications and cliques in right branch, or NULL */
1327 SCIP_Real* rightproplbs, /**< lower bounds after applying domain propagation in right branch */
1328 SCIP_Real* rightpropubs, /**< upper bounds after applying domain propagation in right branch */
1329 int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
1330 int* naggrvars, /**< pointer to counter which is increased by the number of deduced variable aggregations */
1331 int* nimplications, /**< pointer to counter which is increased by the number of deduced implications */
1332 int* nchgbds, /**< pointer to counter which is increased by the number of deduced bound tightenings */
1333 SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
1334 )
1335{
1336 SCIP_Bool fixedleft;
1337 SCIP_Bool fixedright;
1338 SCIP_Bool probingvarisbinary;
1339 SCIP_Bool probingvarisinteger;
1340 int j;
1341
1342 assert(scip != NULL);
1343 assert(probingvar != NULL);
1344 assert(SCIPisGE(scip, leftub, SCIPvarGetLbLocal(probingvar))); /* left branch should not be empty by default */
1345 assert(SCIPisLE(scip, rightlb, SCIPvarGetUbLocal(probingvar))); /* right branch should not be empty by default */
1346 assert(vars != NULL || nvars == 0);
1347 assert(leftproplbs != NULL);
1348 assert(leftpropubs != NULL);
1349 assert(rightproplbs != NULL);
1350 assert(rightpropubs != NULL);
1351 assert(nfixedvars != NULL);
1352 assert(naggrvars != NULL);
1353 assert(nimplications != NULL);
1354 assert(nchgbds != NULL);
1355 assert(cutoff != NULL);
1356
1357 /* @todo the asserts below could be relaxed by taking domain holes into account */
1358 if( SCIPvarIsIntegral(probingvar) )
1359 {
1360 /* adjust bounds to actually used ones */
1361 leftub = SCIPfloor(scip, leftub);
1362 rightlb = SCIPceil(scip, rightlb);
1363
1364 probingvarisinteger = TRUE;
1365 probingvarisbinary = SCIPvarIsBinary(probingvar);
1366 }
1367 else
1368 {
1369 /* assert dichotomy in case of continuous var: leftub >= rightlb */
1370 assert(SCIPisGE(scip, leftub, rightlb));
1371 probingvarisbinary = FALSE;
1372 probingvarisinteger = FALSE;
1373 }
1374
1375 /* check if probing variable was fixed in the branches */
1376 fixedleft = SCIPisEQ(scip, SCIPvarGetLbLocal(probingvar), leftub);
1377 fixedright = SCIPisEQ(scip, SCIPvarGetUbLocal(probingvar), rightlb);
1378
1379 *cutoff = FALSE;
1380
1381 for( j = 0; j < nvars && !*cutoff; ++j )
1382 {
1383 SCIP_VAR* var;
1384 SCIP_Bool varisinteger;
1385 SCIP_Real newlb;
1386 SCIP_Real newub;
1387
1388 assert(vars != NULL); /* for flexelint */
1389
1390 var = vars[j];
1391 assert(var != NULL);
1392
1393 /* @todo: add holes, and even add holes if x was the probing variable and it followed a better bound on x itself */
1394 /* @todo: check if we probed on an integer variable, that this maybe led to aggregation on two other variables, i.e
1395 * probing on x <= 1 and x >= 2 led to y = 1, z = 1 and y = 0, z = 0 resp., which means y = Z
1396 */
1397
1398 /* if probing variable is binary, then there is nothing we could deduce here (variable should be fixed in both branches)
1399 * if it is not binary, we want to see if we found bound tightenings, even though it seems quite unlikely */
1400 if( var == probingvar && probingvarisbinary )
1401 continue;
1402
1403 /* new bounds of the variable is the union of the propagated bounds of the left and right case */
1404 newlb = MIN(leftproplbs[j], rightproplbs[j]);
1405 newub = MAX(leftpropubs[j], rightpropubs[j]);
1406 varisinteger = SCIPvarIsIntegral(var);
1407
1408 /* check for fixed variables */
1409 if( SCIPisEQ(scip, newlb, newub) )
1410 {
1411 SCIP_Real fixval;
1412 SCIP_Bool fixed;
1413
1414 if( !varisinteger )
1415 {
1416 /* in both probings, variable j is deduced to the same value: fix variable to this value */
1417 fixval = SCIPselectSimpleValue(newlb - 0.9 * SCIPepsilon(scip), newub + 0.9 * SCIPepsilon(scip), MAXDNOM);
1418 }
1419 else
1420 {
1421 fixval = newlb;
1422 }
1423
1425 {
1426 SCIP_CALL( SCIPfixVar(scip, var, fixval, cutoff, &fixed) );
1427 }
1428 else
1429 {
1430 SCIP_CALL( SCIPtightenVarLb(scip, var, fixval, TRUE, cutoff, &fixed) );
1431 if( !*cutoff )
1432 {
1433 SCIP_Bool tightened;
1434
1435 SCIP_CALL( SCIPtightenVarUb(scip, var, fixval, TRUE, cutoff, &tightened) );
1436 fixed &= tightened;
1437 }
1438 }
1439
1440 if( fixed )
1441 {
1442 SCIPdebugMsg(scip, "fixed variable <%s> to %g due to probing on <%s> with nlocks=(%d/%d)\n",
1443 SCIPvarGetName(var), fixval,
1446 (*nfixedvars)++;
1447 }
1448 else if( *cutoff )
1449 {
1450 SCIPdebugMsg(scip, "analyzing probing deduction of <%s> led to an infeasible fixing of variable <%s> to %g\n",
1451 SCIPvarGetName(probingvar), SCIPvarGetName(var), fixval);
1452 }
1453
1454 continue;
1455 }
1456 else
1457 {
1458 /* check for bound tightenings */
1459 SCIP_Real oldlb;
1460 SCIP_Real oldub;
1461 SCIP_Bool tightened;
1462 SCIP_Bool tightenlb;
1463 SCIP_Bool tightenub;
1464 SCIP_Bool force;
1465
1466 oldlb = SCIPvarGetLbLocal(var);
1467 oldub = SCIPvarGetUbLocal(var);
1468
1469 if( varisinteger )
1470 {
1471 force = TRUE;
1472 tightenlb = (newlb > oldlb + 0.5);
1473 tightenub = (newub < oldub - 0.5);
1474 }
1475 else
1476 {
1477 force = TRUE;
1478 tightenlb = SCIPisLbBetter(scip, newlb, oldlb, oldub);
1479 tightenub = SCIPisUbBetter(scip, newub, oldlb, oldub);
1480 }
1481
1482 if( tightenlb )
1483 {
1484 /* in both probings, variable j is deduced to be at least newlb: tighten lower bound */
1485 SCIP_CALL( SCIPtightenVarLb(scip, var, newlb, force, cutoff, &tightened) );
1486 if( tightened )
1487 {
1488 SCIPdebugMsg(scip, "tightened lower bound of variable <%s>[%g,%g] to %g due to probing on <%s> with nlocks=(%d/%d)\n",
1489 SCIPvarGetName(var), oldlb, oldub, newlb,
1492 (*nchgbds)++;
1493 }
1494 else if( *cutoff )
1495 {
1496 SCIPdebugMsg(scip, "analyzing probing deduction of <%s> led to an infeasible new lower bound of variable <%s> to %g\n",
1497 SCIPvarGetName(probingvar), SCIPvarGetName(var), newlb);
1498 }
1499 }
1500
1501 if( tightenub && !*cutoff )
1502 {
1503 /* in both probings, variable j is deduced to be at most newub: tighten upper bound */
1504 SCIP_CALL( SCIPtightenVarUb(scip, var, newub, force, cutoff, &tightened) );
1505 if( tightened )
1506 {
1507 SCIPdebugMsg(scip, "tightened upper bound of variable <%s>[%g,%g] to %g due to probing on <%s> with nlocks=(%d/%d)\n",
1508 SCIPvarGetName(var), oldlb, oldub, newub,
1511 (*nchgbds)++;
1512 }
1513 else if( *cutoff )
1514 {
1515 SCIPdebugMsg(scip, "analyzing probing deduction of <%s> led to an infeasible new lower bound of variable <%s> to %g\n",
1516 SCIPvarGetName(probingvar), SCIPvarGetName(var), newub);
1517 }
1518 }
1519 if( *cutoff )
1520 break;
1521 }
1522
1523 /* below we add aggregations and implications between probingvar and var,
1524 * we don't want this if both variables are the same
1525 */
1526 if( var == probingvar )
1527 continue;
1528
1529 /* check for aggregations and implications */
1530 if( fixedleft && fixedright &&
1531 SCIPisEQ(scip, leftproplbs[j], leftpropubs[j]) && SCIPisEQ(scip, rightproplbs[j], rightpropubs[j]) )
1532 {
1533 /* var is fixed whenever probingvar is fixed, i.e.,
1534 * var = leftproplbs[j] + (rightproplbs[j] - leftproplbs[j]) / (rightlb - leftub) * (probingvar - leftub)
1535 * -> both variables can be aggregated:
1536 * (rightlb - leftub) * (var - leftproplbs[j]) = (rightproplbs[j] - leftproplbs[j]) * (probingvar - leftub)
1537 * -> (rightlb - leftub) * var - (rightproplbs[j] - leftproplbs[j]) * probingvar = leftproplbs[j] * rightlb - rightproplbs[j] * leftub
1538 *
1539 * check for case where both variables are binary: leftub = 1, rightlb = 0
1540 * case leftproplbs[j] = 0, rightproplbs[j] = 1, i.e., var and probingvar are fixed to same value
1541 * -> aggregation is 1 * var - 1 * probingvar = 0 * 1 - 1 * 0 = 0 -> correct
1542 * case leftproplbs[j] = 1, rightproblbs[j] = 0, i.e., var and probingvar are fixed to opposite values
1543 * -> aggregation is 1 * var + 1 * probingvar = 1 * 1 - 0 * 0 = 0 -> correct
1544 */
1546 {
1547 SCIP_Bool aggregated;
1548 SCIP_Bool redundant;
1549
1550 SCIP_CALL( SCIPaggregateVars(scip, var, probingvar,
1551 rightlb - leftub, -(rightproplbs[j] - leftproplbs[j]), leftproplbs[j] * rightlb - rightproplbs[j] * leftub,
1552 cutoff, &redundant, &aggregated) );
1553
1554 if( aggregated )
1555 {
1556 SCIPdebugMsg(scip, "aggregated variables %g<%s> - %g<%s> == %g, nlocks=(%d/%d)\n",
1557 rightlb - leftub, SCIPvarGetName(var),
1558 rightproplbs[j] - leftproplbs[j], SCIPvarGetName(probingvar),
1559 leftproplbs[j] * rightlb - rightproplbs[j] * leftub,
1562 (*naggrvars)++;
1563 }
1564 if( *cutoff )
1565 {
1566 SCIPdebugMsg(scip, "analyzing probing deduction of <%s> led to an infeasible aggregation: %g<%s> - %g<%s> == %g\n",
1567 SCIPvarGetName(probingvar), rightlb - leftub, SCIPvarGetName(var),
1568 rightproplbs[j] - leftproplbs[j], SCIPvarGetName(probingvar),
1569 leftproplbs[j] * rightlb - rightproplbs[j] * leftub);
1570 }
1571 }
1572 else if( probingvarisinteger && SCIPnodeGetDepth(SCIPgetCurrentNode(scip)) == 0 )
1573 {
1574 /* if we are not in presolving, then we cannot do aggregations
1575 * but we can use variable bounds to code the same equality
1576 * var == ((leftproplbs[j] * rightlb - rightproplbs[j] * leftub) + (rightproplbs[j] - leftproplbs[j]) * probingvar) / (rightlb - leftub)
1577 */
1578 int nboundchanges;
1579
1580 assert(!SCIPisEQ(scip, leftub, rightlb));
1581
1582 SCIP_CALL( SCIPaddVarVlb(scip, var, probingvar, (rightproplbs[j] - leftproplbs[j]) / (rightlb - leftub), (leftproplbs[j] * rightlb - rightproplbs[j] * leftub) / (rightlb - leftub), cutoff, &nboundchanges) );
1583 (*nchgbds) += nboundchanges;
1584
1585 if( *cutoff )
1586 {
1587 SCIPdebugMsg(scip, "analyzing probing deduction of <%s> led to an infeasible vlb: %g<%s> - %g<%s> == %g\n",
1588 SCIPvarGetName(probingvar), rightlb - leftub, SCIPvarGetName(var),
1589 rightproplbs[j] - leftproplbs[j], SCIPvarGetName(probingvar),
1590 leftproplbs[j] * rightlb - rightproplbs[j] * leftub);
1591 }
1592 else
1593 {
1594 SCIP_CALL( SCIPaddVarVub(scip, var, probingvar, (rightproplbs[j] - leftproplbs[j]) / (rightlb - leftub), (leftproplbs[j] * rightlb - rightproplbs[j] * leftub) / (rightlb - leftub), cutoff, &nboundchanges) );
1595 (*nchgbds) += nboundchanges;
1596
1597 if( *cutoff )
1598 {
1599 SCIPdebugMsg(scip, "analyzing probing deduction of <%s> led to an infeasible vub: %g<%s> - %g<%s> == %g\n",
1600 SCIPvarGetName(probingvar), rightlb - leftub, SCIPvarGetName(var),
1601 rightproplbs[j] - leftproplbs[j], SCIPvarGetName(probingvar),
1602 leftproplbs[j] * rightlb - rightproplbs[j] * leftub);
1603 }
1604 }
1605 (*nimplications)++;
1606 }
1607 /* if probingvar is continuous and we are in solving stage, then we do nothing, but it's unlikely that we get
1608 * here (fixedleft && fixedright) with a continuous variable
1609 */
1610 }
1611 /* @todo: check if we can add variable lowerbounds/upperbounds on integer variables */
1612 /* can only add implications on binary variables which are globally valid */
1613 else if( probingvarisbinary && (SCIPgetStage(scip) != SCIP_STAGE_SOLVING || SCIPnodeGetDepth(SCIPgetCurrentNode(scip)) == 0) )
1614 {
1615 /* implications can be added only for binary variables */
1616 int nboundchanges;
1617
1618 /* since probing var is binary variable, probing should have fixed variable in both branches,
1619 * which is to 0.0 in the left branch and to 1.0 in the right branch */
1620 assert(fixedleft);
1621 assert(fixedright);
1622 assert(SCIPisZero(scip, leftub));
1623 assert(SCIPisEQ(scip, rightlb, 1.0));
1624
1625 if( SCIPisEQ(scip, newlb, leftpropubs[j]) && (leftimplubs == NULL || leftimplubs[j] > leftpropubs[j]) )
1626 {
1627 /* var is fixed to lower bound whenever probingvar is fixed to 0.0
1628 * and implication is not already known
1629 * -> insert implication: probingvar == 0 => var <= leftpropubs[j]
1630 */
1631 /*SCIPdebugMsg(scip, "found implication <%s> == 0 => <%s> == %g\n",
1632 SCIPvarGetName(probingvar), SCIPvarGetName(var), leftpropubs[j]);*/
1633 SCIP_CALL( SCIPaddVarImplication(scip, probingvar, FALSE, var, SCIP_BOUNDTYPE_UPPER, leftpropubs[j],
1634 cutoff, &nboundchanges) );
1635 (*nimplications)++;
1636 (*nchgbds) += nboundchanges;
1637
1638 if( *cutoff )
1639 {
1640 SCIPdebugMsg(scip, "analyzing probing deduction of <%s> led to an infeasible implication <%s> == 0 => <%s> == %g\n",
1641 SCIPvarGetName(probingvar), SCIPvarGetName(probingvar), SCIPvarGetName(var), leftpropubs[j]);
1642 }
1643 }
1644 else if( SCIPisEQ(scip, newub, leftproplbs[j]) && (leftimpllbs == NULL || leftimpllbs[j] < leftproplbs[j]) )
1645 {
1646 /* var is fixed to upper bound whenever probingvar is fixed to 0.0
1647 * and implication is not already known
1648 * -> insert implication: probingvar == 0 => var >= leftproplbs[j]
1649 */
1650 /*SCIPdebugMsg(scip, "found implication <%s> == 0 => <%s> == %g\n",
1651 SCIPvarGetName(probingvar), SCIPvarGetName(var), leftproplbs[j]);*/
1652 SCIP_CALL( SCIPaddVarImplication(scip, probingvar, FALSE, var, SCIP_BOUNDTYPE_LOWER, leftproplbs[j],
1653 cutoff, &nboundchanges) );
1654 (*nimplications)++;
1655 (*nchgbds) += nboundchanges;
1656
1657 if( *cutoff )
1658 {
1659 SCIPdebugMsg(scip, "analyzing probing deduction of <%s> led to an infeasible implication <%s> == 0 => <%s> == %g\n",
1660 SCIPvarGetName(probingvar), SCIPvarGetName(probingvar), SCIPvarGetName(var), leftproplbs[j]);
1661 }
1662 }
1663 /* we can do an else here, since the case where var is fixed for both fixings of probingvar had been handled as aggregation */
1664 else if( SCIPisEQ(scip, newlb, rightpropubs[j]) && (rightimplubs == NULL || rightimplubs[j] > rightpropubs[j]) )
1665 {
1666 /* var is fixed to lower bound whenever probingvar is fixed to 1.0
1667 * and implication is not already known
1668 * -> insert implication: probingvar == 1 => var <= rightpropubs[j]
1669 */
1670 /*SCIPdebugMsg(scip, "found implication <%s> == 1 => <%s> == %g\n",
1671 SCIPvarGetName(probingvar), SCIPvarGetName(var), rightpropubs[j]);*/
1672 SCIP_CALL( SCIPaddVarImplication(scip, probingvar, TRUE, var, SCIP_BOUNDTYPE_UPPER, rightpropubs[j],
1673 cutoff, &nboundchanges) );
1674 (*nimplications)++;
1675 (*nchgbds) += nboundchanges;
1676
1677 if( *cutoff )
1678 {
1679 SCIPdebugMsg(scip, "analyzing probing deduction of <%s> led to an infeasible implication <%s> == 1 => <%s> == %g\n",
1680 SCIPvarGetName(probingvar), SCIPvarGetName(probingvar), SCIPvarGetName(var), rightpropubs[j]);
1681 }
1682 }
1683 else if( SCIPisEQ(scip, newub, rightproplbs[j]) && (rightimpllbs == NULL || rightimpllbs[j] < rightproplbs[j]) )
1684 {
1685 /* var is fixed to upper bound whenever probingvar is fixed to 1.0
1686 * and implication is not already known
1687 * -> insert implication: probingvar == 1 => var >= leftproplbs[j]
1688 */
1689 /*SCIPdebugMsg(scip, "found implication <%s> == 1 => <%s> == %g\n",
1690 SCIPvarGetName(probingvar), SCIPvarGetName(var), rightproplbs[j]);*/
1691 SCIP_CALL( SCIPaddVarImplication(scip, probingvar, TRUE, var, SCIP_BOUNDTYPE_LOWER, rightproplbs[j],
1692 cutoff, &nboundchanges) );
1693 (*nimplications)++;
1694 (*nchgbds) += nboundchanges;
1695
1696 if( *cutoff )
1697 {
1698 SCIPdebugMsg(scip, "analyzing probing deduction of <%s> led to an infeasible implication <%s> == 1 => <%s> == %g\n",
1699 SCIPvarGetName(probingvar), SCIPvarGetName(probingvar), SCIPvarGetName(var), rightproplbs[j]);
1700 }
1701 }
1703 {
1704 /* check for implications for lower or upper bounds (only store implications with bounds tightened at least by 0.5)
1705 * in case of binary variables, this should have been handled in the previous cases, since every boundchange also fixes the variable
1706 */
1707 if( leftpropubs[j] < newub - 0.5 && (leftimplubs == NULL || leftpropubs[j] < leftimplubs[j]) )
1708 {
1709 /* insert implication: probingvar == 0 => var <= leftpropubs[j] */
1710 /*SCIPdebugMsg(scip, "found implication <%s> == 0 => <%s>[%g,%g] <= %g\n",
1711 SCIPvarGetName(probingvar), SCIPvarGetName(var), newlb, newub, leftpropubs[j]);*/
1712 SCIP_CALL( SCIPaddVarImplication(scip, probingvar, FALSE, var, SCIP_BOUNDTYPE_UPPER, leftpropubs[j],
1713 cutoff, &nboundchanges) );
1714 (*nimplications)++;
1715 (*nchgbds) += nboundchanges;
1716
1717 if( *cutoff )
1718 {
1719 SCIPdebugMsg(scip, "analyzing probing deduction of <%s> led to an infeasible implication <%s> == 0 => <%s> <= %g\n",
1720 SCIPvarGetName(probingvar), SCIPvarGetName(probingvar), SCIPvarGetName(var), leftpropubs[j]);
1721 }
1722 }
1723 if( leftproplbs[j] > newlb + 0.5 && (leftimpllbs == NULL || leftproplbs[j] > leftimpllbs[j]) && !*cutoff )
1724 {
1725 /* insert implication: probingvar == 0 => var >= leftproplbs[j] */
1726 /*SCIPdebugMsg(scip, "found implication <%s> == 0 => <%s>[%g,%g] >= %g\n",
1727 SCIPvarGetName(probingvar), SCIPvarGetName(var), newlb, newub, leftproplbs[j]);*/
1728 SCIP_CALL( SCIPaddVarImplication(scip, probingvar, FALSE, var, SCIP_BOUNDTYPE_LOWER, leftproplbs[j],
1729 cutoff, &nboundchanges) );
1730 (*nimplications)++;
1731 (*nchgbds) += nboundchanges;
1732
1733 if( *cutoff )
1734 {
1735 SCIPdebugMsg(scip, "analyzing probing deduction of <%s> led to an infeasible implication <%s> == 0 => <%s> >= %g\n",
1736 SCIPvarGetName(probingvar), SCIPvarGetName(probingvar), SCIPvarGetName(var), leftproplbs[j]);
1737 }
1738 }
1739 if( rightpropubs[j] < newub - 0.5 && (rightimplubs == NULL || rightpropubs[j] < rightimplubs[j]) && !*cutoff )
1740 {
1741 /* insert implication: probingvar == 1 => var <= rightpropubs[j] */
1742 /*SCIPdebugMsg(scip, "found implication <%s> == 1 => <%s>[%g,%g] <= %g\n",
1743 SCIPvarGetName(probingvar), SCIPvarGetName(var), newlb, newub, rightpropubs[j]);*/
1744 SCIP_CALL( SCIPaddVarImplication(scip, probingvar, TRUE, var, SCIP_BOUNDTYPE_UPPER, rightpropubs[j],
1745 cutoff, &nboundchanges) );
1746 (*nimplications)++;
1747 (*nchgbds) += nboundchanges;
1748
1749 if( *cutoff )
1750 {
1751 SCIPdebugMsg(scip, "analyzing probing deduction of <%s> led to an infeasible implication <%s> == 1 => <%s> <= %g\n",
1752 SCIPvarGetName(probingvar), SCIPvarGetName(probingvar), SCIPvarGetName(var), rightpropubs[j]);
1753 }
1754 }
1755 if( rightproplbs[j] > newlb + 0.5 && (rightimpllbs == NULL || rightproplbs[j] > rightimpllbs[j]) && !*cutoff )
1756 {
1757 /* insert implication: probingvar == 1 => var >= rightproplbs[j] */
1758 /*SCIPdebugMsg(scip, "found implication <%s> == 1 => <%s>[%g,%g] >= %g\n",
1759 SCIPvarGetName(probingvar), SCIPvarGetName(var), newlb, newub, rightproplbs[j]);*/
1760 SCIP_CALL( SCIPaddVarImplication(scip, probingvar, TRUE, var, SCIP_BOUNDTYPE_LOWER, rightproplbs[j],
1761 cutoff, &nboundchanges) );
1762 (*nimplications)++;
1763 (*nchgbds) += nboundchanges;
1764
1765 if( *cutoff )
1766 {
1767 SCIPdebugMsg(scip, "analyzing probing deduction of <%s> led to an infeasible implication <%s> == 1 => <%s> <= %g\n",
1768 SCIPvarGetName(probingvar), SCIPvarGetName(probingvar), SCIPvarGetName(var), rightproplbs[j]);
1769 }
1770 }
1771 }
1772 }
1773 }
1774
1775 return SCIP_OKAY;
1776}
static long bound
#define DEFAULT_MAXDEPTH
#define MAXDNOM
#define DEFAULT_RANDSEED
#define NULL
Definition def.h:257
#define SCIP_Longint
Definition def.h:150
#define SCIP_Bool
Definition def.h:100
#define MIN(x, y)
Definition def.h:233
#define SCIP_STRINGEQ(name, reference, retcode)
Definition def.h:454
#define SCIP_Real
Definition def.h:165
#define ABS(x)
Definition def.h:225
#define TRUE
Definition def.h:102
#define FALSE
Definition def.h:103
#define MAX(x, y)
Definition def.h:229
#define SCIP_LONGINT_FORMAT
Definition def.h:157
#define SCIP_CALL(x)
Definition def.h:364
SCIP_Bool SCIPisStopped(SCIP *scip)
SCIP_STAGE SCIPgetStage(SCIP *scip)
int SCIPgetNIntVars(SCIP *scip)
Definition scip_prob.c:2340
int SCIPgetNImplVars(SCIP *scip)
Definition scip_prob.c:2387
const char * SCIPgetProbName(SCIP *scip)
Definition scip_prob.c:1242
int SCIPgetNVars(SCIP *scip)
Definition scip_prob.c:2246
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition scip_prob.c:2201
int SCIPgetNBinVars(SCIP *scip)
Definition scip_prob.c:2293
int SCIPgetNTotalVars(SCIP *scip)
Definition scip_prob.c:3064
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
#define SCIPdebugMsg
SCIP_Real SCIPselectSimpleValue(SCIP_Real lb, SCIP_Real ub, SCIP_Longint maxdnom)
Definition misc.c:10041
SCIP_RETCODE SCIPapplyProbingVar(SCIP *scip, SCIP_VAR **vars, int nvars, int probingpos, SCIP_BOUNDTYPE boundtype, SCIP_Real bound, int maxproprounds, SCIP_Real *impllbs, SCIP_Real *implubs, SCIP_Real *proplbs, SCIP_Real *propubs, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPanalyzeDeductionsProbing(SCIP *scip, SCIP_VAR *probingvar, SCIP_Real leftub, SCIP_Real rightlb, int nvars, SCIP_VAR **vars, SCIP_Real *leftimpllbs, SCIP_Real *leftimplubs, SCIP_Real *leftproplbs, SCIP_Real *leftpropubs, SCIP_Real *rightimpllbs, SCIP_Real *rightimplubs, SCIP_Real *rightproplbs, SCIP_Real *rightpropubs, int *nfixedvars, int *naggrvars, int *nimplications, int *nchgbds, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:83
void SCIPswapPointers(void **pointer1, void **pointer2)
Definition misc.c:10511
SCIP_RETCODE SCIPincludePropProbing(SCIP *scip)
SCIP_RETCODE SCIPgetLPBranchCands(SCIP *scip, SCIP_VAR ***lpcands, SCIP_Real **lpcandssol, SCIP_Real **lpcandsfrac, int *nlpcands, int *npriolpcands, int *nfracimplvars)
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition scip_lp.c:174
#define SCIPfreeMemoryArrayNull(scip, ptr)
Definition scip_mem.h:81
#define SCIPreallocMemoryArray(scip, ptr, newnum)
Definition scip_mem.h:70
#define SCIPallocBufferArray(scip, ptr, num)
Definition scip_mem.h:124
#define SCIPreallocBufferArray(scip, ptr, num)
Definition scip_mem.h:128
#define SCIPfreeBufferArray(scip, ptr)
Definition scip_mem.h:136
#define SCIPduplicateMemoryArray(scip, ptr, source, num)
Definition scip_mem.h:76
#define SCIPfreeMemoryArray(scip, ptr)
Definition scip_mem.h:80
#define SCIPfreeBlockMemory(scip, ptr)
Definition scip_mem.h:108
#define SCIPallocBlockMemory(scip, ptr)
Definition scip_mem.h:89
SCIP_Longint SCIPnodeGetNumber(SCIP_NODE *node)
Definition tree.c:8513
int SCIPnodeGetDepth(SCIP_NODE *node)
Definition tree.c:8523
SCIP_RETCODE SCIPchgVarUbProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
SCIP_RETCODE SCIPchgVarLbProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
SCIP_RETCODE SCIPpropagateProbing(SCIP *scip, int maxproprounds, SCIP_Bool *cutoff, SCIP_Longint *ndomredsfound)
SCIP_Bool SCIPinProbing(SCIP *scip)
SCIP_RETCODE SCIPstartProbing(SCIP *scip)
SCIP_RETCODE SCIPpropagateProbingImplications(SCIP *scip, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPsetPropInitpre(SCIP *scip, SCIP_PROP *prop,)
Definition scip_prop.c:251
void SCIPpropSetData(SCIP_PROP *prop, SCIP_PROPDATA *propdata)
Definition prop.c:801
SCIP_RETCODE SCIPsetPropExitpre(SCIP *scip, SCIP_PROP *prop,)
Definition scip_prop.c:267
SCIP_RETCODE SCIPsetPropCopy(SCIP *scip, SCIP_PROP *prop,)
Definition scip_prop.c:155
SCIP_PROPDATA * SCIPpropGetData(SCIP_PROP *prop)
Definition prop.c:791
SCIP_RETCODE SCIPsetPropPresol(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPPRESOL((*proppresol)), int presolpriority, int presolmaxrounds, SCIP_PRESOLTIMING presoltiming)
Definition scip_prop.c:283
const char * SCIPpropGetName(SCIP_PROP *prop)
Definition prop.c:951
SCIP_RETCODE SCIPsetPropResprop(SCIP *scip, SCIP_PROP *prop,)
Definition scip_prop.c:316
SCIP_RETCODE SCIPsetPropFree(SCIP *scip, SCIP_PROP *prop,)
Definition scip_prop.c:171
SCIP_RETCODE SCIPsetPropInit(SCIP *scip, SCIP_PROP *prop,)
Definition scip_prop.c:187
SCIP_Real SCIPpropGetTime(SCIP_PROP *prop)
Definition prop.c:1066
SCIP_RETCODE SCIPsetPropInitsol(SCIP *scip, SCIP_PROP *prop,)
Definition scip_prop.c:219
SCIP_RETCODE SCIPsetPropExit(SCIP *scip, SCIP_PROP *prop,)
Definition scip_prop.c:203
SCIP_RETCODE SCIPincludePropBasic(SCIP *scip, SCIP_PROP **propptr, const char *name, const char *desc, int priority, int freq, SCIP_Bool delay, SCIP_PROPTIMING timingmask, SCIP_DECL_PROPEXEC((*propexec)), SCIP_PROPDATA *propdata)
Definition scip_prop.c:118
int SCIPgetNRuns(SCIP *scip)
SCIP_Real SCIPgetSolvingTime(SCIP *scip)
SCIP_Bool SCIPisUbBetter(SCIP *scip, SCIP_Real newub, SCIP_Real oldlb, SCIP_Real oldub)
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisLbBetter(SCIP *scip, SCIP_Real newlb, SCIP_Real oldlb, SCIP_Real oldub)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPepsilon(SCIP *scip)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
int SCIPgetDepth(SCIP *scip)
Definition scip_tree.c:672
SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
Definition scip_tree.c:91
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition scip_var.c:6401
SCIP_Bool SCIPvarIsDeleted(SCIP_VAR *var)
Definition var.c:23566
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition var.c:23674
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition var.c:23510
int SCIPvarGetNImpls(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:24600
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition var.c:4380
SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR *var)
Definition var.c:23530
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition var.c:24300
SCIP_RETCODE SCIPaggregateVars(SCIP *scip, SCIP_VAR *varx, SCIP_VAR *vary, SCIP_Real scalarx, SCIP_Real scalary, SCIP_Real rhs, SCIP_Bool *infeasible, SCIP_Bool *redundant, SCIP_Bool *aggregated)
Definition scip_var.c:10550
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition scip_var.c:6651
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition var.c:23485
SCIP_RETCODE SCIPaddVarVub(SCIP *scip, SCIP_VAR *var, SCIP_VAR *vubvar, SCIP_Real vubcoef, SCIP_Real vubconstant, SCIP_Bool *infeasible, int *nbdchgs)
Definition scip_var.c:8680
int SCIPvarGetIndex(SCIP_VAR *var)
Definition var.c:23684
SCIP_RETCODE SCIPaddVarVlb(SCIP *scip, SCIP_VAR *var, SCIP_VAR *vlbvar, SCIP_Real vlbcoef, SCIP_Real vlbconstant, SCIP_Bool *infeasible, int *nbdchgs)
Definition scip_var.c:8621
const char * SCIPvarGetName(SCIP_VAR *var)
Definition var.c:23299
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition scip_var.c:1887
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition var.c:23522
SCIP_RETCODE SCIPaddVarImplication(SCIP *scip, SCIP_VAR *var, SCIP_Bool varfixing, SCIP_VAR *implvar, SCIP_BOUNDTYPE impltype, SCIP_Real implbound, SCIP_Bool *infeasible, int *nbdchgs)
Definition scip_var.c:8740
int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:24674
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition var.c:24266
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition scip_var.c:10318
int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition var.c:4322
void SCIPenableVarHistory(SCIP *scip)
Definition scip_var.c:11083
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition scip_var.c:1853
SCIP_Real SCIPrandomGetReal(SCIP_RANDNUMGEN *randnumgen, SCIP_Real minrandval, SCIP_Real maxrandval)
Definition misc.c:10245
void SCIPsortDownRealPtr(SCIP_Real *realarray, void **ptrarray, int len)
return SCIP_OKAY
SCIPfreeRandom(scip, &heurdata->randnumgen)
#define DEFAULT_PROPROUNDS
SCIPendProbing(scip))
int maxdepth
SCIP_Bool cutoff
SCIPcreateRandom(scip, &heurdata->randnumgen, DEFAULT_RANDSEED, TRUE))
assert(minobj< SCIPgetCutoffbound(scip))
int nvars
SCIP_VAR * var
static SCIP_VAR ** vars
memory allocation routines
#define BMSclearMemoryArray(ptr, num)
Definition memory.h:130
#define PROP_PRESOL_MAXROUNDS
#define PROP_PRESOLTIMING
#define PROP_DESC
#define PROP_NAME
#define PROP_DELAY
#define PROP_TIMING
#define PROP_FREQ
#define PROP_PRIORITY
#define PROP_PRESOL_PRIORITY
#define DEFAULT_MAXUSELESS
#define DEFAULT_MAXTOTALUSELESS
static SCIP_RETCODE applyProbing(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_VAR **vars, int nvars, int nbinvars, int *startidx, int *nfixedvars, int *naggrvars, int *nchgbds, int oldnfixedvars, int oldnaggrvars, SCIP_Bool *delay, SCIP_Bool *cutoff)
static SCIP_RETCODE initPropdata(SCIP_PROPDATA *propdata)
static SCIP_RETCODE freeSortedvars(SCIP *scip, SCIP_PROPDATA *propdata)
#define DEFAULT_MAXSUMUSELESS
static SCIP_RETCODE sortVariables(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_VAR **vars, int nvars, int firstidx)
#define DEFAULT_MAXRUNS
#define DEFAULT_MAXFIXINGS
probing propagator
public methods for message output
#define SCIPdebug(x)
Definition pub_message.h:93
public data structures and miscellaneous methods
methods for sorting joint arrays of various types
public methods for propagators
public methods for branch and bound tree
public methods for problem variables
public methods for branching rule plugins and branching
general public methods
public methods for the LP relaxation, rows and columns
public methods for memory management
public methods for message handling
public methods for numerical tolerances
public methods for SCIP parameter handling
public methods for global and local (sub)problems
public methods for the probing mode
public methods for propagator plugins
public methods for random numbers
public methods for querying solving statistics
public methods for timing
public methods for the branch-and-bound tree
public methods for SCIP variables
@ SCIP_BOUNDTYPE_UPPER
Definition type_lp.h:58
@ SCIP_BOUNDTYPE_LOWER
Definition type_lp.h:57
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition type_lp.h:60
@ SCIP_LPSOLSTAT_OPTIMAL
Definition type_lp.h:44
enum SCIP_VerbLevel SCIP_VERBLEVEL
@ SCIP_VERBLEVEL_HIGH
@ SCIP_VERBLEVEL_FULL
struct SCIP_RandNumGen SCIP_RANDNUMGEN
Definition type_misc.h:127
#define SCIP_DECL_PROPCOPY(x)
Definition type_prop.h:61
#define SCIP_DECL_PROPEXITPRE(x)
Definition type_prop.h:114
#define SCIP_DECL_PROPINITSOL(x)
Definition type_prop.h:129
#define SCIP_DECL_PROPINIT(x)
Definition type_prop.h:77
#define SCIP_DECL_PROPFREE(x)
Definition type_prop.h:69
#define SCIP_DECL_PROPEXIT(x)
Definition type_prop.h:85
struct SCIP_Prop SCIP_PROP
Definition type_prop.h:51
#define SCIP_DECL_PROPPRESOL(x)
Definition type_prop.h:193
#define SCIP_DECL_PROPINITPRE(x)
Definition type_prop.h:99
#define SCIP_DECL_PROPRESPROP(x)
Definition type_prop.h:258
struct SCIP_PropData SCIP_PROPDATA
Definition type_prop.h:52
#define SCIP_DECL_PROPEXEC(x)
Definition type_prop.h:217
@ SCIP_DIDNOTRUN
Definition type_result.h:42
@ SCIP_CUTOFF
Definition type_result.h:48
@ SCIP_REDUCEDDOM
Definition type_result.h:51
@ SCIP_DIDNOTFIND
Definition type_result.h:44
@ SCIP_SUCCESS
Definition type_result.h:58
@ SCIP_INVALIDCALL
enum SCIP_Retcode SCIP_RETCODE
struct Scip SCIP
Definition type_scip.h:39
@ SCIP_STAGE_PRESOLVING
Definition type_set.h:49
@ SCIP_STAGE_SOLVING
Definition type_set.h:53
struct SCIP_Var SCIP_VAR
Definition type_var.h:166
@ SCIP_VARTYPE_BINARY
Definition type_var.h:64
@ SCIP_LOCKTYPE_MODEL
Definition type_var.h:141