1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /*                                                                           */
3 /*                  This file is part of the program and library             */
4 /*         SCIP --- Solving Constraint Integer Programs                      */
5 /*                                                                           */
6 /*    Copyright (C) 2002-2021 Konrad-Zuse-Zentrum                            */
7 /*                            fuer Informationstechnik Berlin                */
8 /*                                                                           */
9 /*  SCIP is distributed under the terms of the ZIB Academic License.         */
10 /*                                                                           */
11 /*  You should have received a copy of the ZIB Academic License              */
12 /*  along with SCIP; see the file COPYING. If not visit scipopt.org.         */
13 /*                                                                           */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 /**@file   conflict.c
16  * @ingroup OTHER_CFILES
17  * @brief  methods and datastructures for conflict analysis
18  * @author Tobias Achterberg
19  * @author Timo Berthold
20  * @author Stefan Heinz
21  * @author Marc Pfetsch
22  * @author Michael Winkler
23  * @author Jakob Witzig
24  *
25  * This file implements a conflict analysis method like the one used in modern
26  * SAT solvers like zchaff. The algorithm works as follows:
27  *
28  * Given is a set of bound changes that are not allowed being applied simultaneously, because they
29  * render the current node infeasible (e.g. because a single constraint is infeasible in the these
30  * bounds, or because the LP relaxation is infeasible).  The goal is to deduce a clause on variables
31  * -- a conflict clause -- representing the "reason" for this conflict, i.e., the branching decisions
32  * or the deductions (applied e.g. in domain propagation) that lead to the conflict. This clause can
33  * then be added to the constraint set to help cutting off similar parts of the branch and bound
34  * tree, that would lead to the same conflict.  A conflict clause can also be generated, if the
35  * conflict was detected by a locally valid constraint. In this case, the resulting conflict clause
36  * is also locally valid in the same depth as the conflict detecting constraint. If all involved
37  * variables are binary, a linear (set covering) constraint can be generated, otherwise a bound
38  * disjunction constraint is generated. Details are given in
39  *
40  * Tobias Achterberg, Conflict Analysis in Mixed Integer Programming@n
41  * Discrete Optimization, 4, 4-20 (2007)
42  *
43  * See also @ref CONF. Here is an outline of the algorithm:
44  *
45  * -#  Put all the given bound changes to a priority queue, which is ordered,
46  *     such that the bound change that was applied last due to branching or deduction
47  *     is at the top of the queue. The variables in the queue are always active
48  *     problem variables. Because binary variables are preferred over general integer
49  *     variables, integer variables are put on the priority queue prior to the binary
50  *     variables. Create an empty conflict set.
51  * -#  Remove the top bound change b from the priority queue.
52  * -#  Perform the following case distinction:
53  *     -#  If the remaining queue is non-empty, and bound change b' (the one that is now
54  *         on the top of the queue) was applied at the same depth level as b, and if
55  *         b was a deduction with known inference reason, and if the inference constraint's
56  *         valid depth is smaller or equal to the conflict detecting constraint's valid
57  *         depth:
58  *          - Resolve bound change b by asking the constraint that inferred the
59  *            bound change to put all the bound changes on the priority queue, that
60  *            lead to the deduction of b.
61  *            Note that these bound changes have at most the same inference depth
62  *            level as b, and were deduced earlier than b.
63  *     -#  Otherwise, the bound change b was a branching decision or a deduction with
64  *         missing inference reason, or the inference constraint's validity is more local
65  *         than the one of the conflict detecting constraint.
66  *          - If a the bound changed corresponds to a binary variable, add it or its
67  *            negation to the conflict set, depending on which of them is currently fixed to
68  *            FALSE (i.e., the conflict set consists of literals that cannot be FALSE
69  *            altogether at the same time).
70  *          - Otherwise put the bound change into the conflict set.
71  *         Note that if the bound change was a branching, all deduced bound changes
72  *         remaining in the priority queue have smaller inference depth level than b,
73  *         since deductions are always applied after the branching decisions. However,
74  *         there is the possibility, that b was a deduction, where the inference
75  *         reason was not given or the inference constraint was too local.
76  *         With this lack of information, we must treat the deduced bound change like
77  *         a branching, and there may exist other deduced bound changes of the same
78  *         inference depth level in the priority queue.
79  * -#  If priority queue is non-empty, goto step 2.
80  * -#  The conflict set represents the conflict clause saying that at least one
81  *     of the conflict variables must take a different value. The conflict set is then passed
82  *     to the conflict handlers, that may create a corresponding constraint (e.g. a logicor
83  *     constraint or bound disjunction constraint) out of these conflict variables and
84  *     add it to the problem.
85  *
86  * If all deduced bound changes come with (global) inference information, depending on
87  * the conflict analyzing strategy, the resulting conflict set has the following property:
88  *  - 1-FirstUIP: In the depth level where the conflict was found, at most one variable
89  *    assigned at that level is member of the conflict set. This conflict variable is the
90  *    first unique implication point of its depth level (FUIP).
91  *  - All-FirstUIP: For each depth level, at most one variable assigned at that level is
92  *    member of the conflict set. This conflict variable is the first unique implication
93  *    point of its depth level (FUIP).
94  *
95  * The user has to do the following to get the conflict analysis running in its
96  * current implementation:
97  *  - A constraint handler or propagator supporting the conflict analysis must implement
98  *    the CONSRESPROP/PROPRESPROP call, that processes a bound change inference b and puts all
99  *    the reason bounds leading to the application of b with calls to
100  *    SCIPaddConflictBound() on the conflict queue (algorithm step 3.(a)).
101  *  - If the current bounds lead to a deduction of a bound change (e.g. in domain
102  *    propagation), a constraint handler should call SCIPinferVarLbCons() or
103  *    SCIPinferVarUbCons(), thus providing the constraint that infered the bound change.
104  *    A propagator should call SCIPinferVarLbProp() or SCIPinferVarUbProp() instead,
105  *    thus providing a pointer to itself.
106  *  - If (in the current bounds) an infeasibility is detected, the constraint handler or
107  *    propagator should
108  *     1. call SCIPinitConflictAnalysis() to initialize the conflict queue,
109  *     2. call SCIPaddConflictBound() for each bound that lead to the conflict,
110  *     3. call SCIPanalyzeConflictCons() or SCIPanalyzeConflict() to analyze the conflict
111  *        and add an appropriate conflict constraint.
112  */
113 
114 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
115 
116 #include "lpi/lpi.h"
117 #include "scip/clock.h"
118 #include "scip/conflict.h"
119 #include "scip/conflictstore.h"
120 #include "scip/cons.h"
121 #include "scip/cons_linear.h"
122 #include "scip/cuts.h"
123 #include "scip/history.h"
124 #include "scip/lp.h"
125 #include "scip/presolve.h"
126 #include "scip/prob.h"
127 #include "scip/prop.h"
128 #include "scip/pub_conflict.h"
129 #include "scip/pub_cons.h"
130 #include "scip/pub_lp.h"
131 #include "scip/pub_message.h"
132 #include "scip/pub_misc.h"
133 #include "scip/pub_misc_sort.h"
134 #include "scip/pub_paramset.h"
135 #include "scip/pub_prop.h"
136 #include "scip/pub_tree.h"
137 #include "scip/pub_var.h"
138 #include "scip/scip_conflict.h"
139 #include "scip/scip_cons.h"
140 #include "scip/scip_mem.h"
141 #include "scip/scip_sol.h"
142 #include "scip/scip_var.h"
143 #include "scip/set.h"
144 #include "scip/sol.h"
145 #include "scip/struct_conflict.h"
146 #include "scip/struct_lp.h"
147 #include "scip/struct_prob.h"
148 #include "scip/struct_set.h"
149 #include "scip/struct_stat.h"
150 #include "scip/struct_tree.h"
151 #include "scip/struct_var.h"
152 #include "scip/tree.h"
153 #include "scip/var.h"
154 #include "scip/visual.h"
155 #include <string.h>
156 #if defined(_WIN32) || defined(_WIN64)
157 #else
158 #include <strings.h> /*lint --e{766}*/
159 #endif
160 
161 
162 
163 #define BOUNDSWITCH                0.51 /**< threshold for bound switching - see cuts.c */
164 #define POSTPROCESS               FALSE /**< apply postprocessing to the cut - see cuts.c */
165 #define USEVBDS                   FALSE /**< use variable bounds - see cuts.c */
166 #define ALLOWLOCAL                FALSE /**< allow to generate local cuts - see cuts. */
167 #define MINFRAC                   0.05  /**< minimal fractionality of floor(rhs) - see cuts.c */
168 #define MAXFRAC                   0.999 /**< maximal fractionality of floor(rhs) - see cuts.c */
169 
170 /*#define SCIP_CONFGRAPH*/
171 
172 
173 #ifdef SCIP_CONFGRAPH
174 /*
175  * Output of Conflict Graph
176  */
177 
178 #include <stdio.h>
179 
180 static FILE*             confgraphfile = NULL;              /**< output file for current conflict graph */
181 static SCIP_BDCHGINFO*   confgraphcurrentbdchginfo = NULL;  /**< currently resolved bound change */
182 static int               confgraphnconflictsets = 0;        /**< number of conflict sets marked in the graph */
183 
184 /** writes a node section to the conflict graph file */
185 static
confgraphWriteNode(void * idptr,const char * label,const char * nodetype,const char * fillcolor,const char * bordercolor)186 void confgraphWriteNode(
187    void*                 idptr,              /**< id of the node */
188    const char*           label,              /**< label of the node */
189    const char*           nodetype,           /**< type of the node */
190    const char*           fillcolor,          /**< color of the node's interior */
191    const char*           bordercolor         /**< color of the node's border */
192    )
193 {
194    assert(confgraphfile != NULL);
195 
196    SCIPgmlWriteNode(confgraphfile, (unsigned int)(size_t)idptr, label, nodetype, fillcolor, bordercolor);
197 }
198 
199 /** writes an edge section to the conflict graph file */
200 static
confgraphWriteEdge(void * source,void * target,const char * color)201 void confgraphWriteEdge(
202    void*                 source,             /**< source node of the edge */
203    void*                 target,             /**< target node of the edge */
204    const char*           color               /**< color of the edge */
205    )
206 {
207    assert(confgraphfile != NULL);
208 
209 #ifndef SCIP_CONFGRAPH_EDGE
210    SCIPgmlWriteArc(confgraphfile, (unsigned int)(size_t)source, (unsigned int)(size_t)target, NULL, color);
211 #else
212    SCIPgmlWriteEdge(confgraphfile, (unsigned int)(size_t)source, (unsigned int)(size_t)target, NULL, color);
213 #endif
214 }
215 
216 /** creates a file to output the current conflict graph into; adds the conflict vertex to the graph */
217 static
confgraphCreate(SCIP_SET * set,SCIP_CONFLICT * conflict)218 SCIP_RETCODE confgraphCreate(
219    SCIP_SET*             set,                /**< global SCIP settings */
220    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
221    )
222 {
223    char fname[SCIP_MAXSTRLEN];
224 
225    assert(conflict != NULL);
226    assert(confgraphfile == NULL);
227 
228    (void) SCIPsnprintf(fname, SCIP_MAXSTRLEN, "conf%p%d.gml", conflict, conflict->count);
229    SCIPinfoMessage(set->scip, NULL, "storing conflict graph in file <%s>\n", fname);
230 
231    confgraphfile = fopen(fname, "w");
232 
233    if( confgraphfile == NULL )
234    {
235       SCIPerrorMessage("cannot open graph file <%s>\n", fname);
236       SCIPABORT(); /*lint !e527*/
237       return SCIP_WRITEERROR;
238    }
239 
240    SCIPgmlWriteOpening(confgraphfile, TRUE);
241 
242    confgraphWriteNode(NULL, "conflict", "ellipse", "#ff0000", "#000000");
243 
244    confgraphcurrentbdchginfo = NULL;
245 
246    return SCIP_OKAY;
247 }
248 
249 /** closes conflict graph file */
250 static
confgraphFree(void)251 void confgraphFree(
252    void
253    )
254 {
255    if( confgraphfile != NULL )
256    {
257       SCIPgmlWriteClosing(confgraphfile);
258 
259       fclose(confgraphfile);
260 
261       confgraphfile = NULL;
262       confgraphnconflictsets = 0;
263    }
264 }
265 
266 /** adds a bound change node to the conflict graph and links it to the currently resolved bound change */
267 static
confgraphAddBdchg(SCIP_BDCHGINFO * bdchginfo)268 void confgraphAddBdchg(
269    SCIP_BDCHGINFO*       bdchginfo           /**< bound change to add to the conflict graph */
270    )
271 {
272    const char* colors[] = {
273       "#8888ff", /* blue for constraint resolving */
274       "#ffff00", /* yellow for propagator resolving */
275       "#55ff55"  /* green branching decision */
276    };
277    char label[SCIP_MAXSTRLEN];
278    char depth[SCIP_MAXSTRLEN];
279    int col;
280 
281    switch( SCIPbdchginfoGetChgtype(bdchginfo) )
282    {
283    case SCIP_BOUNDCHGTYPE_BRANCHING:
284       col = 2;
285       break;
286    case SCIP_BOUNDCHGTYPE_CONSINFER:
287       col = 0;
288       break;
289    case SCIP_BOUNDCHGTYPE_PROPINFER:
290       col = (SCIPbdchginfoGetInferProp(bdchginfo) == NULL ? 1 : 0);
291       break;
292    default:
293       SCIPerrorMessage("invalid bound change type\n");
294       col = 0;
295       SCIPABORT();
296       break;
297    }
298 
299    if( SCIPbdchginfoGetDepth(bdchginfo) == INT_MAX )
300       (void) SCIPsnprintf(depth, SCIP_MAXSTRLEN, "dive");
301    else
302       (void) SCIPsnprintf(depth, SCIP_MAXSTRLEN, "%d", SCIPbdchginfoGetDepth(bdchginfo));
303    (void) SCIPsnprintf(label, SCIP_MAXSTRLEN, "%s %s %g\n[%s:%d]", SCIPvarGetName(SCIPbdchginfoGetVar(bdchginfo)),
304       SCIPbdchginfoGetBoundtype(bdchginfo) == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=",
305       SCIPbdchginfoGetNewbound(bdchginfo), depth, SCIPbdchginfoGetPos(bdchginfo));
306    confgraphWriteNode(bdchginfo, label, "ellipse", colors[col], "#000000");
307    confgraphWriteEdge(bdchginfo, confgraphcurrentbdchginfo, "#000000");
308 }
309 
310 /** links the already existing bound change node to the currently resolved bound change */
311 static
confgraphLinkBdchg(SCIP_BDCHGINFO * bdchginfo)312 void confgraphLinkBdchg(
313    SCIP_BDCHGINFO*       bdchginfo           /**< bound change to add to the conflict graph */
314    )
315 {
316    confgraphWriteEdge(bdchginfo, confgraphcurrentbdchginfo, "#000000");
317 }
318 
319 /** marks the given bound change to be the currently resolved bound change */
320 static
confgraphSetCurrentBdchg(SCIP_BDCHGINFO * bdchginfo)321 void confgraphSetCurrentBdchg(
322    SCIP_BDCHGINFO*       bdchginfo           /**< bound change to add to the conflict graph */
323    )
324 {
325    confgraphcurrentbdchginfo = bdchginfo;
326 }
327 
328 /** marks given conflict set in the conflict graph */
329 static
confgraphMarkConflictset(SCIP_CONFLICTSET * conflictset)330 void confgraphMarkConflictset(
331    SCIP_CONFLICTSET*     conflictset         /**< conflict set */
332    )
333 {
334    char label[SCIP_MAXSTRLEN];
335    int i;
336 
337    assert(conflictset != NULL);
338 
339    confgraphnconflictsets++;
340    (void) SCIPsnprintf(label, SCIP_MAXSTRLEN, "conf %d (%d)", confgraphnconflictsets, conflictset->validdepth);
341    confgraphWriteNode((void*)(size_t)confgraphnconflictsets, label, "rectangle", "#ff00ff", "#000000");
342    for( i = 0; i < conflictset->nbdchginfos; ++i )
343       confgraphWriteEdge((void*)(size_t)confgraphnconflictsets, conflictset->bdchginfos[i], "#ff00ff");
344 }
345 
346 #endif
347 
348 /*
349  * Conflict Handler
350  */
351 
352 /** compares two conflict handlers w. r. to their priority */
SCIP_DECL_SORTPTRCOMP(SCIPconflicthdlrComp)353 SCIP_DECL_SORTPTRCOMP(SCIPconflicthdlrComp)
354 {  /*lint --e{715}*/
355    return ((SCIP_CONFLICTHDLR*)elem2)->priority - ((SCIP_CONFLICTHDLR*)elem1)->priority;
356 }
357 
358 /** comparison method for sorting conflict handler w.r.t. to their name */
SCIP_DECL_SORTPTRCOMP(SCIPconflicthdlrCompName)359 SCIP_DECL_SORTPTRCOMP(SCIPconflicthdlrCompName)
360 {
361    return strcmp(SCIPconflicthdlrGetName((SCIP_CONFLICTHDLR*)elem1), SCIPconflicthdlrGetName((SCIP_CONFLICTHDLR*)elem2));
362 }
363 
364 /** method to call, when the priority of a conflict handler was changed */
365 static
SCIP_DECL_PARAMCHGD(paramChgdConflicthdlrPriority)366 SCIP_DECL_PARAMCHGD(paramChgdConflicthdlrPriority)
367 {  /*lint --e{715}*/
368    SCIP_PARAMDATA* paramdata;
369 
370    paramdata = SCIPparamGetData(param);
371    assert(paramdata != NULL);
372 
373    /* use SCIPsetConflicthdlrPriority() to mark the conflicthdlrs unsorted */
374    SCIP_CALL( SCIPsetConflicthdlrPriority(scip, (SCIP_CONFLICTHDLR*)paramdata, SCIPparamGetInt(param)) ); /*lint !e740*/
375 
376    return SCIP_OKAY;
377 }
378 
379 /** copies the given conflict handler to a new scip */
SCIPconflicthdlrCopyInclude(SCIP_CONFLICTHDLR * conflicthdlr,SCIP_SET * set)380 SCIP_RETCODE SCIPconflicthdlrCopyInclude(
381    SCIP_CONFLICTHDLR*    conflicthdlr,       /**< conflict handler */
382    SCIP_SET*             set                 /**< SCIP_SET of SCIP to copy to */
383    )
384 {
385    assert(conflicthdlr != NULL);
386    assert(set != NULL);
387    assert(set->scip != NULL);
388 
389    if( conflicthdlr->conflictcopy != NULL )
390    {
391       SCIPsetDebugMsg(set, "including conflict handler %s in subscip %p\n", SCIPconflicthdlrGetName(conflicthdlr), (void*)set->scip);
392       SCIP_CALL( conflicthdlr->conflictcopy(set->scip, conflicthdlr) );
393    }
394 
395    return SCIP_OKAY;
396 }
397 
398 /** internal method for creating a conflict handler */
399 static
doConflicthdlrCreate(SCIP_CONFLICTHDLR ** conflicthdlr,SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr,BMS_BLKMEM * blkmem,const char * name,const char * desc,int priority,SCIP_DECL_CONFLICTCOPY ((* conflictcopy)),SCIP_DECL_CONFLICTFREE ((* conflictfree)),SCIP_DECL_CONFLICTINIT ((* conflictinit)),SCIP_DECL_CONFLICTEXIT ((* conflictexit)),SCIP_DECL_CONFLICTINITSOL ((* conflictinitsol)),SCIP_DECL_CONFLICTEXITSOL ((* conflictexitsol)),SCIP_DECL_CONFLICTEXEC ((* conflictexec)),SCIP_CONFLICTHDLRDATA * conflicthdlrdata)400 SCIP_RETCODE doConflicthdlrCreate(
401    SCIP_CONFLICTHDLR**   conflicthdlr,       /**< pointer to conflict handler data structure */
402    SCIP_SET*             set,                /**< global SCIP settings */
403    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
404    BMS_BLKMEM*           blkmem,             /**< block memory for parameter settings */
405    const char*           name,               /**< name of conflict handler */
406    const char*           desc,               /**< description of conflict handler */
407    int                   priority,           /**< priority of the conflict handler */
408    SCIP_DECL_CONFLICTCOPY((*conflictcopy)),  /**< copy method of conflict handler or NULL if you don't want to copy your plugin into sub-SCIPs */
409    SCIP_DECL_CONFLICTFREE((*conflictfree)),  /**< destructor of conflict handler */
410    SCIP_DECL_CONFLICTINIT((*conflictinit)),  /**< initialize conflict handler */
411    SCIP_DECL_CONFLICTEXIT((*conflictexit)),  /**< deinitialize conflict handler */
412    SCIP_DECL_CONFLICTINITSOL((*conflictinitsol)),/**< solving process initialization method of conflict handler */
413    SCIP_DECL_CONFLICTEXITSOL((*conflictexitsol)),/**< solving process deinitialization method of conflict handler */
414    SCIP_DECL_CONFLICTEXEC((*conflictexec)),  /**< conflict processing method of conflict handler */
415    SCIP_CONFLICTHDLRDATA* conflicthdlrdata   /**< conflict handler data */
416    )
417 {
418    char paramname[SCIP_MAXSTRLEN];
419    char paramdesc[SCIP_MAXSTRLEN];
420 
421    assert(conflicthdlr != NULL);
422    assert(name != NULL);
423    assert(desc != NULL);
424 
425    SCIP_ALLOC( BMSallocMemory(conflicthdlr) );
426    BMSclearMemory(*conflicthdlr);
427 
428    SCIP_ALLOC( BMSduplicateMemoryArray(&(*conflicthdlr)->name, name, strlen(name)+1) );
429    SCIP_ALLOC( BMSduplicateMemoryArray(&(*conflicthdlr)->desc, desc, strlen(desc)+1) );
430    (*conflicthdlr)->priority = priority;
431    (*conflicthdlr)->conflictcopy = conflictcopy;
432    (*conflicthdlr)->conflictfree = conflictfree;
433    (*conflicthdlr)->conflictinit = conflictinit;
434    (*conflicthdlr)->conflictexit = conflictexit;
435    (*conflicthdlr)->conflictinitsol = conflictinitsol;
436    (*conflicthdlr)->conflictexitsol = conflictexitsol;
437    (*conflicthdlr)->conflictexec = conflictexec;
438    (*conflicthdlr)->conflicthdlrdata = conflicthdlrdata;
439    (*conflicthdlr)->initialized = FALSE;
440 
441    SCIP_CALL( SCIPclockCreate(&(*conflicthdlr)->setuptime, SCIP_CLOCKTYPE_DEFAULT) );
442    SCIP_CALL( SCIPclockCreate(&(*conflicthdlr)->conflicttime, SCIP_CLOCKTYPE_DEFAULT) );
443 
444    /* add parameters */
445    (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "conflict/%s/priority", name);
446    (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "priority of conflict handler <%s>", name);
447    SCIP_CALL( SCIPsetAddIntParam(set, messagehdlr, blkmem, paramname, paramdesc, &(*conflicthdlr)->priority, TRUE, \
448          priority, INT_MIN, INT_MAX, paramChgdConflicthdlrPriority, (SCIP_PARAMDATA*)(*conflicthdlr)) ); /*lint !e740*/
449 
450    return SCIP_OKAY;
451 }
452 
453 /** creates a conflict handler */
SCIPconflicthdlrCreate(SCIP_CONFLICTHDLR ** conflicthdlr,SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr,BMS_BLKMEM * blkmem,const char * name,const char * desc,int priority,SCIP_DECL_CONFLICTCOPY ((* conflictcopy)),SCIP_DECL_CONFLICTFREE ((* conflictfree)),SCIP_DECL_CONFLICTINIT ((* conflictinit)),SCIP_DECL_CONFLICTEXIT ((* conflictexit)),SCIP_DECL_CONFLICTINITSOL ((* conflictinitsol)),SCIP_DECL_CONFLICTEXITSOL ((* conflictexitsol)),SCIP_DECL_CONFLICTEXEC ((* conflictexec)),SCIP_CONFLICTHDLRDATA * conflicthdlrdata)454 SCIP_RETCODE SCIPconflicthdlrCreate(
455    SCIP_CONFLICTHDLR**   conflicthdlr,       /**< pointer to conflict handler data structure */
456    SCIP_SET*             set,                /**< global SCIP settings */
457    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
458    BMS_BLKMEM*           blkmem,             /**< block memory for parameter settings */
459    const char*           name,               /**< name of conflict handler */
460    const char*           desc,               /**< description of conflict handler */
461    int                   priority,           /**< priority of the conflict handler */
462    SCIP_DECL_CONFLICTCOPY((*conflictcopy)),  /**< copy method of conflict handler or NULL if you don't want to
463                                               *   copy your plugin into sub-SCIPs */
464    SCIP_DECL_CONFLICTFREE((*conflictfree)),  /**< destructor of conflict handler */
465    SCIP_DECL_CONFLICTINIT((*conflictinit)),  /**< initialize conflict handler */
466    SCIP_DECL_CONFLICTEXIT((*conflictexit)),  /**< deinitialize conflict handler */
467    SCIP_DECL_CONFLICTINITSOL((*conflictinitsol)),/**< solving process initialization method of conflict handler */
468    SCIP_DECL_CONFLICTEXITSOL((*conflictexitsol)),/**< solving process deinitialization method of conflict handler */
469    SCIP_DECL_CONFLICTEXEC((*conflictexec)),  /**< conflict processing method of conflict handler */
470    SCIP_CONFLICTHDLRDATA* conflicthdlrdata   /**< conflict handler data */
471    )
472 {
473    assert(conflicthdlr != NULL);
474    assert(name != NULL);
475    assert(desc != NULL);
476 
477    SCIP_CALL_FINALLY( doConflicthdlrCreate(conflicthdlr, set, messagehdlr, blkmem, name, desc, priority,
478       conflictcopy, conflictfree, conflictinit, conflictexit, conflictinitsol, conflictexitsol, conflictexec,
479       conflicthdlrdata), (void) SCIPconflicthdlrFree(conflicthdlr, set) );
480 
481    return SCIP_OKAY;
482 }
483 
484 /** calls destructor and frees memory of conflict handler */
SCIPconflicthdlrFree(SCIP_CONFLICTHDLR ** conflicthdlr,SCIP_SET * set)485 SCIP_RETCODE SCIPconflicthdlrFree(
486    SCIP_CONFLICTHDLR**   conflicthdlr,       /**< pointer to conflict handler data structure */
487    SCIP_SET*             set                 /**< global SCIP settings */
488    )
489 {
490    assert(conflicthdlr != NULL);
491    if( *conflicthdlr == NULL )
492       return SCIP_OKAY;
493    assert(!(*conflicthdlr)->initialized);
494    assert(set != NULL);
495 
496    /* call destructor of conflict handler */
497    if( (*conflicthdlr)->conflictfree != NULL )
498    {
499       SCIP_CALL( (*conflicthdlr)->conflictfree(set->scip, *conflicthdlr) );
500    }
501 
502    SCIPclockFree(&(*conflicthdlr)->conflicttime);
503    SCIPclockFree(&(*conflicthdlr)->setuptime);
504 
505    BMSfreeMemoryArrayNull(&(*conflicthdlr)->name);
506    BMSfreeMemoryArrayNull(&(*conflicthdlr)->desc);
507    BMSfreeMemory(conflicthdlr);
508 
509    return SCIP_OKAY;
510 }
511 
512 /** calls initialization method of conflict handler */
SCIPconflicthdlrInit(SCIP_CONFLICTHDLR * conflicthdlr,SCIP_SET * set)513 SCIP_RETCODE SCIPconflicthdlrInit(
514    SCIP_CONFLICTHDLR*    conflicthdlr,       /**< conflict handler */
515    SCIP_SET*             set                 /**< global SCIP settings */
516    )
517 {
518    assert(conflicthdlr != NULL);
519    assert(set != NULL);
520 
521    if( conflicthdlr->initialized )
522    {
523       SCIPerrorMessage("conflict handler <%s> already initialized\n", conflicthdlr->name);
524       return SCIP_INVALIDCALL;
525    }
526 
527    if( set->misc_resetstat )
528    {
529       SCIPclockReset(conflicthdlr->setuptime);
530       SCIPclockReset(conflicthdlr->conflicttime);
531    }
532 
533    /* call initialization method of conflict handler */
534    if( conflicthdlr->conflictinit != NULL )
535    {
536       /* start timing */
537       SCIPclockStart(conflicthdlr->setuptime, set);
538 
539       SCIP_CALL( conflicthdlr->conflictinit(set->scip, conflicthdlr) );
540 
541       /* stop timing */
542       SCIPclockStop(conflicthdlr->setuptime, set);
543    }
544    conflicthdlr->initialized = TRUE;
545 
546    return SCIP_OKAY;
547 }
548 
549 /** calls exit method of conflict handler */
SCIPconflicthdlrExit(SCIP_CONFLICTHDLR * conflicthdlr,SCIP_SET * set)550 SCIP_RETCODE SCIPconflicthdlrExit(
551    SCIP_CONFLICTHDLR*    conflicthdlr,       /**< conflict handler */
552    SCIP_SET*             set                 /**< global SCIP settings */
553    )
554 {
555    assert(conflicthdlr != NULL);
556    assert(set != NULL);
557 
558    if( !conflicthdlr->initialized )
559    {
560       SCIPerrorMessage("conflict handler <%s> not initialized\n", conflicthdlr->name);
561       return SCIP_INVALIDCALL;
562    }
563 
564    /* call deinitialization method of conflict handler */
565    if( conflicthdlr->conflictexit != NULL )
566    {
567       /* start timing */
568       SCIPclockStart(conflicthdlr->setuptime, set);
569 
570       SCIP_CALL( conflicthdlr->conflictexit(set->scip, conflicthdlr) );
571 
572       /* stop timing */
573       SCIPclockStop(conflicthdlr->setuptime, set);
574    }
575    conflicthdlr->initialized = FALSE;
576 
577    return SCIP_OKAY;
578 }
579 
580 /** informs conflict handler that the branch and bound process is being started */
SCIPconflicthdlrInitsol(SCIP_CONFLICTHDLR * conflicthdlr,SCIP_SET * set)581 SCIP_RETCODE SCIPconflicthdlrInitsol(
582    SCIP_CONFLICTHDLR*    conflicthdlr,       /**< conflict handler */
583    SCIP_SET*             set                 /**< global SCIP settings */
584    )
585 {
586    assert(conflicthdlr != NULL);
587    assert(set != NULL);
588 
589    /* call solving process initialization method of conflict handler */
590    if( conflicthdlr->conflictinitsol != NULL )
591    {
592       /* start timing */
593       SCIPclockStart(conflicthdlr->setuptime, set);
594 
595       SCIP_CALL( conflicthdlr->conflictinitsol(set->scip, conflicthdlr) );
596 
597       /* stop timing */
598       SCIPclockStop(conflicthdlr->setuptime, set);
599    }
600 
601    return SCIP_OKAY;
602 }
603 
604 /** informs conflict handler that the branch and bound process data is being freed */
SCIPconflicthdlrExitsol(SCIP_CONFLICTHDLR * conflicthdlr,SCIP_SET * set)605 SCIP_RETCODE SCIPconflicthdlrExitsol(
606    SCIP_CONFLICTHDLR*    conflicthdlr,       /**< conflict handler */
607    SCIP_SET*             set                 /**< global SCIP settings */
608    )
609 {
610    assert(conflicthdlr != NULL);
611    assert(set != NULL);
612 
613    /* call solving process deinitialization method of conflict handler */
614    if( conflicthdlr->conflictexitsol != NULL )
615    {
616       /* start timing */
617       SCIPclockStart(conflicthdlr->setuptime, set);
618 
619       SCIP_CALL( conflicthdlr->conflictexitsol(set->scip, conflicthdlr) );
620 
621       /* stop timing */
622       SCIPclockStop(conflicthdlr->setuptime, set);
623    }
624 
625    return SCIP_OKAY;
626 }
627 
628 /** calls execution method of conflict handler */
SCIPconflicthdlrExec(SCIP_CONFLICTHDLR * conflicthdlr,SCIP_SET * set,SCIP_NODE * node,SCIP_NODE * validnode,SCIP_BDCHGINFO ** bdchginfos,SCIP_Real * relaxedbds,int nbdchginfos,SCIP_CONFTYPE conftype,SCIP_Bool usescutoffbound,SCIP_Bool resolved,SCIP_RESULT * result)629 SCIP_RETCODE SCIPconflicthdlrExec(
630    SCIP_CONFLICTHDLR*    conflicthdlr,       /**< conflict handler */
631    SCIP_SET*             set,                /**< global SCIP settings */
632    SCIP_NODE*            node,               /**< node to add conflict constraint to */
633    SCIP_NODE*            validnode,          /**< node at which the constraint is valid */
634    SCIP_BDCHGINFO**      bdchginfos,         /**< bound change resembling the conflict set */
635    SCIP_Real*            relaxedbds,         /**< array with relaxed bounds which are efficient to create a valid conflict */
636    int                   nbdchginfos,        /**< number of bound changes in the conflict set */
637    SCIP_CONFTYPE         conftype,           /**< type of the conflict */
638    SCIP_Bool             usescutoffbound,    /**< depends the conflict on the cutoff bound? */
639    SCIP_Bool             resolved,           /**< was the conflict set already used to create a constraint? */
640    SCIP_RESULT*          result              /**< pointer to store the result of the callback method */
641    )
642 {
643    assert(conflicthdlr != NULL);
644    assert(set != NULL);
645    assert(bdchginfos != NULL || nbdchginfos == 0);
646    assert(result != NULL);
647 
648    /* call solution start method of conflict handler */
649    *result = SCIP_DIDNOTRUN;
650    if( conflicthdlr->conflictexec != NULL )
651    {
652       /* start timing */
653       SCIPclockStart(conflicthdlr->conflicttime, set);
654 
655       SCIP_CALL( conflicthdlr->conflictexec(set->scip, conflicthdlr, node, validnode, bdchginfos, relaxedbds, nbdchginfos,
656             conftype, usescutoffbound, set->conf_separate, (SCIPnodeGetDepth(validnode) > 0), set->conf_dynamic,
657             set->conf_removable, resolved, result) );
658 
659       /* stop timing */
660       SCIPclockStop(conflicthdlr->conflicttime, set);
661 
662       if( *result != SCIP_CONSADDED
663          && *result != SCIP_DIDNOTFIND
664          && *result != SCIP_DIDNOTRUN )
665       {
666          SCIPerrorMessage("execution method of conflict handler <%s> returned invalid result <%d>\n",
667             conflicthdlr->name, *result);
668          return SCIP_INVALIDRESULT;
669       }
670    }
671 
672    return SCIP_OKAY;
673 }
674 
675 /** gets user data of conflict handler */
SCIPconflicthdlrGetData(SCIP_CONFLICTHDLR * conflicthdlr)676 SCIP_CONFLICTHDLRDATA* SCIPconflicthdlrGetData(
677    SCIP_CONFLICTHDLR*    conflicthdlr        /**< conflict handler */
678    )
679 {
680    assert(conflicthdlr != NULL);
681 
682    return conflicthdlr->conflicthdlrdata;
683 }
684 
685 /** sets user data of conflict handler; user has to free old data in advance! */
SCIPconflicthdlrSetData(SCIP_CONFLICTHDLR * conflicthdlr,SCIP_CONFLICTHDLRDATA * conflicthdlrdata)686 void SCIPconflicthdlrSetData(
687    SCIP_CONFLICTHDLR*    conflicthdlr,       /**< conflict handler */
688    SCIP_CONFLICTHDLRDATA* conflicthdlrdata   /**< new conflict handler user data */
689    )
690 {
691    assert(conflicthdlr != NULL);
692 
693    conflicthdlr->conflicthdlrdata = conflicthdlrdata;
694 }
695 
696 /** set copy method of conflict handler */
SCIPconflicthdlrSetCopy(SCIP_CONFLICTHDLR * conflicthdlr,SCIP_DECL_CONFLICTCOPY ((* conflictcopy)))697 void SCIPconflicthdlrSetCopy(
698    SCIP_CONFLICTHDLR*    conflicthdlr,       /**< conflict handler */
699    SCIP_DECL_CONFLICTCOPY((*conflictcopy))   /**< copy method of the conflict handler */
700    )
701 {
702    assert(conflicthdlr != NULL);
703 
704    conflicthdlr->conflictcopy = conflictcopy;
705 }
706 
707 /** set destructor of conflict handler */
SCIPconflicthdlrSetFree(SCIP_CONFLICTHDLR * conflicthdlr,SCIP_DECL_CONFLICTFREE ((* conflictfree)))708 void SCIPconflicthdlrSetFree(
709    SCIP_CONFLICTHDLR*    conflicthdlr,       /**< conflict handler */
710    SCIP_DECL_CONFLICTFREE((*conflictfree))   /**< destructor of conflict handler */
711    )
712 {
713    assert(conflicthdlr != NULL);
714 
715    conflicthdlr->conflictfree = conflictfree;
716 }
717 
718 /** set initialization method of conflict handler */
SCIPconflicthdlrSetInit(SCIP_CONFLICTHDLR * conflicthdlr,SCIP_DECL_CONFLICTINIT ((* conflictinit)))719 void SCIPconflicthdlrSetInit(
720    SCIP_CONFLICTHDLR*    conflicthdlr,       /**< conflict handler */
721    SCIP_DECL_CONFLICTINIT((*conflictinit))   /**< initialization method conflict handler */
722    )
723 {
724    assert(conflicthdlr != NULL);
725 
726    conflicthdlr->conflictinit = conflictinit;
727 }
728 
729 /** set deinitialization method of conflict handler */
SCIPconflicthdlrSetExit(SCIP_CONFLICTHDLR * conflicthdlr,SCIP_DECL_CONFLICTEXIT ((* conflictexit)))730 void SCIPconflicthdlrSetExit(
731    SCIP_CONFLICTHDLR*    conflicthdlr,       /**< conflict handler */
732    SCIP_DECL_CONFLICTEXIT((*conflictexit))   /**< deinitialization method conflict handler */
733    )
734 {
735    assert(conflicthdlr != NULL);
736 
737    conflicthdlr->conflictexit = conflictexit;
738 }
739 
740 /** set solving process initialization method of conflict handler */
SCIPconflicthdlrSetInitsol(SCIP_CONFLICTHDLR * conflicthdlr,SCIP_DECL_CONFLICTINITSOL ((* conflictinitsol)))741 void SCIPconflicthdlrSetInitsol(
742    SCIP_CONFLICTHDLR*    conflicthdlr,       /**< conflict handler */
743    SCIP_DECL_CONFLICTINITSOL((*conflictinitsol))/**< solving process initialization method of conflict handler */
744    )
745 {
746    assert(conflicthdlr != NULL);
747 
748    conflicthdlr->conflictinitsol = conflictinitsol;
749 }
750 
751 /** set solving process deinitialization method of conflict handler */
SCIPconflicthdlrSetExitsol(SCIP_CONFLICTHDLR * conflicthdlr,SCIP_DECL_CONFLICTEXITSOL ((* conflictexitsol)))752 void SCIPconflicthdlrSetExitsol(
753    SCIP_CONFLICTHDLR*    conflicthdlr,       /**< conflict handler */
754    SCIP_DECL_CONFLICTEXITSOL((*conflictexitsol))/**< solving process deinitialization method of conflict handler */
755    )
756 {
757    assert(conflicthdlr != NULL);
758 
759    conflicthdlr->conflictexitsol = conflictexitsol;
760 }
761 
762 /** gets name of conflict handler */
SCIPconflicthdlrGetName(SCIP_CONFLICTHDLR * conflicthdlr)763 const char* SCIPconflicthdlrGetName(
764    SCIP_CONFLICTHDLR*    conflicthdlr        /**< conflict handler */
765    )
766 {
767    assert(conflicthdlr != NULL);
768 
769    return conflicthdlr->name;
770 }
771 
772 /** gets description of conflict handler */
SCIPconflicthdlrGetDesc(SCIP_CONFLICTHDLR * conflicthdlr)773 const char* SCIPconflicthdlrGetDesc(
774    SCIP_CONFLICTHDLR*    conflicthdlr        /**< conflict handler */
775    )
776 {
777    assert(conflicthdlr != NULL);
778 
779    return conflicthdlr->desc;
780 }
781 
782 /** gets priority of conflict handler */
SCIPconflicthdlrGetPriority(SCIP_CONFLICTHDLR * conflicthdlr)783 int SCIPconflicthdlrGetPriority(
784    SCIP_CONFLICTHDLR*    conflicthdlr        /**< conflict handler */
785    )
786 {
787    assert(conflicthdlr != NULL);
788 
789    return conflicthdlr->priority;
790 }
791 
792 /** sets priority of conflict handler */
SCIPconflicthdlrSetPriority(SCIP_CONFLICTHDLR * conflicthdlr,SCIP_SET * set,int priority)793 void SCIPconflicthdlrSetPriority(
794    SCIP_CONFLICTHDLR*    conflicthdlr,       /**< conflict handler */
795    SCIP_SET*             set,                /**< global SCIP settings */
796    int                   priority            /**< new priority of the conflict handler */
797    )
798 {
799    assert(conflicthdlr != NULL);
800    assert(set != NULL);
801 
802    conflicthdlr->priority = priority;
803    set->conflicthdlrssorted = FALSE;
804 }
805 
806 /** is conflict handler initialized? */
SCIPconflicthdlrIsInitialized(SCIP_CONFLICTHDLR * conflicthdlr)807 SCIP_Bool SCIPconflicthdlrIsInitialized(
808    SCIP_CONFLICTHDLR*    conflicthdlr        /**< conflict handler */
809    )
810 {
811    assert(conflicthdlr != NULL);
812 
813    return conflicthdlr->initialized;
814 }
815 
816 /** enables or disables all clocks of \p conflicthdlr, depending on the value of the flag */
SCIPconflicthdlrEnableOrDisableClocks(SCIP_CONFLICTHDLR * conflicthdlr,SCIP_Bool enable)817 void SCIPconflicthdlrEnableOrDisableClocks(
818    SCIP_CONFLICTHDLR*    conflicthdlr,       /**< the conflict handler for which all clocks should be enabled or disabled */
819    SCIP_Bool             enable              /**< should the clocks of the conflict handler be enabled? */
820    )
821 {
822    assert(conflicthdlr != NULL);
823 
824    SCIPclockEnableOrDisable(conflicthdlr->setuptime, enable);
825    SCIPclockEnableOrDisable(conflicthdlr->conflicttime, enable);
826 }
827 
828 /** gets time in seconds used in this conflict handler for setting up for next stages */
SCIPconflicthdlrGetSetupTime(SCIP_CONFLICTHDLR * conflicthdlr)829 SCIP_Real SCIPconflicthdlrGetSetupTime(
830    SCIP_CONFLICTHDLR*    conflicthdlr        /**< conflict handler */
831    )
832 {
833    assert(conflicthdlr != NULL);
834 
835    return SCIPclockGetTime(conflicthdlr->setuptime);
836 }
837 
838 /** gets time in seconds used in this conflict handler */
SCIPconflicthdlrGetTime(SCIP_CONFLICTHDLR * conflicthdlr)839 SCIP_Real SCIPconflicthdlrGetTime(
840    SCIP_CONFLICTHDLR*    conflicthdlr        /**< conflict handler */
841    )
842 {
843    assert(conflicthdlr != NULL);
844 
845    return SCIPclockGetTime(conflicthdlr->conflicttime);
846 }
847 
848 /*
849  * Conflict LP Bound Changes
850  */
851 
852 
853 /** create conflict LP bound change data structure */
854 static
lpbdchgsCreate(SCIP_LPBDCHGS ** lpbdchgs,SCIP_SET * set,int ncols)855 SCIP_RETCODE lpbdchgsCreate(
856    SCIP_LPBDCHGS**       lpbdchgs,           /**< pointer to store the conflict LP bound change data structure */
857    SCIP_SET*             set,                /**< global SCIP settings */
858    int                   ncols               /**< number of columns */
859    )
860 {
861    SCIP_CALL( SCIPsetAllocBuffer(set, lpbdchgs) );
862 
863    SCIP_CALL( SCIPsetAllocBufferArray(set, &(*lpbdchgs)->bdchginds, ncols) );
864    SCIP_CALL( SCIPsetAllocBufferArray(set, &(*lpbdchgs)->bdchglbs, ncols) );
865    SCIP_CALL( SCIPsetAllocBufferArray(set, &(*lpbdchgs)->bdchgubs, ncols) );
866    SCIP_CALL( SCIPsetAllocBufferArray(set, &(*lpbdchgs)->bdchgcolinds, ncols) );
867    SCIP_CALL( SCIPsetAllocBufferArray(set, &(*lpbdchgs)->usedcols, ncols) );
868    BMSclearMemoryArray((*lpbdchgs)->usedcols, ncols);
869 
870    (*lpbdchgs)->nbdchgs = 0;
871 
872    return SCIP_OKAY;
873 }
874 
875 /** reset conflict LP bound change data structure */
876 static
lpbdchgsReset(SCIP_LPBDCHGS * lpbdchgs,int ncols)877 void lpbdchgsReset(
878    SCIP_LPBDCHGS*        lpbdchgs,           /**< conflict LP bound change data structure */
879    int                   ncols               /**< number of columns */
880    )
881 {
882    assert(lpbdchgs != NULL);
883 
884    BMSclearMemoryArray(lpbdchgs->usedcols, ncols);
885    lpbdchgs->nbdchgs = 0;
886 }
887 
888 /** free conflict LP bound change data structure */
889 static
lpbdchgsFree(SCIP_LPBDCHGS ** lpbdchgs,SCIP_SET * set)890 void lpbdchgsFree(
891    SCIP_LPBDCHGS**       lpbdchgs,           /**< pointer to store the conflict LP bound change data structure */
892    SCIP_SET*             set                 /**< global SCIP settings */
893    )
894 {
895    SCIPsetFreeBufferArray(set, &(*lpbdchgs)->usedcols);
896    SCIPsetFreeBufferArray(set, &(*lpbdchgs)->bdchgcolinds);
897    SCIPsetFreeBufferArray(set, &(*lpbdchgs)->bdchgubs);
898    SCIPsetFreeBufferArray(set, &(*lpbdchgs)->bdchglbs);
899    SCIPsetFreeBufferArray(set, &(*lpbdchgs)->bdchginds);
900 
901    SCIPsetFreeBuffer(set, lpbdchgs);
902 }
903 
904 /*
905  * Proof Sets
906  */
907 
908 /** return the char associated with the type of the variable */
909 static
varGetChar(SCIP_VAR * var)910 char varGetChar(
911    SCIP_VAR*             var                 /**< variable */
912    )
913 {
914    SCIP_VARTYPE vartype = SCIPvarGetType(var);
915 
916    return (!SCIPvarIsIntegral(var) ? 'C' :
917           (vartype == SCIP_VARTYPE_BINARY ? 'B' :
918           (vartype == SCIP_VARTYPE_INTEGER ? 'I' : 'M')));
919 }
920 
921 /** resets the data structure of a proofset */
922 static
proofsetClear(SCIP_PROOFSET * proofset)923 void proofsetClear(
924    SCIP_PROOFSET*        proofset            /**< proof set */
925    )
926 {
927    assert(proofset != NULL);
928 
929    proofset->nnz = 0;
930    proofset->rhs = 0.0;
931    proofset->validdepth = 0;
932    proofset->conflicttype = SCIP_CONFTYPE_UNKNOWN;
933 }
934 
935 /** creates a proofset */
936 static
proofsetCreate(SCIP_PROOFSET ** proofset,BMS_BLKMEM * blkmem)937 SCIP_RETCODE proofsetCreate(
938    SCIP_PROOFSET**       proofset,           /**< proof set */
939    BMS_BLKMEM*           blkmem              /**< block memory of transformed problem */
940    )
941 {
942    assert(proofset != NULL);
943 
944    SCIP_ALLOC( BMSallocBlockMemory(blkmem, proofset) );
945    (*proofset)->vals = NULL;
946    (*proofset)->inds = NULL;
947    (*proofset)->rhs = 0.0;
948    (*proofset)->nnz = 0;
949    (*proofset)->size = 0;
950    (*proofset)->validdepth = 0;
951    (*proofset)->conflicttype = SCIP_CONFTYPE_UNKNOWN;
952 
953    return SCIP_OKAY;
954 }
955 
956 /** creates and clears the proofset */
957 static
conflictInitProofset(SCIP_CONFLICT * conflict,BMS_BLKMEM * blkmem)958 SCIP_RETCODE conflictInitProofset(
959    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
960    BMS_BLKMEM*           blkmem              /**< block memory of transformed problem */
961    )
962 {
963    assert(conflict != NULL);
964    assert(blkmem != NULL);
965 
966    SCIP_CALL( proofsetCreate(&conflict->proofset, blkmem) );
967 
968    return SCIP_OKAY;
969 }
970 
971 /** frees a proofset */
972 static
proofsetFree(SCIP_PROOFSET ** proofset,BMS_BLKMEM * blkmem)973 void proofsetFree(
974    SCIP_PROOFSET**       proofset,           /**< proof set */
975    BMS_BLKMEM*           blkmem              /**< block memory */
976    )
977 {
978    assert(proofset != NULL);
979    assert(*proofset != NULL);
980    assert(blkmem != NULL);
981 
982    BMSfreeBlockMemoryArrayNull(blkmem, &(*proofset)->vals, (*proofset)->size);
983    BMSfreeBlockMemoryArrayNull(blkmem, &(*proofset)->inds, (*proofset)->size);
984    BMSfreeBlockMemory(blkmem, proofset);
985    (*proofset) = NULL;
986 }
987 
988 #ifdef SCIP_DEBUG
989 static
proofsetPrint(SCIP_PROOFSET * proofset,SCIP_SET * set,SCIP_PROB * transprob)990 void proofsetPrint(
991    SCIP_PROOFSET*        proofset,
992    SCIP_SET*             set,
993    SCIP_PROB*            transprob
994    )
995 {
996    SCIP_VAR** vars;
997    int i;
998 
999    assert(proofset != NULL);
1000 
1001    vars = SCIPprobGetVars(transprob);
1002    assert(vars != NULL);
1003 
1004    printf("proofset: ");
1005    for( i = 0; i < proofset->nnz; i++ )
1006       printf("%+.15g <%s> ", proofset->vals[i], SCIPvarGetName(vars[proofset->inds[i]]));
1007    printf(" <= %.15g\n", proofset->rhs);
1008 }
1009 #endif
1010 
1011 /** return the indices of variables in the proofset */
1012 static
proofsetGetInds(SCIP_PROOFSET * proofset)1013 int* proofsetGetInds(
1014    SCIP_PROOFSET*        proofset            /**< proof set */
1015    )
1016 {
1017    assert(proofset != NULL);
1018 
1019    return proofset->inds;
1020 }
1021 
1022 /** return coefficient of variable in the proofset with given probindex */
1023 static
proofsetGetVals(SCIP_PROOFSET * proofset)1024 SCIP_Real* proofsetGetVals(
1025    SCIP_PROOFSET*        proofset            /**< proof set */
1026    )
1027 {
1028    assert(proofset != NULL);
1029 
1030    return proofset->vals;
1031 }
1032 
1033 /** return the right-hand side if a proofset */
1034 static
proofsetGetRhs(SCIP_PROOFSET * proofset)1035 SCIP_Real proofsetGetRhs(
1036    SCIP_PROOFSET*        proofset            /**< proof set */
1037    )
1038 {
1039    assert(proofset != NULL);
1040 
1041    return proofset->rhs;
1042 }
1043 
1044 /** returns the number of variables in the proofset */
1045 static
proofsetGetNVars(SCIP_PROOFSET * proofset)1046 int proofsetGetNVars(
1047    SCIP_PROOFSET*        proofset            /**< proof set */
1048    )
1049 {
1050    assert(proofset != NULL);
1051 
1052    return proofset->nnz;
1053 }
1054 
1055 /** returns the number of variables in the proofset */
1056 static
proofsetGetConftype(SCIP_PROOFSET * proofset)1057 SCIP_CONFTYPE proofsetGetConftype(
1058    SCIP_PROOFSET*        proofset            /**< proof set */
1059    )
1060 {
1061    assert(proofset != NULL);
1062 
1063    return proofset->conflicttype;
1064 }
1065 
1066 /** adds given data as aggregation row to the proofset */
1067 static
proofsetAddSparseData(SCIP_PROOFSET * proofset,BMS_BLKMEM * blkmem,SCIP_Real * vals,int * inds,int nnz,SCIP_Real rhs)1068 SCIP_RETCODE proofsetAddSparseData(
1069    SCIP_PROOFSET*        proofset,           /**< proof set */
1070    BMS_BLKMEM*           blkmem,             /**< block memory */
1071    SCIP_Real*            vals,               /**< variable coefficients */
1072    int*                  inds,               /**< variable array */
1073    int                   nnz,                /**< size of variable and coefficient array */
1074    SCIP_Real             rhs                 /**< right-hand side of the aggregation row */
1075    )
1076 {
1077    assert(proofset != NULL);
1078    assert(blkmem != NULL);
1079 
1080    if( proofset->size == 0 )
1081    {
1082       assert(proofset->vals == NULL);
1083       assert(proofset->inds == NULL);
1084 
1085       SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &proofset->vals, vals, nnz) );
1086       SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &proofset->inds, inds, nnz) );
1087 
1088       proofset->size = nnz;
1089    }
1090    else
1091    {
1092       int i;
1093 
1094       assert(proofset->vals != NULL);
1095       assert(proofset->inds != NULL);
1096 
1097       if( proofset->size < nnz )
1098       {
1099          SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &proofset->vals, proofset->size, nnz) );
1100          SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &proofset->inds, proofset->size, nnz) );
1101          proofset->size = nnz;
1102       }
1103 
1104       for( i = 0; i < nnz; i++ )
1105       {
1106          proofset->vals[i] = vals[i];
1107          proofset->inds[i] = inds[i];
1108       }
1109    }
1110 
1111    proofset->rhs = rhs;
1112    proofset->nnz = nnz;
1113 
1114    return SCIP_OKAY;
1115 }
1116 
1117 /** adds an aggregation row to the proofset */
1118 static
proofsetAddAggrrow(SCIP_PROOFSET * proofset,SCIP_SET * set,BMS_BLKMEM * blkmem,SCIP_AGGRROW * aggrrow)1119 SCIP_RETCODE proofsetAddAggrrow(
1120    SCIP_PROOFSET*        proofset,           /**< proof set */
1121    SCIP_SET*             set,                /**< global SCIP settings */
1122    BMS_BLKMEM*           blkmem,             /**< block memory */
1123    SCIP_AGGRROW*         aggrrow             /**< aggregation row to add */
1124    )
1125 {
1126    SCIP_Real* vals;
1127    int* inds;
1128    int nnz;
1129    int i;
1130 
1131    assert(proofset != NULL);
1132    assert(set != NULL);
1133 
1134    inds = SCIPaggrRowGetInds(aggrrow);
1135    assert(inds != NULL);
1136 
1137    nnz = SCIPaggrRowGetNNz(aggrrow);
1138    assert(nnz > 0);
1139 
1140    SCIP_CALL( SCIPsetAllocBufferArray(set, &vals, nnz) );
1141 
1142    for( i = 0; i < nnz; i++ )
1143    {
1144       vals[i] = SCIPaggrRowGetProbvarValue(aggrrow, inds[i]);
1145    }
1146 
1147    SCIP_CALL( proofsetAddSparseData(proofset, blkmem, vals, inds, nnz, SCIPaggrRowGetRhs(aggrrow)) );
1148 
1149    SCIPsetFreeBufferArray(set, &vals);
1150 
1151    return SCIP_OKAY;
1152 }
1153 
1154 /** Removes a given variable @p var from position @p pos from the proofset and updates the right-hand side according
1155  *  to sign of the coefficient, i.e., rhs -= coef * bound, where bound = lb if coef >= 0 and bound = ub, otherwise.
1156  *
1157  *  @note: The list of non-zero indices and coefficients will be updated by swapping the last non-zero index to @p pos.
1158  */
1159 static
proofsetCancelVarWithBound(SCIP_PROOFSET * proofset,SCIP_SET * set,SCIP_VAR * var,int pos,SCIP_Bool * valid)1160 void proofsetCancelVarWithBound(
1161    SCIP_PROOFSET*        proofset,
1162    SCIP_SET*             set,
1163    SCIP_VAR*             var,
1164    int                   pos,
1165    SCIP_Bool*            valid
1166    )
1167 {
1168    assert(proofset != NULL);
1169    assert(var != NULL);
1170    assert(pos >= 0 && pos < proofset->nnz);
1171    assert(valid != NULL);
1172 
1173    *valid = TRUE;
1174 
1175    /* cancel with lower bound */
1176    if( proofset->vals[pos] > 0.0 )
1177    {
1178       proofset->rhs -= proofset->vals[pos] * SCIPvarGetLbGlobal(var);
1179    }
1180    /* cancel with upper bound */
1181    else
1182    {
1183       assert(proofset->vals[pos] < 0.0);
1184       proofset->rhs -= proofset->vals[pos] * SCIPvarGetUbGlobal(var);
1185    }
1186 
1187    --proofset->nnz;
1188 
1189    proofset->vals[pos] = proofset->vals[proofset->nnz];
1190    proofset->inds[pos] = proofset->inds[proofset->nnz];
1191    proofset->vals[proofset->nnz] = 0.0;
1192    proofset->inds[proofset->nnz] = 0;
1193 
1194    if( SCIPsetIsInfinity(set, proofset->rhs) )
1195       *valid = FALSE;
1196 }
1197 
1198 /*
1199  * Conflict Sets
1200  */
1201 
1202 /** resizes the array of the temporary bound change informations to be able to store at least num bound change entries */
1203 static
conflictEnsureTmpbdchginfosMem(SCIP_CONFLICT * conflict,SCIP_SET * set,int num)1204 SCIP_RETCODE conflictEnsureTmpbdchginfosMem(
1205    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
1206    SCIP_SET*             set,                /**< global SCIP settings */
1207    int                   num                 /**< minimal number of slots in arrays */
1208    )
1209 {
1210    assert(conflict != NULL);
1211    assert(set != NULL);
1212 
1213    if( num > conflict->tmpbdchginfossize )
1214    {
1215       int newsize;
1216 
1217       newsize = SCIPsetCalcMemGrowSize(set, num);
1218       SCIP_ALLOC( BMSreallocMemoryArray(&conflict->tmpbdchginfos, newsize) );
1219       conflict->tmpbdchginfossize = newsize;
1220    }
1221    assert(num <= conflict->tmpbdchginfossize);
1222 
1223    return SCIP_OKAY;
1224 }
1225 
1226 /** creates a temporary bound change information object that is destroyed after the conflict sets are flushed */
1227 static
conflictCreateTmpBdchginfo(SCIP_CONFLICT * conflict,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_VAR * var,SCIP_BOUNDTYPE boundtype,SCIP_Real oldbound,SCIP_Real newbound,SCIP_BDCHGINFO ** bdchginfo)1228 SCIP_RETCODE conflictCreateTmpBdchginfo(
1229    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
1230    BMS_BLKMEM*           blkmem,             /**< block memory */
1231    SCIP_SET*             set,                /**< global SCIP settings */
1232    SCIP_VAR*             var,                /**< active variable that changed the bounds */
1233    SCIP_BOUNDTYPE        boundtype,          /**< type of bound for var: lower or upper bound */
1234    SCIP_Real             oldbound,           /**< old value for bound */
1235    SCIP_Real             newbound,           /**< new value for bound */
1236    SCIP_BDCHGINFO**      bdchginfo           /**< pointer to store bound change information */
1237    )
1238 {
1239    assert(conflict != NULL);
1240 
1241    SCIP_CALL( conflictEnsureTmpbdchginfosMem(conflict, set, conflict->ntmpbdchginfos+1) );
1242    SCIP_CALL( SCIPbdchginfoCreate(&conflict->tmpbdchginfos[conflict->ntmpbdchginfos], blkmem,
1243          var, boundtype, oldbound, newbound) );
1244    *bdchginfo = conflict->tmpbdchginfos[conflict->ntmpbdchginfos];
1245    conflict->ntmpbdchginfos++;
1246 
1247    return SCIP_OKAY;
1248 }
1249 
1250 /** frees all temporarily created bound change information data */
1251 static
conflictFreeTmpBdchginfos(SCIP_CONFLICT * conflict,BMS_BLKMEM * blkmem)1252 void conflictFreeTmpBdchginfos(
1253    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
1254    BMS_BLKMEM*           blkmem              /**< block memory */
1255    )
1256 {
1257    int i;
1258 
1259    assert(conflict != NULL);
1260 
1261    for( i = 0; i < conflict->ntmpbdchginfos; ++i )
1262       SCIPbdchginfoFree(&conflict->tmpbdchginfos[i], blkmem);
1263    conflict->ntmpbdchginfos = 0;
1264 }
1265 
1266 /** clears the given conflict set */
1267 static
conflictsetClear(SCIP_CONFLICTSET * conflictset)1268 void conflictsetClear(
1269    SCIP_CONFLICTSET*     conflictset         /**< conflict set */
1270    )
1271 {
1272    assert(conflictset != NULL);
1273 
1274    conflictset->nbdchginfos = 0;
1275    conflictset->validdepth = 0;
1276    conflictset->insertdepth = 0;
1277    conflictset->conflictdepth = 0;
1278    conflictset->repropdepth = 0;
1279    conflictset->repropagate = TRUE;
1280    conflictset->usescutoffbound = FALSE;
1281    conflictset->hasrelaxonlyvar = FALSE;
1282    conflictset->conflicttype = SCIP_CONFTYPE_UNKNOWN;
1283 }
1284 
1285 /** creates an empty conflict set */
1286 static
conflictsetCreate(SCIP_CONFLICTSET ** conflictset,BMS_BLKMEM * blkmem)1287 SCIP_RETCODE conflictsetCreate(
1288    SCIP_CONFLICTSET**    conflictset,        /**< pointer to store the conflict set */
1289    BMS_BLKMEM*           blkmem              /**< block memory of transformed problem */
1290    )
1291 {
1292    assert(conflictset != NULL);
1293 
1294    SCIP_ALLOC( BMSallocBlockMemory(blkmem, conflictset) );
1295    (*conflictset)->bdchginfos = NULL;
1296    (*conflictset)->relaxedbds = NULL;
1297    (*conflictset)->sortvals = NULL;
1298    (*conflictset)->bdchginfossize = 0;
1299 
1300    conflictsetClear(*conflictset);
1301 
1302    return SCIP_OKAY;
1303 }
1304 
1305 /** creates a copy of the given conflict set, allocating an additional amount of memory */
1306 static
conflictsetCopy(SCIP_CONFLICTSET ** targetconflictset,BMS_BLKMEM * blkmem,SCIP_CONFLICTSET * sourceconflictset,int nadditionalelems)1307 SCIP_RETCODE conflictsetCopy(
1308    SCIP_CONFLICTSET**    targetconflictset,  /**< pointer to store the conflict set */
1309    BMS_BLKMEM*           blkmem,             /**< block memory of transformed problem */
1310    SCIP_CONFLICTSET*     sourceconflictset,  /**< source conflict set */
1311    int                   nadditionalelems    /**< number of additional elements to allocate memory for */
1312    )
1313 {
1314    int targetsize;
1315 
1316    assert(targetconflictset != NULL);
1317    assert(sourceconflictset != NULL);
1318 
1319    targetsize = sourceconflictset->nbdchginfos + nadditionalelems;
1320    SCIP_ALLOC( BMSallocBlockMemory(blkmem, targetconflictset) );
1321    SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*targetconflictset)->bdchginfos, targetsize) );
1322    SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*targetconflictset)->relaxedbds, targetsize) );
1323    SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*targetconflictset)->sortvals, targetsize) );
1324    (*targetconflictset)->bdchginfossize = targetsize;
1325 
1326    BMScopyMemoryArray((*targetconflictset)->bdchginfos, sourceconflictset->bdchginfos, sourceconflictset->nbdchginfos);
1327    BMScopyMemoryArray((*targetconflictset)->relaxedbds, sourceconflictset->relaxedbds, sourceconflictset->nbdchginfos);
1328    BMScopyMemoryArray((*targetconflictset)->sortvals, sourceconflictset->sortvals, sourceconflictset->nbdchginfos);
1329 
1330    (*targetconflictset)->nbdchginfos = sourceconflictset->nbdchginfos;
1331    (*targetconflictset)->validdepth = sourceconflictset->validdepth;
1332    (*targetconflictset)->insertdepth = sourceconflictset->insertdepth;
1333    (*targetconflictset)->conflictdepth = sourceconflictset->conflictdepth;
1334    (*targetconflictset)->repropdepth = sourceconflictset->repropdepth;
1335    (*targetconflictset)->usescutoffbound = sourceconflictset->usescutoffbound;
1336    (*targetconflictset)->hasrelaxonlyvar = sourceconflictset->hasrelaxonlyvar;
1337    (*targetconflictset)->conflicttype = sourceconflictset->conflicttype;
1338 
1339    return SCIP_OKAY;
1340 }
1341 
1342 /** frees a conflict set */
1343 static
conflictsetFree(SCIP_CONFLICTSET ** conflictset,BMS_BLKMEM * blkmem)1344 void conflictsetFree(
1345    SCIP_CONFLICTSET**    conflictset,        /**< pointer to the conflict set */
1346    BMS_BLKMEM*           blkmem              /**< block memory of transformed problem */
1347    )
1348 {
1349    assert(conflictset != NULL);
1350    assert(*conflictset != NULL);
1351 
1352    BMSfreeBlockMemoryArrayNull(blkmem, &(*conflictset)->bdchginfos, (*conflictset)->bdchginfossize);
1353    BMSfreeBlockMemoryArrayNull(blkmem, &(*conflictset)->relaxedbds, (*conflictset)->bdchginfossize);
1354    BMSfreeBlockMemoryArrayNull(blkmem, &(*conflictset)->sortvals, (*conflictset)->bdchginfossize);
1355    BMSfreeBlockMemory(blkmem, conflictset);
1356 }
1357 
1358 /** resizes the arrays of the conflict set to be able to store at least num bound change entries */
1359 static
conflictsetEnsureBdchginfosMem(SCIP_CONFLICTSET * conflictset,BMS_BLKMEM * blkmem,SCIP_SET * set,int num)1360 SCIP_RETCODE conflictsetEnsureBdchginfosMem(
1361    SCIP_CONFLICTSET*     conflictset,        /**< conflict set */
1362    BMS_BLKMEM*           blkmem,             /**< block memory of transformed problem */
1363    SCIP_SET*             set,                /**< global SCIP settings */
1364    int                   num                 /**< minimal number of slots in arrays */
1365    )
1366 {
1367    assert(conflictset != NULL);
1368    assert(set != NULL);
1369 
1370    if( num > conflictset->bdchginfossize )
1371    {
1372       int newsize;
1373 
1374       newsize = SCIPsetCalcMemGrowSize(set, num);
1375       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &conflictset->bdchginfos, conflictset->bdchginfossize, newsize) );
1376       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &conflictset->relaxedbds, conflictset->bdchginfossize, newsize) );
1377       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &conflictset->sortvals, conflictset->bdchginfossize, newsize) );
1378       conflictset->bdchginfossize = newsize;
1379    }
1380    assert(num <= conflictset->bdchginfossize);
1381 
1382    return SCIP_OKAY;
1383 }
1384 
1385 /** calculates the score of the conflict set
1386  *
1387  *  the score is weighted sum of number of bound changes, repropagation depth, and valid depth
1388  */
1389 static
conflictsetCalcScore(SCIP_CONFLICTSET * conflictset,SCIP_SET * set)1390 SCIP_Real conflictsetCalcScore(
1391    SCIP_CONFLICTSET*     conflictset,        /**< conflict set */
1392    SCIP_SET*             set                 /**< global SCIP settings */
1393    )
1394 {
1395    assert(conflictset != NULL);
1396 
1397    return -(set->conf_weightsize * conflictset->nbdchginfos
1398          + set->conf_weightrepropdepth * conflictset->repropdepth
1399          + set->conf_weightvaliddepth * conflictset->validdepth);
1400 }
1401 
1402 /** calculates the score of a bound change within a conflict */
1403 static
calcBdchgScore(SCIP_Real prooflhs,SCIP_Real proofact,SCIP_Real proofactdelta,SCIP_Real proofcoef,int depth,int currentdepth,SCIP_VAR * var,SCIP_SET * set)1404 SCIP_Real calcBdchgScore(
1405    SCIP_Real             prooflhs,           /**< lhs of proof constraint */
1406    SCIP_Real             proofact,           /**< activity of the proof constraint */
1407    SCIP_Real             proofactdelta,      /**< activity change */
1408    SCIP_Real             proofcoef,          /**< coefficient in proof constraint */
1409    int                   depth,              /**< bound change depth */
1410    int                   currentdepth,       /**< current depth */
1411    SCIP_VAR*             var,                /**< variable corresponding to bound change */
1412    SCIP_SET*             set                 /**< global SCIP settings */
1413    )
1414 {
1415    SCIP_COL* col;
1416    SCIP_Real score;
1417 
1418    score = set->conf_proofscorefac * (1.0 - proofactdelta/(prooflhs - proofact));
1419    score = MAX(score, 0.0);
1420    score += set->conf_depthscorefac * (SCIP_Real)(depth+1)/(SCIP_Real)(currentdepth+1);
1421 
1422    if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN )
1423       col = SCIPvarGetCol(var);
1424    else
1425       col = NULL;
1426 
1427    if( proofcoef > 0.0 )
1428    {
1429       if( col != NULL && SCIPcolGetNNonz(col) > 0 )
1430          score += set->conf_uplockscorefac
1431             * (SCIP_Real)(SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL))/(SCIP_Real)(SCIPcolGetNNonz(col));
1432       else
1433          score += set->conf_uplockscorefac * SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL);
1434    }
1435    else
1436    {
1437       if( col != NULL && SCIPcolGetNNonz(col) > 0 )
1438          score += set->conf_downlockscorefac
1439             * (SCIP_Real)(SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL))/(SCIP_Real)(SCIPcolGetNNonz(col));
1440       else
1441          score += set->conf_downlockscorefac * SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL);
1442    }
1443 
1444    return score;
1445 }
1446 
1447 /** check if the bound change info (which is the potential next candidate which is queued) is valid for the current
1448  *  conflict analysis; a bound change info can get invalid if after this one was added to the queue, a weaker bound
1449  *  change was added to the queue (due the bound widening idea) which immediately makes this bound change redundant; due
1450  *  to the priority we did not removed that bound change info since that cost O(log(n)); hence we have to skip/ignore it
1451  *  now
1452  *
1453  *  The following situations can occur before for example the bound change info (x >= 3) is potentially popped from the
1454  *  queue.
1455  *
1456  *  Postcondition: the reason why (x >= 3) was queued is that at this time point no lower bound of x was involved yet in
1457  *                 the current conflict or the lower bound which was involved until then was stronger, e.g., (x >= 2).
1458  *
1459  *  1) during the time until (x >= 3) gets potentially popped no weaker lower bound was added to the queue, in that case
1460  *     the conflictlbcount is valid and conflictlb is 3; that is (var->conflictlbcount == conflict->count &&
1461  *     var->conflictlb == 3)
1462  *
1463  *  2) a weaker bound change info gets queued (e.g., x >= 4); this bound change is popped before (x >= 3) since it has
1464  *     higher priority (which is the time stamp of the bound change info and (x >= 4) has to be done after (x >= 3)
1465  *     during propagation or branching)
1466  *
1467  *    a) if (x >= 4) is popped and added to the conflict set the conflictlbcount is still valid and conflictlb is at
1468  *      most 4; that is (var->conflictlbcount == conflict->count && var->conflictlb >= 4); it follows that any bound
1469  *      change info which is stronger than (x >= 4) gets ignored (for example x >= 2)
1470  *
1471  *    b) if (x >= 4) is popped and resolved without introducing a new lower bound on x until (x >= 3) is a potentially
1472  *       candidate the conflictlbcount indicates that bound change is currently not present; that is
1473  *       (var->conflictlbcount != conflict->count)
1474  *
1475  *    c) if (x >= 4) is popped and resolved and a new lower bound on x (e.g., x >= 2) is introduced until (x >= 3) is
1476  *       pooped, the conflictlbcount indicates that bound change is currently present; that is (var->conflictlbcount ==
1477  *       conflict->count); however the (x >= 3) only has be explained if conflictlb matches that one; that is
1478  *       (var->conflictlb == bdchginfo->newbound); otherwise it redundant/invalid.
1479  */
1480 static
bdchginfoIsInvalid(SCIP_CONFLICT * conflict,SCIP_BDCHGINFO * bdchginfo)1481 SCIP_Bool bdchginfoIsInvalid(
1482    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
1483    SCIP_BDCHGINFO*       bdchginfo           /**< bound change information */
1484    )
1485 {
1486    SCIP_VAR* var;
1487 
1488    assert(bdchginfo != NULL);
1489 
1490    var = SCIPbdchginfoGetVar(bdchginfo);
1491    assert(var != NULL);
1492 
1493    /* the bound change info of a binary (domained) variable can never be invalid since the concepts of relaxed bounds
1494     * and bound widening do not make sense for these type of variables
1495     */
1496    if( SCIPvarIsBinary(var) )
1497       return FALSE;
1498 
1499    /* check if the bdchginfo is invaild since a tight/weaker bound change was already explained */
1500    if( SCIPbdchginfoGetBoundtype(bdchginfo) == SCIP_BOUNDTYPE_LOWER )
1501    {
1502       if( var->conflictlbcount != conflict->count || var->conflictlb != SCIPbdchginfoGetNewbound(bdchginfo) ) /*lint !e777*/
1503       {
1504          assert(!SCIPvarIsBinary(var));
1505          return TRUE;
1506       }
1507    }
1508    else
1509    {
1510       assert(SCIPbdchginfoGetBoundtype(bdchginfo) == SCIP_BOUNDTYPE_UPPER);
1511 
1512       if( var->conflictubcount != conflict->count || var->conflictub != SCIPbdchginfoGetNewbound(bdchginfo) ) /*lint !e777*/
1513       {
1514          assert(!SCIPvarIsBinary(var));
1515          return TRUE;
1516       }
1517    }
1518 
1519    return FALSE;
1520 }
1521 
1522 /** adds a bound change to a conflict set */
1523 static
conflictsetAddBound(SCIP_CONFLICTSET * conflictset,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_BDCHGINFO * bdchginfo,SCIP_Real relaxedbd)1524 SCIP_RETCODE conflictsetAddBound(
1525    SCIP_CONFLICTSET*     conflictset,        /**< conflict set */
1526    BMS_BLKMEM*           blkmem,             /**< block memory of transformed problem */
1527    SCIP_SET*             set,                /**< global SCIP settings */
1528    SCIP_BDCHGINFO*       bdchginfo,          /**< bound change to add to the conflict set */
1529    SCIP_Real             relaxedbd           /**< relaxed bound */
1530    )
1531 {
1532    SCIP_BDCHGINFO** bdchginfos;
1533    SCIP_Real* relaxedbds;
1534    int* sortvals;
1535    SCIP_VAR* var;
1536    SCIP_BOUNDTYPE boundtype;
1537    int idx;
1538    int sortval;
1539    int pos;
1540 
1541    assert(conflictset != NULL);
1542    assert(bdchginfo != NULL);
1543 
1544    /* allocate memory for additional element */
1545    SCIP_CALL( conflictsetEnsureBdchginfosMem(conflictset, blkmem, set, conflictset->nbdchginfos+1) );
1546 
1547    /* insert the new bound change in the arrays sorted by increasing variable index and by bound type */
1548    bdchginfos = conflictset->bdchginfos;
1549    relaxedbds = conflictset->relaxedbds;
1550    sortvals = conflictset->sortvals;
1551    var = SCIPbdchginfoGetVar(bdchginfo);
1552    boundtype = SCIPbdchginfoGetBoundtype(bdchginfo);
1553    idx = SCIPvarGetIndex(var);
1554    assert(idx < INT_MAX/2);
1555    assert((int)boundtype == 0 || (int)boundtype == 1);
1556    sortval = 2*idx + (int)boundtype; /* first sorting criteria: variable index, second criteria: boundtype */
1557 
1558    /* insert new element into the sorted arrays; if an element exits with the same value insert the new element afterwards
1559     *
1560     * @todo check if it better (faster) to first search for the position O(log n) and compare the sort values and if
1561     *       they are equal just replace the element and if not run the insert method O(n)
1562     */
1563 
1564    SCIPsortedvecInsertIntPtrReal(sortvals, (void**)bdchginfos, relaxedbds, sortval, (void*)bdchginfo, relaxedbd, &conflictset->nbdchginfos, &pos);
1565    assert(pos == conflictset->nbdchginfos - 1 || sortval < sortvals[pos+1]);
1566 
1567    /* merge multiple bound changes */
1568    if( pos > 0 && sortval == sortvals[pos-1] )
1569    {
1570       /* this is a multiple bound change */
1571       if( SCIPbdchginfoIsTighter(bdchginfo, bdchginfos[pos-1]) )
1572       {
1573          /* remove the "old" bound change since the "new" one in tighter */
1574          SCIPsortedvecDelPosIntPtrReal(sortvals, (void**)bdchginfos, relaxedbds, pos-1, &conflictset->nbdchginfos);
1575       }
1576       else if( SCIPbdchginfoIsTighter(bdchginfos[pos-1], bdchginfo) )
1577       {
1578          /* remove the "new"  bound change since the "old" one is tighter */
1579          SCIPsortedvecDelPosIntPtrReal(sortvals, (void**)bdchginfos, relaxedbds, pos, &conflictset->nbdchginfos);
1580       }
1581       else
1582       {
1583          /* both bound change are equivalent; hence, keep the worse relaxed bound and remove one of them */
1584          relaxedbds[pos-1] = boundtype == SCIP_BOUNDTYPE_LOWER ? MAX(relaxedbds[pos-1], relaxedbd) : MIN(relaxedbds[pos-1], relaxedbd);
1585          SCIPsortedvecDelPosIntPtrReal(sortvals, (void**)bdchginfos, relaxedbds, pos, &conflictset->nbdchginfos);
1586       }
1587    }
1588 
1589    if( SCIPvarIsRelaxationOnly(var) )
1590       conflictset->hasrelaxonlyvar = TRUE;
1591 
1592    return SCIP_OKAY;
1593 }
1594 
1595 /** adds given bound changes to a conflict set */
1596 static
conflictsetAddBounds(SCIP_CONFLICT * conflict,SCIP_CONFLICTSET * conflictset,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_BDCHGINFO ** bdchginfos,int nbdchginfos)1597 SCIP_RETCODE conflictsetAddBounds(
1598    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
1599    SCIP_CONFLICTSET*     conflictset,        /**< conflict set */
1600    BMS_BLKMEM*           blkmem,             /**< block memory of transformed problem */
1601    SCIP_SET*             set,                /**< global SCIP settings */
1602    SCIP_BDCHGINFO**      bdchginfos,         /**< bound changes to add to the conflict set */
1603    int                   nbdchginfos         /**< number of bound changes to add */
1604    )
1605 {
1606    SCIP_BDCHGINFO** confbdchginfos;
1607    SCIP_BDCHGINFO* bdchginfo;
1608    SCIP_Real* confrelaxedbds;
1609    int* confsortvals;
1610    int confnbdchginfos;
1611    int idx;
1612    int sortval;
1613    int i;
1614    SCIP_BOUNDTYPE boundtype;
1615 
1616    assert(conflict != NULL);
1617    assert(conflictset != NULL);
1618    assert(blkmem != NULL);
1619    assert(set != NULL);
1620    assert(bdchginfos != NULL || nbdchginfos == 0);
1621 
1622    /* nothing to add */
1623    if( nbdchginfos == 0 )
1624       return SCIP_OKAY;
1625 
1626    assert(bdchginfos != NULL);
1627 
1628    /* only one element to add, use the single insertion method */
1629    if( nbdchginfos == 1 )
1630    {
1631       bdchginfo = bdchginfos[0];
1632       assert(bdchginfo != NULL);
1633 
1634       if( !bdchginfoIsInvalid(conflict, bdchginfo) )
1635       {
1636          SCIP_CALL( conflictsetAddBound(conflictset, blkmem, set, bdchginfo, SCIPbdchginfoGetRelaxedBound(bdchginfo)) );
1637       }
1638       else
1639       {
1640          SCIPsetDebugMsg(set, "-> bound change info [%d:<%s> %s %g] is invaild -> ignore it\n", SCIPbdchginfoGetDepth(bdchginfo),
1641             SCIPvarGetName(SCIPbdchginfoGetVar(bdchginfo)),
1642             SCIPbdchginfoGetBoundtype(bdchginfo) == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=",
1643             SCIPbdchginfoGetNewbound(bdchginfo));
1644       }
1645 
1646       return SCIP_OKAY;
1647    }
1648 
1649    confnbdchginfos = conflictset->nbdchginfos;
1650 
1651    /* allocate memory for additional element */
1652    SCIP_CALL( conflictsetEnsureBdchginfosMem(conflictset, blkmem, set, confnbdchginfos + nbdchginfos) );
1653 
1654    confbdchginfos = conflictset->bdchginfos;
1655    confrelaxedbds = conflictset->relaxedbds;
1656    confsortvals = conflictset->sortvals;
1657 
1658    assert(SCIP_BOUNDTYPE_LOWER == FALSE); /*lint !e641 !e506*/
1659    assert(SCIP_BOUNDTYPE_UPPER == TRUE); /*lint !e641 !e506*/
1660 
1661    for( i = 0; i < nbdchginfos; ++i )
1662    {
1663       bdchginfo = bdchginfos[i];
1664       assert(bdchginfo != NULL);
1665 
1666       /* add only valid bound change infos */
1667       if( !bdchginfoIsInvalid(conflict, bdchginfo) )
1668       {
1669          /* calculate sorting value */
1670          boundtype = SCIPbdchginfoGetBoundtype(bdchginfo);
1671          assert(SCIPbdchginfoGetVar(bdchginfo) != NULL);
1672 
1673          idx = SCIPvarGetIndex(SCIPbdchginfoGetVar(bdchginfo));
1674          assert(idx < INT_MAX/2);
1675 
1676          assert((int)boundtype == 0 || (int)boundtype == 1);
1677          sortval = 2*idx + (int)boundtype; /* first sorting criteria: variable index, second criteria: boundtype */
1678 
1679          /* add new element */
1680          confbdchginfos[confnbdchginfos] = bdchginfo;
1681          confrelaxedbds[confnbdchginfos] = SCIPbdchginfoGetRelaxedBound(bdchginfo);
1682          confsortvals[confnbdchginfos] = sortval;
1683          ++confnbdchginfos;
1684 
1685          if( SCIPvarIsRelaxationOnly(SCIPbdchginfoGetVar(bdchginfo)) )
1686             conflictset->hasrelaxonlyvar = TRUE;
1687       }
1688       else
1689       {
1690          SCIPsetDebugMsg(set, "-> bound change info [%d:<%s> %s %g] is invaild -> ignore it\n", SCIPbdchginfoGetDepth(bdchginfo),
1691             SCIPvarGetName(SCIPbdchginfoGetVar(bdchginfo)),
1692             SCIPbdchginfoGetBoundtype(bdchginfo) == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=",
1693             SCIPbdchginfoGetNewbound(bdchginfo));
1694       }
1695    }
1696    assert(confnbdchginfos <= conflictset->nbdchginfos + nbdchginfos);
1697 
1698    /* sort and merge the new conflict set */
1699    if( confnbdchginfos > conflictset->nbdchginfos )
1700    {
1701       int k = 0;
1702 
1703       /* sort array */
1704       SCIPsortIntPtrReal(confsortvals, (void**)confbdchginfos, confrelaxedbds, confnbdchginfos);
1705 
1706       i = 1;
1707       /* merge multiple bound changes */
1708       while( i < confnbdchginfos )
1709       {
1710          assert(i > k);
1711 
1712          /* is this a multiple bound change */
1713          if( confsortvals[k] == confsortvals[i] )
1714          {
1715             if( SCIPbdchginfoIsTighter(confbdchginfos[k], confbdchginfos[i]) )
1716                ++i;
1717             else if( SCIPbdchginfoIsTighter(confbdchginfos[i], confbdchginfos[k]) )
1718             {
1719                /* replace worse bound change info by tighter bound change info */
1720                confbdchginfos[k] = confbdchginfos[i];
1721                confrelaxedbds[k] = confrelaxedbds[i];
1722                confsortvals[k] = confsortvals[i];
1723                ++i;
1724             }
1725             else
1726             {
1727                assert(confsortvals[k] == confsortvals[i]);
1728 
1729                /* both bound change are equivalent; hence, keep the worse relaxed bound and remove one of them */
1730                confrelaxedbds[k] = (confsortvals[k] % 2 == 0) ? MAX(confrelaxedbds[k], confrelaxedbds[i]) : MIN(confrelaxedbds[k], confrelaxedbds[i]);
1731                ++i;
1732             }
1733          }
1734          else
1735          {
1736             /* all bound change infos must be valid */
1737             assert(!bdchginfoIsInvalid(conflict, confbdchginfos[k]));
1738 
1739             ++k;
1740             /* move next comparison element to the correct position */
1741             if( k != i )
1742             {
1743                confbdchginfos[k] = confbdchginfos[i];
1744                confrelaxedbds[k] = confrelaxedbds[i];
1745                confsortvals[k] = confsortvals[i];
1746             }
1747             ++i;
1748          }
1749       }
1750       /* last bound change infos must also be valid */
1751       assert(!bdchginfoIsInvalid(conflict, confbdchginfos[k]));
1752       /* the number of bound change infos cannot be decreased, it would mean that the conflict set was not merged
1753        * before
1754        */
1755       assert(conflictset->nbdchginfos <= k + 1 );
1756       assert(k + 1 <= confnbdchginfos);
1757 
1758       conflictset->nbdchginfos = k + 1;
1759    }
1760 
1761    return SCIP_OKAY;
1762 }
1763 
1764 /** calculates the conflict and the repropagation depths of the conflict set */
1765 static
conflictsetCalcConflictDepth(SCIP_CONFLICTSET * conflictset)1766 void conflictsetCalcConflictDepth(
1767    SCIP_CONFLICTSET*     conflictset         /**< conflict set */
1768    )
1769 {
1770    int maxdepth[2];
1771    int i;
1772 
1773    assert(conflictset != NULL);
1774    assert(conflictset->validdepth <= conflictset->insertdepth);
1775 
1776    /* get the depth of the last and last but one bound change */
1777    maxdepth[0] = conflictset->validdepth;
1778    maxdepth[1] = conflictset->validdepth;
1779    for( i = 0; i < conflictset->nbdchginfos; ++i )
1780    {
1781       int depth;
1782 
1783       depth = SCIPbdchginfoGetDepth(conflictset->bdchginfos[i]);
1784       assert(depth >= 0);
1785       if( depth > maxdepth[0] )
1786       {
1787          maxdepth[1] = maxdepth[0];
1788          maxdepth[0] = depth;
1789       }
1790       else if( depth > maxdepth[1] )
1791          maxdepth[1] = depth;
1792    }
1793    assert(maxdepth[0] >= maxdepth[1]);
1794 
1795    conflictset->conflictdepth = maxdepth[0];
1796    conflictset->repropdepth = maxdepth[1];
1797 }
1798 
1799 /** identifies the depth, at which the conflict set should be added:
1800  *  - if the branching rule operates on variables only, and if all branching variables up to a certain
1801  *    depth level are member of the conflict, the conflict constraint can only be violated in the subtree
1802  *    of the node at that depth, because in all other nodes, at least one of these branching variables
1803  *    violates its conflicting bound, such that the conflict constraint is feasible
1804  *  - if there is at least one branching variable in a node, we assume, that this branching was performed
1805  *    on variables, and that the siblings of this node are disjunct w.r.t. the branching variables' fixings
1806  *  - we have to add the conflict set at least in the valid depth of the initial conflict set,
1807  *    so we start searching at the first branching after this depth level, i.e. validdepth+1
1808  */
1809 static
conflictsetCalcInsertDepth(SCIP_CONFLICTSET * conflictset,SCIP_SET * set,SCIP_TREE * tree)1810 SCIP_RETCODE conflictsetCalcInsertDepth(
1811    SCIP_CONFLICTSET*     conflictset,        /**< conflict set */
1812    SCIP_SET*             set,                /**< global SCIP settings */
1813    SCIP_TREE*            tree                /**< branch and bound tree */
1814    )
1815 {
1816    SCIP_Bool* branchingincluded;
1817    int currentdepth;
1818    int i;
1819 
1820    assert(conflictset != NULL);
1821    assert(set != NULL);
1822    assert(tree != NULL);
1823 
1824    /* the conflict set must not be inserted prior to its valid depth */
1825    conflictset->insertdepth = conflictset->validdepth;
1826    assert(conflictset->insertdepth >= 0);
1827 
1828    currentdepth = SCIPtreeGetCurrentDepth(tree);
1829    assert(currentdepth == tree->pathlen-1);
1830 
1831    /* mark the levels for which a branching variable is included in the conflict set */
1832    SCIP_CALL( SCIPsetAllocBufferArray(set, &branchingincluded, currentdepth+2) );
1833    BMSclearMemoryArray(branchingincluded, currentdepth+2);
1834    for( i = 0; i < conflictset->nbdchginfos; ++i )
1835    {
1836       int depth;
1837 
1838       depth = SCIPbdchginfoGetDepth(conflictset->bdchginfos[i]);
1839       depth = MIN(depth, currentdepth+1); /* put diving/probing/strong branching changes in this depth level */
1840       branchingincluded[depth] = TRUE;
1841    }
1842 
1843    /* skip additional depth levels where branching on the conflict variables was applied */
1844    while( conflictset->insertdepth < currentdepth && branchingincluded[conflictset->insertdepth+1] )
1845       conflictset->insertdepth++;
1846 
1847    /* free temporary memory */
1848    SCIPsetFreeBufferArray(set, &branchingincluded);
1849 
1850    assert(conflictset->validdepth <= conflictset->insertdepth && conflictset->insertdepth <= currentdepth);
1851 
1852    return SCIP_OKAY;
1853 }
1854 
1855 /** checks whether the first conflict set is redundant to the second one */
1856 static
conflictsetIsRedundant(SCIP_CONFLICTSET * conflictset1,SCIP_CONFLICTSET * conflictset2)1857 SCIP_Bool conflictsetIsRedundant(
1858    SCIP_CONFLICTSET*     conflictset1,       /**< first conflict conflict set */
1859    SCIP_CONFLICTSET*     conflictset2        /**< second conflict conflict set */
1860    )
1861 {
1862    int i1;
1863    int i2;
1864 
1865    assert(conflictset1 != NULL);
1866    assert(conflictset2 != NULL);
1867 
1868    /* if conflictset1 has smaller validdepth, it is definitely not redundant to conflictset2 */
1869    if( conflictset1->validdepth < conflictset2->validdepth )
1870       return FALSE;
1871 
1872    /* check, if all bound changes in conflictset2 are also present at least as tight in conflictset1;
1873     * we can stop immediately, if more bound changes are remaining in conflictset2 than in conflictset1
1874     */
1875    for( i1 = 0, i2 = 0; i2 < conflictset2->nbdchginfos && conflictset1->nbdchginfos - i1 >= conflictset2->nbdchginfos - i2;
1876         ++i1, ++i2 )
1877    {
1878       int sortval;
1879 
1880       assert(i2 == 0 || conflictset2->sortvals[i2-1] < conflictset2->sortvals[i2]);
1881 
1882       sortval = conflictset2->sortvals[i2];
1883       for( ; i1 < conflictset1->nbdchginfos && conflictset1->sortvals[i1] < sortval; ++i1 ) /*lint !e445*/
1884       {
1885          /* while scanning conflictset1, check consistency */
1886          assert(i1 == 0 || conflictset1->sortvals[i1-1] < conflictset1->sortvals[i1]);
1887       }
1888       if( i1 >= conflictset1->nbdchginfos || conflictset1->sortvals[i1] > sortval
1889          || SCIPbdchginfoIsTighter(conflictset2->bdchginfos[i2], conflictset1->bdchginfos[i1]) )
1890          return FALSE;
1891    }
1892 
1893    return (i2 == conflictset2->nbdchginfos);
1894 }
1895 
1896 #ifdef SCIP_DEBUG
1897 /** prints a conflict set to the screen */
1898 static
conflictsetPrint(SCIP_CONFLICTSET * conflictset)1899 void conflictsetPrint(
1900    SCIP_CONFLICTSET*     conflictset         /**< conflict set */
1901    )
1902 {
1903    int i;
1904 
1905    assert(conflictset != NULL);
1906    for( i = 0; i < conflictset->nbdchginfos; ++i )
1907    {
1908       SCIPdebugPrintf(" [%d:<%s> %s %g(%g)]", SCIPbdchginfoGetDepth(conflictset->bdchginfos[i]),
1909          SCIPvarGetName(SCIPbdchginfoGetVar(conflictset->bdchginfos[i])),
1910          SCIPbdchginfoGetBoundtype(conflictset->bdchginfos[i]) == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=",
1911          SCIPbdchginfoGetNewbound(conflictset->bdchginfos[i]), conflictset->relaxedbds[i]);
1912    }
1913    SCIPdebugPrintf("\n");
1914 }
1915 #endif
1916 
1917 /** resizes proofsets array to be able to store at least num entries */
1918 static
conflictEnsureProofsetsMem(SCIP_CONFLICT * conflict,SCIP_SET * set,int num)1919 SCIP_RETCODE conflictEnsureProofsetsMem(
1920    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
1921    SCIP_SET*             set,                /**< global SCIP settings */
1922    int                   num                 /**< minimal number of slots in array */
1923    )
1924 {
1925    assert(conflict != NULL);
1926    assert(set != NULL);
1927 
1928    if( num > conflict->proofsetssize )
1929    {
1930       int newsize;
1931 
1932       newsize = SCIPsetCalcMemGrowSize(set, num);
1933       SCIP_ALLOC( BMSreallocMemoryArray(&conflict->proofsets, newsize) );
1934       conflict->proofsetssize = newsize;
1935    }
1936    assert(num <= conflict->proofsetssize);
1937 
1938    return SCIP_OKAY;
1939 }
1940 
1941 /** resizes conflictsets array to be able to store at least num entries */
1942 static
conflictEnsureConflictsetsMem(SCIP_CONFLICT * conflict,SCIP_SET * set,int num)1943 SCIP_RETCODE conflictEnsureConflictsetsMem(
1944    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
1945    SCIP_SET*             set,                /**< global SCIP settings */
1946    int                   num                 /**< minimal number of slots in array */
1947    )
1948 {
1949    assert(conflict != NULL);
1950    assert(set != NULL);
1951 
1952    if( num > conflict->conflictsetssize )
1953    {
1954       int newsize;
1955 
1956       newsize = SCIPsetCalcMemGrowSize(set, num);
1957       SCIP_ALLOC( BMSreallocMemoryArray(&conflict->conflictsets, newsize) );
1958       SCIP_ALLOC( BMSreallocMemoryArray(&conflict->conflictsetscores, newsize) );
1959       conflict->conflictsetssize = newsize;
1960    }
1961    assert(num <= conflict->conflictsetssize);
1962 
1963    return SCIP_OKAY;
1964 }
1965 
1966 /** add a proofset to the list of all proofsets */
1967 static
conflictInsertProofset(SCIP_CONFLICT * conflict,SCIP_SET * set,SCIP_PROOFSET * proofset)1968 SCIP_RETCODE conflictInsertProofset(
1969    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
1970    SCIP_SET*             set,                /**< global SCIP settings */
1971    SCIP_PROOFSET*        proofset            /**< proof set to add */
1972    )
1973 {
1974    assert(conflict != NULL);
1975    assert(proofset != NULL);
1976 
1977    /* insert proofset into the sorted proofsets array */
1978    SCIP_CALL( conflictEnsureProofsetsMem(conflict, set, conflict->nproofsets + 1) );
1979 
1980    conflict->proofsets[conflict->nproofsets] = proofset;
1981    ++conflict->nproofsets;
1982 
1983    return SCIP_OKAY;
1984 }
1985 
1986 /** inserts conflict set into sorted conflictsets array and deletes the conflict set pointer */
1987 static
conflictInsertConflictset(SCIP_CONFLICT * conflict,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_CONFLICTSET ** conflictset)1988 SCIP_RETCODE conflictInsertConflictset(
1989    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
1990    BMS_BLKMEM*           blkmem,             /**< block memory of transformed problem */
1991    SCIP_SET*             set,                /**< global SCIP settings */
1992    SCIP_CONFLICTSET**    conflictset         /**< pointer to conflict set to insert */
1993    )
1994 {
1995    SCIP_Real score;
1996    int pos;
1997    int i;
1998    int j;
1999 
2000    assert(conflict != NULL);
2001    assert(set != NULL);
2002    assert(conflictset != NULL);
2003    assert(*conflictset != NULL);
2004    assert((*conflictset)->validdepth <= (*conflictset)->insertdepth);
2005    assert(set->conf_allowlocal || (*conflictset)->validdepth == 0);
2006 
2007    /* calculate conflict and repropagation depth */
2008    conflictsetCalcConflictDepth(*conflictset);
2009 
2010    /* if we apply repropagations, the conflict set should be inserted at most at its repropdepth */
2011    if( set->conf_repropagate )
2012       (*conflictset)->insertdepth = MIN((*conflictset)->insertdepth, (*conflictset)->repropdepth);
2013    else
2014       (*conflictset)->repropdepth = INT_MAX;
2015    assert((*conflictset)->insertdepth <= (*conflictset)->repropdepth);
2016 
2017    SCIPsetDebugMsg(set, "inserting conflict set (valid: %d, insert: %d, conf: %d, reprop: %d):\n",
2018       (*conflictset)->validdepth, (*conflictset)->insertdepth, (*conflictset)->conflictdepth, (*conflictset)->repropdepth);
2019    SCIPdebug(conflictsetPrint(*conflictset));
2020 
2021    /* get the score of the conflict set */
2022    score = conflictsetCalcScore(*conflictset, set);
2023 
2024    /* check, if conflict set is redundant to a better conflict set */
2025    for( pos = 0; pos < conflict->nconflictsets && score < conflict->conflictsetscores[pos]; ++pos )
2026    {
2027       /* check if conflict set is redundant with respect to conflictsets[pos] */
2028       if( conflictsetIsRedundant(*conflictset, conflict->conflictsets[pos]) )
2029       {
2030          SCIPsetDebugMsg(set, " -> conflict set is redundant to: ");
2031          SCIPdebug(conflictsetPrint(conflict->conflictsets[pos]));
2032          conflictsetFree(conflictset, blkmem);
2033          return SCIP_OKAY;
2034       }
2035 
2036       /**@todo like in sepastore.c: calculate overlap between conflictsets -> large overlap reduces score */
2037    }
2038 
2039    /* insert conflictset into the sorted conflictsets array */
2040    SCIP_CALL( conflictEnsureConflictsetsMem(conflict, set, conflict->nconflictsets + 1) );
2041    for( i = conflict->nconflictsets; i > pos; --i )
2042    {
2043       assert(score >= conflict->conflictsetscores[i-1]);
2044       conflict->conflictsets[i] = conflict->conflictsets[i-1];
2045       conflict->conflictsetscores[i] = conflict->conflictsetscores[i-1];
2046    }
2047    conflict->conflictsets[pos] = *conflictset;
2048    conflict->conflictsetscores[pos] = score;
2049    conflict->nconflictsets++;
2050 
2051    /* remove worse conflictsets that are redundant to the new conflictset */
2052    for( i = pos+1, j = pos+1; i < conflict->nconflictsets; ++i )
2053    {
2054       if( conflictsetIsRedundant(conflict->conflictsets[i], *conflictset) )
2055       {
2056          SCIPsetDebugMsg(set, " -> conflict set dominates: ");
2057          SCIPdebug(conflictsetPrint(conflict->conflictsets[i]));
2058          conflictsetFree(&conflict->conflictsets[i], blkmem);
2059       }
2060       else
2061       {
2062          assert(j <= i);
2063          conflict->conflictsets[j] = conflict->conflictsets[i];
2064          conflict->conflictsetscores[j] = conflict->conflictsetscores[i];
2065          j++;
2066       }
2067    }
2068    assert(j <= conflict->nconflictsets);
2069    conflict->nconflictsets = j;
2070 
2071 #ifdef SCIP_CONFGRAPH
2072    confgraphMarkConflictset(*conflictset);
2073 #endif
2074 
2075    *conflictset = NULL; /* ownership of pointer is now in the conflictsets array */
2076 
2077    return SCIP_OKAY;
2078 }
2079 
2080 /** calculates the maximal size of conflict sets to be used */
2081 static
conflictCalcMaxsize(SCIP_SET * set,SCIP_PROB * prob)2082 int conflictCalcMaxsize(
2083    SCIP_SET*             set,                /**< global SCIP settings */
2084    SCIP_PROB*            prob                /**< problem data */
2085    )
2086 {
2087    int maxsize;
2088 
2089    assert(set != NULL);
2090    assert(prob != NULL);
2091 
2092    maxsize = (int)(set->conf_maxvarsfac * (prob->nvars - prob->ncontvars));
2093    maxsize = MAX(maxsize, set->conf_minmaxvars);
2094 
2095    return maxsize;
2096 }
2097 
2098 /** increases the conflict score of the variable in the given direction */
2099 static
incVSIDS(SCIP_VAR * var,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_BOUNDTYPE boundtype,SCIP_Real value,SCIP_Real weight)2100 SCIP_RETCODE incVSIDS(
2101    SCIP_VAR*             var,                /**< problem variable */
2102    BMS_BLKMEM*           blkmem,             /**< block memory */
2103    SCIP_SET*             set,                /**< global SCIP settings */
2104    SCIP_STAT*            stat,               /**< dynamic problem statistics */
2105    SCIP_BOUNDTYPE        boundtype,          /**< type of bound for which the score should be increased */
2106    SCIP_Real             value,              /**< value of the bound */
2107    SCIP_Real             weight              /**< weight of this VSIDS updates */
2108    )
2109 {
2110    SCIP_BRANCHDIR branchdir;
2111 
2112    assert(var != NULL);
2113    assert(stat != NULL);
2114 
2115    /* weight the VSIDS by the given weight */
2116    weight *= stat->vsidsweight;
2117 
2118    if( SCIPsetIsZero(set, weight) )
2119       return SCIP_OKAY;
2120 
2121    branchdir = (boundtype == SCIP_BOUNDTYPE_LOWER ? SCIP_BRANCHDIR_UPWARDS : SCIP_BRANCHDIR_DOWNWARDS); /*lint !e641*/
2122    SCIP_CALL( SCIPvarIncVSIDS(var, blkmem, set, stat, branchdir, value, weight) );
2123    SCIPhistoryIncVSIDS(stat->glbhistory, branchdir,  weight);
2124    SCIPhistoryIncVSIDS(stat->glbhistorycrun, branchdir,  weight);
2125 
2126    return SCIP_OKAY;
2127 }
2128 
2129 /** update conflict statistics */
2130 static
updateStatistics(SCIP_CONFLICT * conflict,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_CONFLICTSET * conflictset,int insertdepth)2131 SCIP_RETCODE updateStatistics(
2132    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
2133    BMS_BLKMEM*           blkmem,             /**< block memory */
2134    SCIP_SET*             set,                /**< global SCIP settings */
2135    SCIP_STAT*            stat,               /**< dynamic problem statistics */
2136    SCIP_CONFLICTSET*     conflictset,        /**< conflict set to add to the tree */
2137    int                   insertdepth         /**< depth level at which the conflict set should be added */
2138    )
2139 {
2140    if( insertdepth > 0 )
2141    {
2142       conflict->nappliedlocconss++;
2143       conflict->nappliedlocliterals += conflictset->nbdchginfos;
2144    }
2145    else
2146    {
2147       int i;
2148       int conflictlength;
2149       conflictlength = conflictset->nbdchginfos;
2150 
2151       for( i = 0; i < conflictlength; i++ )
2152       {
2153          SCIP_VAR* var;
2154          SCIP_BRANCHDIR branchdir;
2155          SCIP_BOUNDTYPE boundtype;
2156          SCIP_Real bound;
2157 
2158          assert(stat != NULL);
2159 
2160          var = conflictset->bdchginfos[i]->var;
2161          boundtype = SCIPbdchginfoGetBoundtype(conflictset->bdchginfos[i]);
2162          bound = conflictset->relaxedbds[i];
2163 
2164          branchdir = (boundtype == SCIP_BOUNDTYPE_LOWER ? SCIP_BRANCHDIR_UPWARDS : SCIP_BRANCHDIR_DOWNWARDS); /*lint !e641*/
2165 
2166          SCIP_CALL( SCIPvarIncNActiveConflicts(var, blkmem, set, stat,  branchdir, bound, (SCIP_Real)conflictlength) );
2167          SCIPhistoryIncNActiveConflicts(stat->glbhistory, branchdir, (SCIP_Real)conflictlength);
2168          SCIPhistoryIncNActiveConflicts(stat->glbhistorycrun, branchdir, (SCIP_Real)conflictlength);
2169 
2170          /* each variable which is part of the conflict gets an increase in the VSIDS */
2171          SCIP_CALL( incVSIDS(var, blkmem, set, stat, boundtype, bound, set->conf_conflictweight) );
2172       }
2173       conflict->nappliedglbconss++;
2174       conflict->nappliedglbliterals += conflictset->nbdchginfos;
2175    }
2176 
2177    return SCIP_OKAY;
2178 }
2179 
2180 
2181 /** check conflict set for redundancy, other conflicts in the same conflict analysis could have led to global reductions
2182  *  an made this conflict set redundant
2183  */
2184 static
checkRedundancy(SCIP_SET * set,SCIP_CONFLICTSET * conflictset)2185 SCIP_Bool checkRedundancy(
2186    SCIP_SET*             set,                /**< global SCIP settings */
2187    SCIP_CONFLICTSET*     conflictset         /**< conflict set */
2188    )
2189 {
2190    SCIP_BDCHGINFO** bdchginfos;
2191    SCIP_VAR* var;
2192    SCIP_Real* relaxedbds;
2193    SCIP_Real bound;
2194    int v;
2195 
2196    assert(set != NULL);
2197    assert(conflictset != NULL);
2198 
2199    bdchginfos = conflictset->bdchginfos;
2200    relaxedbds = conflictset->relaxedbds;
2201    assert(bdchginfos != NULL);
2202    assert(relaxedbds != NULL);
2203 
2204    /* check all boundtypes and bounds for redundancy */
2205    for( v = conflictset->nbdchginfos - 1; v >= 0; --v )
2206    {
2207       var = SCIPbdchginfoGetVar(bdchginfos[v]);
2208       assert(var != NULL);
2209       assert(SCIPvarGetProbindex(var) >= 0);
2210 
2211       /* check if the relaxed bound is really a relaxed bound */
2212       assert(SCIPbdchginfoGetBoundtype(bdchginfos[v]) == SCIP_BOUNDTYPE_LOWER || SCIPsetIsGE(set, relaxedbds[v], SCIPbdchginfoGetNewbound(bdchginfos[v])));
2213       assert(SCIPbdchginfoGetBoundtype(bdchginfos[v]) == SCIP_BOUNDTYPE_UPPER || SCIPsetIsLE(set, relaxedbds[v], SCIPbdchginfoGetNewbound(bdchginfos[v])));
2214 
2215       bound = relaxedbds[v];
2216 
2217       if( SCIPbdchginfoGetBoundtype(bdchginfos[v]) == SCIP_BOUNDTYPE_UPPER )
2218       {
2219          if( SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS )
2220          {
2221             assert(SCIPsetIsIntegral(set, bound));
2222             bound += 1.0;
2223          }
2224 
2225          /* check if the bound is already fulfilled globally */
2226          if( SCIPsetIsFeasGE(set, SCIPvarGetLbGlobal(var), bound) )
2227             return TRUE;
2228       }
2229       else
2230       {
2231          assert(SCIPbdchginfoGetBoundtype(bdchginfos[v]) == SCIP_BOUNDTYPE_LOWER);
2232 
2233          if( SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS )
2234          {
2235             assert(SCIPsetIsIntegral(set, bound));
2236             bound -= 1.0;
2237          }
2238 
2239          /* check if the bound is already fulfilled globally */
2240          if( SCIPsetIsFeasLE(set, SCIPvarGetUbGlobal(var), bound) )
2241             return TRUE;
2242       }
2243    }
2244 
2245    return FALSE;
2246 }
2247 
2248 /** find global fixings which can be derived from the new conflict set */
2249 static
detectImpliedBounds(SCIP_SET * set,SCIP_PROB * prob,SCIP_CONFLICTSET * conflictset,int * nbdchgs,int * nredvars,SCIP_Bool * redundant)2250 SCIP_RETCODE detectImpliedBounds(
2251    SCIP_SET*             set,                /**< global SCIP settings */
2252    SCIP_PROB*            prob,               /**< transformed problem after presolve */
2253    SCIP_CONFLICTSET*     conflictset,        /**< conflict set to add to the tree */
2254    int*                  nbdchgs,            /**< number of global deducted bound changes due to the conflict set */
2255    int*                  nredvars,           /**< number of redundant and removed variables from conflict set */
2256    SCIP_Bool*            redundant           /**< did we found a global reduction on a conflict set variable, which makes this conflict redundant */
2257    )
2258 {
2259    SCIP_BDCHGINFO** bdchginfos;
2260    SCIP_Real* relaxedbds;
2261    SCIP_VAR* var;
2262    SCIP_Bool* boundtypes;
2263    SCIP_Real* bounds;
2264    SCIP_Longint* nbinimpls;
2265    int* sortvals;
2266    SCIP_Real bound;
2267    SCIP_Bool isupper;
2268    int ntrivialredvars;
2269    int nbdchginfos;
2270    int nzeroimpls;
2271    int v;
2272 
2273    assert(set != NULL);
2274    assert(prob != NULL);
2275    assert(SCIPprobIsTransformed(prob));
2276    assert(conflictset != NULL);
2277    assert(nbdchgs != NULL);
2278    assert(nredvars != NULL);
2279    /* only check conflict sets with more than one variable */
2280    assert(conflictset->nbdchginfos > 1);
2281 
2282    *nbdchgs = 0;
2283    *nredvars = 0;
2284 
2285    /* due to other conflict in the same conflict analysis, this conflict set might have become redundant */
2286    *redundant = checkRedundancy(set, conflictset);
2287 
2288    if( *redundant )
2289       return SCIP_OKAY;
2290 
2291    bdchginfos = conflictset->bdchginfos;
2292    relaxedbds = conflictset->relaxedbds;
2293    nbdchginfos = conflictset->nbdchginfos;
2294    sortvals = conflictset->sortvals;
2295 
2296    assert(bdchginfos != NULL);
2297    assert(relaxedbds != NULL);
2298    assert(sortvals != NULL);
2299 
2300    /* check if the boolean representation of boundtypes matches the 'standard' definition */
2301    assert(SCIP_BOUNDTYPE_LOWER == FALSE); /*lint !e641 !e506*/
2302    assert(SCIP_BOUNDTYPE_UPPER == TRUE); /*lint !e641 !e506*/
2303 
2304    ntrivialredvars = 0;
2305 
2306    /* due to multiple conflict sets for one conflict, it can happen, that we already have redundant information in the
2307     * conflict set
2308     */
2309    for( v = nbdchginfos - 1; v >= 0; --v )
2310    {
2311       var = SCIPbdchginfoGetVar(bdchginfos[v]);
2312       bound = relaxedbds[v];
2313       isupper = (SCIP_Bool) SCIPboundtypeOpposite(SCIPbdchginfoGetBoundtype(bdchginfos[v]));
2314 
2315       /* for integral variable we can increase/decrease the conflicting bound */
2316       if( SCIPvarIsIntegral(var) )
2317          bound += (isupper ? -1.0 : +1.0);
2318 
2319       /* if conflict variable cannot fulfill the conflict we can remove it */
2320       if( (isupper && SCIPsetIsFeasLT(set, bound, SCIPvarGetLbGlobal(var))) ||
2321          (!isupper && SCIPsetIsFeasGT(set, bound, SCIPvarGetUbGlobal(var))) )
2322       {
2323          SCIPsetDebugMsg(set, "remove redundant variable <%s> from conflict set\n", SCIPvarGetName(var));
2324 
2325          bdchginfos[v] = bdchginfos[nbdchginfos - 1];
2326          relaxedbds[v] = relaxedbds[nbdchginfos - 1];
2327          sortvals[v] = sortvals[nbdchginfos - 1];
2328 
2329          --nbdchginfos;
2330          ++ntrivialredvars;
2331       }
2332    }
2333    assert(ntrivialredvars + nbdchginfos == conflictset->nbdchginfos);
2334 
2335    SCIPsetDebugMsg(set, "trivially removed %d redundant of %d variables from conflictset (%p)\n", ntrivialredvars, conflictset->nbdchginfos, (void*)conflictset);
2336    conflictset->nbdchginfos = nbdchginfos;
2337 
2338    /* all variables where removed, the conflict cannot be fulfilled, i.e., we have an infeasibility proof */
2339    if( conflictset->nbdchginfos == 0 )
2340       return SCIP_OKAY;
2341 
2342    /* do not check to big or trivial conflicts */
2343    if( conflictset->nbdchginfos > set->conf_maxvarsdetectimpliedbounds || conflictset->nbdchginfos == 1 )
2344    {
2345       *nredvars = ntrivialredvars;
2346       return SCIP_OKAY;
2347    }
2348 
2349    /* create array of boundtypes, and bound values in conflict set */
2350    SCIP_CALL( SCIPsetAllocBufferArray(set, &boundtypes, nbdchginfos) );
2351    SCIP_CALL( SCIPsetAllocBufferArray(set, &bounds, nbdchginfos) );
2352    /* memory for the estimates for binary implications used for sorting */
2353    SCIP_CALL( SCIPsetAllocBufferArray(set, &nbinimpls, nbdchginfos) );
2354 
2355    nzeroimpls = 0;
2356 
2357    /* collect estimates and initialize variables, boundtypes, and bounds array */
2358    for( v = 0; v < nbdchginfos; ++v )
2359    {
2360       var = SCIPbdchginfoGetVar(bdchginfos[v]);
2361       boundtypes[v] = (SCIP_Bool) SCIPboundtypeOpposite(SCIPbdchginfoGetBoundtype(bdchginfos[v]));
2362       bounds[v] = relaxedbds[v];
2363 
2364       assert(SCIPvarGetProbindex(var) >= 0);
2365 
2366       /* check if the relaxed bound is really a relaxed bound */
2367       assert(SCIPbdchginfoGetBoundtype(bdchginfos[v]) == SCIP_BOUNDTYPE_LOWER || SCIPsetIsGE(set, relaxedbds[v], SCIPbdchginfoGetNewbound(bdchginfos[v])));
2368       assert(SCIPbdchginfoGetBoundtype(bdchginfos[v]) == SCIP_BOUNDTYPE_UPPER || SCIPsetIsLE(set, relaxedbds[v], SCIPbdchginfoGetNewbound(bdchginfos[v])));
2369 
2370       /* for continuous variables, we can only use the relaxed version of the bounds negation: !(x <= u) -> x >= u */
2371       if( SCIPvarIsBinary(var) )
2372       {
2373          if( !boundtypes[v] )
2374          {
2375             assert(SCIPsetIsZero(set, bounds[v]));
2376             bounds[v] = 1.0;
2377             nbinimpls[v] = (SCIP_Longint)SCIPvarGetNCliques(var, TRUE) * 2;
2378          }
2379          else
2380          {
2381             assert(SCIPsetIsEQ(set, bounds[v], 1.0));
2382             bounds[v] = 0.0;
2383             nbinimpls[v] = (SCIP_Longint)SCIPvarGetNCliques(var, FALSE) * 2;
2384          }
2385       }
2386       else if( SCIPvarIsIntegral(var) )
2387       {
2388          assert(SCIPsetIsIntegral(set, bounds[v]));
2389 
2390          bounds[v] += ((!boundtypes[v]) ? +1.0 : -1.0);
2391          nbinimpls[v] = (boundtypes[v] ? SCIPvarGetNVlbs(var) : SCIPvarGetNVubs(var));
2392       }
2393       else if( ((!boundtypes[v]) && SCIPsetIsFeasEQ(set, SCIPvarGetLbGlobal(var), bounds[v]))
2394          || ((boundtypes[v]) && SCIPsetIsFeasEQ(set, SCIPvarGetUbGlobal(var), bounds[v])) )
2395       {
2396          /* the literal is satisfied in global bounds (may happen due to weak "negation" of continuous variables)
2397           * -> discard the conflict constraint
2398           */
2399          break;
2400       }
2401       else
2402       {
2403          nbinimpls[v] = (boundtypes[v] ? SCIPvarGetNVlbs(var) : SCIPvarGetNVubs(var));
2404       }
2405 
2406       if( nbinimpls[v] == 0 )
2407          ++nzeroimpls;
2408    }
2409 
2410    /* starting to derive global bound changes */
2411    if( v == nbdchginfos && ((!set->conf_fullshortenconflict && nzeroimpls < 2) || (set->conf_fullshortenconflict && nzeroimpls < nbdchginfos)) )
2412    {
2413       SCIP_VAR** vars;
2414       SCIP_Bool* redundants;
2415       SCIP_Bool glbinfeas;
2416 
2417       /* sort variables in increasing order of binary implications to gain speed later on */
2418       SCIPsortLongPtrRealRealBool(nbinimpls, (void**)bdchginfos, relaxedbds, bounds, boundtypes, v);
2419 
2420       SCIPsetDebugMsg(set, "checking for global reductions and redundant conflict variables(in %s) on conflict:\n", SCIPprobGetName(prob));
2421       SCIPsetDebugMsg(set, "[");
2422       for( v = 0; v < nbdchginfos; ++v )
2423       {
2424          SCIPsetDebugMsgPrint(set, "%s %s %g", SCIPvarGetName(SCIPbdchginfoGetVar(bdchginfos[v])), (!boundtypes[v]) ? ">=" : "<=", bounds[v]);
2425          if( v < nbdchginfos - 1 )
2426             SCIPsetDebugMsgPrint(set, ", ");
2427       }
2428       SCIPsetDebugMsgPrint(set, "]\n");
2429 
2430       SCIP_CALL( SCIPsetAllocBufferArray(set, &vars, v) );
2431       SCIP_CALL( SCIPsetAllocCleanBufferArray(set, &redundants, v) );
2432 
2433       /* initialize conflict variable data */
2434       for( v = 0; v < nbdchginfos; ++v )
2435          vars[v] = SCIPbdchginfoGetVar(bdchginfos[v]);
2436 
2437       SCIP_CALL( SCIPshrinkDisjunctiveVarSet(set->scip, vars, bounds, boundtypes, redundants, nbdchginfos, nredvars, \
2438             nbdchgs, redundant, &glbinfeas, set->conf_fullshortenconflict) );
2439 
2440       if( glbinfeas )
2441       {
2442          SCIPsetDebugMsg(set, "conflict set (%p) led to global infeasibility\n", (void*) conflictset);
2443 
2444          /* clear the memory array before freeing it */
2445          BMSclearMemoryArray(redundants, nbdchginfos);
2446          goto TERMINATE;
2447       }
2448 
2449 #ifdef SCIP_DEBUG
2450       if( *nbdchgs > 0 )
2451       {
2452          SCIPsetDebugMsg(set, "conflict set (%p) led to %d global bound reductions\n", (void*) conflictset, *nbdchgs);
2453       }
2454 #endif
2455 
2456       /* remove as redundant marked variables */
2457       if( *redundant )
2458       {
2459          SCIPsetDebugMsg(set, "conflict set (%p) is redundant because at least one global reduction, fulfills the conflict constraint\n", (void*)conflictset);
2460 
2461          /* clear the memory array before freeing it */
2462          BMSclearMemoryArray(redundants, nbdchginfos);
2463       }
2464       else if( *nredvars > 0 )
2465       {
2466          assert(bdchginfos == conflictset->bdchginfos);
2467          assert(relaxedbds == conflictset->relaxedbds);
2468          assert(sortvals == conflictset->sortvals);
2469 
2470          for( v = nbdchginfos - 1; v >= 0; --v )
2471          {
2472             /* if conflict variable was marked to be redundant remove it */
2473             if( redundants[v] )
2474             {
2475                SCIPsetDebugMsg(set, "remove redundant variable <%s> from conflict set\n", SCIPvarGetName(SCIPbdchginfoGetVar(bdchginfos[v])));
2476 
2477                bdchginfos[v] = bdchginfos[nbdchginfos - 1];
2478                relaxedbds[v] = relaxedbds[nbdchginfos - 1];
2479                sortvals[v] = sortvals[nbdchginfos - 1];
2480 
2481                /* reset redundants[v] to 0 */
2482                redundants[v] = 0;
2483 
2484                --nbdchginfos;
2485             }
2486          }
2487          assert((*nredvars) + nbdchginfos == conflictset->nbdchginfos);
2488 
2489          SCIPsetDebugMsg(set, "removed %d redundant of %d variables from conflictset (%p)\n", (*nredvars), conflictset->nbdchginfos, (void*)conflictset);
2490          conflictset->nbdchginfos = nbdchginfos;
2491       }
2492       else
2493       {
2494          /* clear the memory array before freeing it */
2495          BMSclearMemoryArray(redundants, nbdchginfos);
2496       }
2497 
2498      TERMINATE:
2499       SCIPsetFreeCleanBufferArray(set, &redundants);
2500       SCIPsetFreeBufferArray(set, &vars);
2501    }
2502 
2503    /* free temporary memory */
2504    SCIPsetFreeBufferArray(set, &nbinimpls);
2505    SCIPsetFreeBufferArray(set, &bounds);
2506    SCIPsetFreeBufferArray(set, &boundtypes);
2507 
2508    *nredvars += ntrivialredvars;
2509 
2510    return SCIP_OKAY;
2511 }
2512 
2513 /** tighten the bound of a singleton variable in a constraint
2514  *
2515  *  if the bound is contradicting with a global bound we cannot tighten the bound directly.
2516  *  in this case we need to create and add a constraint of size one such that propagating this constraint will
2517  *  enforce the infeasibility.
2518  */
2519 static
tightenSingleVar(SCIP_CONFLICT * conflict,SCIP_SET * set,SCIP_STAT * stat,SCIP_TREE * tree,BMS_BLKMEM * blkmem,SCIP_PROB * origprob,SCIP_PROB * transprob,SCIP_REOPT * reopt,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_EVENTQUEUE * eventqueue,SCIP_CLIQUETABLE * cliquetable,SCIP_VAR * var,SCIP_Real val,SCIP_Real rhs,SCIP_CONFTYPE prooftype,int validdepth)2520 SCIP_RETCODE tightenSingleVar(
2521    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
2522    SCIP_SET*             set,                /**< global SCIP settings */
2523    SCIP_STAT*            stat,               /**< dynamic SCIP statistics */
2524    SCIP_TREE*            tree,               /**< tree data */
2525    BMS_BLKMEM*           blkmem,             /**< block memory */
2526    SCIP_PROB*            origprob,           /**< original problem */
2527    SCIP_PROB*            transprob,          /**< transformed problem */
2528    SCIP_REOPT*           reopt,              /**< reoptimization data */
2529    SCIP_LP*              lp,                 /**< LP data */
2530    SCIP_BRANCHCAND*      branchcand,         /**< branching candidates */
2531    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
2532    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table */
2533    SCIP_VAR*             var,                /**< problem variable */
2534    SCIP_Real             val,                /**< coefficient of the variable */
2535    SCIP_Real             rhs,                /**< rhs of the constraint */
2536    SCIP_CONFTYPE         prooftype,          /**< type of the proof */
2537    int                   validdepth          /**< depth where the bound change is valid */
2538    )
2539 {
2540    SCIP_Real newbound;
2541    SCIP_Bool applyglobal;
2542    SCIP_BOUNDTYPE boundtype;
2543 
2544    assert(tree != NULL);
2545    assert(validdepth >= 0);
2546 
2547    applyglobal = (validdepth <= SCIPtreeGetEffectiveRootDepth(tree));
2548 
2549    /* if variable and coefficient are integral the rhs can be rounded down */
2550    if( SCIPvarIsIntegral(var) && SCIPsetIsIntegral(set, val) )
2551       newbound = SCIPsetFeasFloor(set, rhs)/val;
2552    else
2553       newbound = rhs/val;
2554 
2555    boundtype = (val > 0.0 ? SCIP_BOUNDTYPE_UPPER : SCIP_BOUNDTYPE_LOWER);
2556    SCIPvarAdjustBd(var, set, boundtype, &newbound);
2557 
2558    /* skip numerical unstable bound changes */
2559    if( applyglobal
2560       && ((boundtype == SCIP_BOUNDTYPE_LOWER && SCIPsetIsLE(set, newbound, SCIPvarGetLbGlobal(var)))
2561        || (boundtype == SCIP_BOUNDTYPE_UPPER && SCIPsetIsGE(set, newbound, SCIPvarGetUbGlobal(var)))) )
2562    {
2563       return SCIP_OKAY;
2564    }
2565 
2566    /* the new bound contradicts a global bound, we can cutoff the root node immediately */
2567    if( applyglobal
2568       && ((boundtype == SCIP_BOUNDTYPE_LOWER && SCIPsetIsGT(set, newbound, SCIPvarGetUbGlobal(var)))
2569        || (boundtype == SCIP_BOUNDTYPE_UPPER && SCIPsetIsLT(set, newbound, SCIPvarGetLbGlobal(var)))) )
2570    {
2571       SCIPsetDebugMsg(set, "detected global infeasibility at var <%s>: locdom=[%g,%g] glbdom=[%g,%g] new %s bound=%g\n",
2572             SCIPvarGetName(var), SCIPvarGetLbLocal(var),
2573             SCIPvarGetUbLocal(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var),
2574             (boundtype == SCIP_BOUNDTYPE_LOWER ? "lower" : "upper"), newbound);
2575       SCIP_CALL( SCIPnodeCutoff(tree->path[0], set, stat, tree, transprob, origprob, reopt, lp, blkmem) );
2576    }
2577    else
2578    {
2579       if( lp->strongbranching || !applyglobal )
2580       {
2581          SCIP_CONS* cons;
2582          SCIP_Real conslhs;
2583          SCIP_Real consrhs;
2584          char name[SCIP_MAXSTRLEN];
2585 
2586          SCIPsetDebugMsg(set, "add constraint <%s>[%c] %s %g to node #%lld in depth %d\n",
2587                SCIPvarGetName(var), varGetChar(var), boundtype == SCIP_BOUNDTYPE_UPPER ? "<=" : ">=", newbound,
2588                SCIPnodeGetNumber(tree->path[validdepth]), validdepth);
2589 
2590          (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "pc_fix_%s", SCIPvarGetName(var));
2591 
2592          if( boundtype == SCIP_BOUNDTYPE_UPPER )
2593          {
2594             conslhs = -SCIPsetInfinity(set);
2595             consrhs = newbound;
2596          }
2597          else
2598          {
2599             conslhs = newbound;
2600             consrhs = SCIPsetInfinity(set);
2601          }
2602 
2603          SCIP_CALL( SCIPcreateConsLinear(set->scip, &cons, name, 0, NULL, NULL, conslhs, consrhs,
2604                FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE) );
2605 
2606          SCIP_CALL( SCIPaddCoefLinear(set->scip, cons, var, 1.0) );
2607 
2608          if( applyglobal )
2609          {
2610             SCIP_CALL( SCIPprobAddCons(transprob, set, stat, cons) );
2611          }
2612          else
2613          {
2614             SCIP_CALL( SCIPnodeAddCons(tree->path[validdepth], blkmem, set, stat, tree, cons) );
2615          }
2616 
2617          SCIP_CALL( SCIPconsRelease(&cons, blkmem, set) );
2618       }
2619       else
2620       {
2621          assert(applyglobal);
2622 
2623          SCIPsetDebugMsg(set, "change global %s bound of <%s>[%c]: %g -> %g\n",
2624                (boundtype == SCIP_BOUNDTYPE_LOWER ? "lower" : "upper"),
2625                SCIPvarGetName(var), varGetChar(var),
2626                (boundtype == SCIP_BOUNDTYPE_LOWER ? SCIPvarGetLbGlobal(var) : SCIPvarGetUbGlobal(var)),
2627                newbound);
2628 
2629          SCIP_CALL( SCIPnodeAddBoundchg(tree->path[0], blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, \
2630                eventqueue, cliquetable, var, newbound, boundtype, FALSE) );
2631 
2632          /* mark the node in the validdepth to be propagated again */
2633          SCIPnodePropagateAgain(tree->path[0], set, stat, tree);
2634       }
2635    }
2636 
2637    if( applyglobal )
2638       ++conflict->nglbchgbds;
2639    else
2640       ++conflict->nlocchgbds;
2641 
2642    if( prooftype == SCIP_CONFTYPE_INFEASLP || prooftype == SCIP_CONFTYPE_ALTINFPROOF )
2643    {
2644       ++conflict->dualproofsinfnnonzeros; /* we count a global bound reduction as size 1 */
2645       ++conflict->ndualproofsinfsuccess;
2646       ++conflict->ninflpsuccess;
2647 
2648       if( applyglobal )
2649          ++conflict->ndualproofsinfglobal;
2650       else
2651          ++conflict->ndualproofsinflocal;
2652    }
2653    else
2654    {
2655       ++conflict->dualproofsbndnnonzeros; /* we count a global bound reduction as size 1 */
2656       ++conflict->ndualproofsbndsuccess;
2657       ++conflict->nboundlpsuccess;
2658 
2659       if( applyglobal )
2660          ++conflict->ndualproofsbndglobal;
2661       else
2662          ++conflict->ndualproofsbndlocal;
2663    }
2664 
2665    return SCIP_OKAY;
2666 }
2667 
2668 /** calculates the minimal activity of a given aggregation row */
2669 static
aggrRowGetMinActivity(SCIP_SET * set,SCIP_PROB * transprob,SCIP_AGGRROW * aggrrow,SCIP_Real * curvarlbs,SCIP_Real * curvarubs,SCIP_Bool * infdelta)2670 SCIP_Real aggrRowGetMinActivity(
2671    SCIP_SET*             set,                /**< global SCIP settings */
2672    SCIP_PROB*            transprob,          /**< transformed problem data */
2673    SCIP_AGGRROW*         aggrrow,            /**< aggregation row */
2674    SCIP_Real*            curvarlbs,          /**< current lower bounds of active problem variables (or NULL for global bounds) */
2675    SCIP_Real*            curvarubs,          /**< current upper bounds of active problem variables (or NULL for global bounds) */
2676    SCIP_Bool*            infdelta            /**< pointer to store whether at least one variable contributes with an infinite value */
2677    )
2678 {
2679    SCIP_VAR** vars;
2680    SCIP_Real QUAD(minact);
2681    int* inds;
2682    int nnz;
2683    int i;
2684 
2685    vars = SCIPprobGetVars(transprob);
2686    assert(vars != NULL);
2687 
2688    nnz = SCIPaggrRowGetNNz(aggrrow);
2689    inds = SCIPaggrRowGetInds(aggrrow);
2690 
2691    QUAD_ASSIGN(minact, 0.0);
2692 
2693    if( infdelta != NULL )
2694       *infdelta = FALSE;
2695 
2696    for( i = 0; i < nnz; i++ )
2697    {
2698       SCIP_Real val;
2699       SCIP_Real QUAD(delta);
2700       int v = inds[i];
2701 
2702       assert(SCIPvarGetProbindex(vars[v]) == v);
2703 
2704       val = SCIPaggrRowGetProbvarValue(aggrrow, v);
2705 
2706       if( val > 0.0 )
2707       {
2708          SCIP_Real bnd = (curvarlbs == NULL ? SCIPvarGetLbGlobal(vars[v]) : curvarlbs[v]);
2709          SCIPquadprecProdDD(delta, val, bnd);
2710       }
2711       else
2712       {
2713          SCIP_Real bnd = (curvarubs == NULL ? SCIPvarGetUbGlobal(vars[v]) : curvarubs[v]);
2714          SCIPquadprecProdDD(delta, val, bnd);
2715       }
2716 
2717       /* update minimal activity */
2718       SCIPquadprecSumQQ(minact, minact, delta);
2719 
2720       if( infdelta != NULL && SCIPsetIsInfinity(set, REALABS(QUAD_TO_DBL(delta))) )
2721       {
2722          *infdelta = TRUE;
2723          goto TERMINATE;
2724       }
2725    }
2726 
2727   TERMINATE:
2728    /* check whether the minimal activity is infinite */
2729    if( SCIPsetIsInfinity(set, QUAD_TO_DBL(minact)) )
2730       return SCIPsetInfinity(set);
2731    if( SCIPsetIsInfinity(set, -QUAD_TO_DBL(minact)) )
2732       return -SCIPsetInfinity(set);
2733 
2734    return QUAD_TO_DBL(minact);
2735 }
2736 
2737 /** calculates the minimal activity of a given set of bounds and coefficients */
2738 static
getMinActivity(SCIP_SET * set,SCIP_PROB * transprob,SCIP_Real * coefs,int * inds,int nnz,SCIP_Real * curvarlbs,SCIP_Real * curvarubs)2739 SCIP_Real getMinActivity(
2740    SCIP_SET*             set,                /**< global SCIP settings */
2741    SCIP_PROB*            transprob,          /**< transformed problem data */
2742    SCIP_Real*            coefs,              /**< coefficients in sparse representation */
2743    int*                  inds,               /**< non-zero indices */
2744    int                   nnz,                /**< number of non-zero indices */
2745    SCIP_Real*            curvarlbs,          /**< current lower bounds of active problem variables (or NULL for global bounds) */
2746    SCIP_Real*            curvarubs           /**< current upper bounds of active problem variables (or NULL for global bounds) */
2747    )
2748 {
2749    SCIP_VAR** vars;
2750    SCIP_Real QUAD(minact);
2751    int i;
2752 
2753    assert(coefs != NULL);
2754    assert(inds != NULL);
2755 
2756    vars = SCIPprobGetVars(transprob);
2757    assert(vars != NULL);
2758 
2759    QUAD_ASSIGN(minact, 0.0);
2760 
2761    for( i = 0; i < nnz; i++ )
2762    {
2763       SCIP_Real val;
2764       SCIP_Real QUAD(delta);
2765       int v = inds[i];
2766 
2767       assert(SCIPvarGetProbindex(vars[v]) == v);
2768 
2769       val = coefs[i];
2770 
2771       if( val > 0.0 )
2772       {
2773          SCIP_Real bnd;
2774 
2775          assert(curvarlbs == NULL || !SCIPsetIsInfinity(set, -curvarlbs[v]));
2776 
2777          bnd = (curvarlbs == NULL ? SCIPvarGetLbGlobal(vars[v]) : curvarlbs[v]);
2778          SCIPquadprecProdDD(delta, val, bnd);
2779       }
2780       else
2781       {
2782          SCIP_Real bnd;
2783 
2784          assert(curvarubs == NULL || !SCIPsetIsInfinity(set, curvarubs[v]));
2785 
2786          bnd = (curvarubs == NULL ? SCIPvarGetUbGlobal(vars[v]) : curvarubs[v]);
2787          SCIPquadprecProdDD(delta, val, bnd);
2788       }
2789 
2790       /* update minimal activity */
2791       SCIPquadprecSumQQ(minact, minact, delta);
2792    }
2793 
2794    /* check whether the minmal activity is infinite */
2795    if( SCIPsetIsInfinity(set, QUAD_TO_DBL(minact)) )
2796       return SCIPsetInfinity(set);
2797    if( SCIPsetIsInfinity(set, -QUAD_TO_DBL(minact)) )
2798       return -SCIPsetInfinity(set);
2799 
2800    return QUAD_TO_DBL(minact);
2801 }
2802 
2803 /** calculates the minimal activity of a given set of bounds and coefficients */
2804 static
getMaxActivity(SCIP_SET * set,SCIP_PROB * transprob,SCIP_Real * coefs,int * inds,int nnz,SCIP_Real * curvarlbs,SCIP_Real * curvarubs)2805 SCIP_Real getMaxActivity(
2806    SCIP_SET*             set,                /**< global SCIP settings */
2807    SCIP_PROB*            transprob,          /**< transformed problem data */
2808    SCIP_Real*            coefs,              /**< coefficients in sparse representation */
2809    int*                  inds,               /**< non-zero indices */
2810    int                   nnz,                /**< number of non-zero indices */
2811    SCIP_Real*            curvarlbs,          /**< current lower bounds of active problem variables (or NULL for global bounds) */
2812    SCIP_Real*            curvarubs           /**< current upper bounds of active problem variables (or NULL for global bounds) */
2813    )
2814 {
2815    SCIP_VAR** vars;
2816    SCIP_Real QUAD(maxact);
2817    int i;
2818 
2819    assert(coefs != NULL);
2820    assert(inds != NULL);
2821 
2822    vars = SCIPprobGetVars(transprob);
2823    assert(vars != NULL);
2824 
2825    QUAD_ASSIGN(maxact, 0.0);
2826 
2827    for( i = 0; i < nnz; i++ )
2828    {
2829       SCIP_Real val;
2830       SCIP_Real QUAD(delta);
2831       int v = inds[i];
2832 
2833       assert(SCIPvarGetProbindex(vars[v]) == v);
2834 
2835       val = coefs[i];
2836 
2837       if( val < 0.0 )
2838       {
2839          SCIP_Real bnd;
2840 
2841          assert(curvarlbs == NULL || !SCIPsetIsInfinity(set, -curvarlbs[v]));
2842 
2843          bnd = (curvarlbs == NULL ? SCIPvarGetLbGlobal(vars[v]) : curvarlbs[v]);
2844          SCIPquadprecProdDD(delta, val, bnd);
2845       }
2846       else
2847       {
2848          SCIP_Real bnd;
2849 
2850          assert(curvarubs == NULL || !SCIPsetIsInfinity(set, curvarubs[v]));
2851 
2852          bnd = (curvarubs == NULL ? SCIPvarGetUbGlobal(vars[v]) : curvarubs[v]);
2853          SCIPquadprecProdDD(delta, val, bnd);
2854       }
2855 
2856       /* update maximal activity */
2857       SCIPquadprecSumQQ(maxact, maxact, delta);
2858    }
2859 
2860    /* check whether the maximal activity got infinite */
2861    if( SCIPsetIsInfinity(set, QUAD_TO_DBL(maxact)) )
2862       return SCIPsetInfinity(set);
2863    if( SCIPsetIsInfinity(set, -QUAD_TO_DBL(maxact)) )
2864       return -SCIPsetInfinity(set);
2865 
2866    return QUAD_TO_DBL(maxact);
2867 }
2868 
2869 static
propagateLongProof(SCIP_CONFLICT * conflict,SCIP_SET * set,SCIP_STAT * stat,SCIP_REOPT * reopt,SCIP_TREE * tree,BMS_BLKMEM * blkmem,SCIP_PROB * origprob,SCIP_PROB * transprob,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_EVENTQUEUE * eventqueue,SCIP_CLIQUETABLE * cliquetable,SCIP_Real * coefs,int * inds,int nnz,SCIP_Real rhs,SCIP_CONFTYPE conflicttype,int validdepth)2870 SCIP_RETCODE propagateLongProof(
2871    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
2872    SCIP_SET*             set,                /**< global SCIP settings */
2873    SCIP_STAT*            stat,               /**< dynamic SCIP statistics */
2874    SCIP_REOPT*           reopt,              /**< reoptimization data */
2875    SCIP_TREE*            tree,               /**< tree data */
2876    BMS_BLKMEM*           blkmem,             /**< block memory */
2877    SCIP_PROB*            origprob,           /**< original problem */
2878    SCIP_PROB*            transprob,          /**< transformed problem */
2879    SCIP_LP*              lp,                 /**< LP data */
2880    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
2881    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
2882    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
2883    SCIP_Real*            coefs,              /**< coefficients in sparse representation */
2884    int*                  inds,               /**< non-zero indices */
2885    int                   nnz,                /**< number of non-zero indices */
2886    SCIP_Real             rhs,                /**< right-hand side */
2887    SCIP_CONFTYPE         conflicttype,       /**< type of the conflict */
2888    int                   validdepth          /**< depth where the proof is valid */
2889    )
2890 {
2891    SCIP_VAR** vars;
2892    SCIP_Real minact;
2893    int i;
2894 
2895    assert(coefs != NULL);
2896    assert(inds != NULL);
2897    assert(nnz >= 0);
2898 
2899    vars = SCIPprobGetVars(transprob);
2900    minact = getMinActivity(set, transprob, coefs, inds, nnz, NULL, NULL);
2901 
2902    /* we cannot find global tightenings */
2903    if( SCIPsetIsInfinity(set, -minact) )
2904       return SCIP_OKAY;
2905 
2906    for( i = 0; i < nnz; i++ )
2907    {
2908       SCIP_VAR* var;
2909       SCIP_Real val;
2910       SCIP_Real resminact;
2911       SCIP_Real lb;
2912       SCIP_Real ub;
2913       int pos;
2914 
2915       pos = inds[i];
2916       val = coefs[i];
2917       var = vars[pos];
2918       lb = SCIPvarGetLbGlobal(var);
2919       ub = SCIPvarGetUbGlobal(var);
2920 
2921       assert(!SCIPsetIsZero(set, val));
2922 
2923       resminact = minact;
2924 
2925       /* we got a potential new upper bound */
2926       if( val > 0.0 )
2927       {
2928          SCIP_Real newub;
2929 
2930          resminact -= (val * lb);
2931          newub = (rhs - resminact)/val;
2932 
2933          if( SCIPsetIsInfinity(set, newub) )
2934             continue;
2935 
2936          /* we cannot tighten the upper bound */
2937          if( SCIPsetIsGE(set, newub, ub) )
2938             continue;
2939 
2940          SCIP_CALL( tightenSingleVar(conflict, set, stat, tree, blkmem, origprob, transprob, reopt, lp, branchcand, \
2941                eventqueue, cliquetable, var, val, rhs-resminact, conflicttype, validdepth) );
2942       }
2943       /* we got a potential new lower bound */
2944       else
2945       {
2946          SCIP_Real newlb;
2947 
2948          resminact -= (val * ub);
2949          newlb = (rhs - resminact)/val;
2950 
2951          if( SCIPsetIsInfinity(set, -newlb) )
2952             continue;
2953 
2954          /* we cannot tighten the lower bound */
2955          if( SCIPsetIsLE(set, newlb, lb) )
2956             continue;
2957 
2958          SCIP_CALL( tightenSingleVar(conflict, set, stat, tree, blkmem, origprob, transprob, reopt, lp, branchcand, \
2959                eventqueue, cliquetable, var, val, rhs-resminact, conflicttype, validdepth) );
2960       }
2961 
2962       /* the minimal activity should stay unchanged because we tightened the bound that doesn't contribute to the
2963        * minimal activity
2964        */
2965       assert(SCIPsetIsEQ(set, minact, getMinActivity(set, transprob, coefs, inds, nnz, NULL, NULL)));
2966    }
2967 
2968    return SCIP_OKAY;
2969 }
2970 
2971 
2972 /** creates a proof constraint and tries to add it to the storage */
2973 static
createAndAddProofcons(SCIP_CONFLICT * conflict,SCIP_CONFLICTSTORE * conflictstore,SCIP_PROOFSET * proofset,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * origprob,SCIP_PROB * transprob,SCIP_TREE * tree,SCIP_REOPT * reopt,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_EVENTQUEUE * eventqueue,SCIP_CLIQUETABLE * cliquetable,BMS_BLKMEM * blkmem)2974 SCIP_RETCODE createAndAddProofcons(
2975    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
2976    SCIP_CONFLICTSTORE*   conflictstore,      /**< conflict pool data */
2977    SCIP_PROOFSET*        proofset,           /**< proof set */
2978    SCIP_SET*             set,                /**< global SCIP settings */
2979    SCIP_STAT*            stat,               /**< dynamic SCIP statistics */
2980    SCIP_PROB*            origprob,           /**< original problem */
2981    SCIP_PROB*            transprob,          /**< transformed problem */
2982    SCIP_TREE*            tree,               /**< tree data */
2983    SCIP_REOPT*           reopt,              /**< reoptimization data */
2984    SCIP_LP*              lp,                 /**< LP data */
2985    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
2986    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
2987    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
2988    BMS_BLKMEM*           blkmem              /**< block memory */
2989    )
2990 {
2991    SCIP_CONS* cons;
2992    SCIP_CONS* upgdcons;
2993    SCIP_VAR** vars;
2994    SCIP_Real* coefs;
2995    int* inds;
2996    SCIP_Real rhs;
2997    SCIP_Real fillin;
2998    SCIP_Real globalminactivity;
2999    SCIP_Bool applyglobal;
3000    SCIP_Bool toolong;
3001    SCIP_Bool contonly;
3002    SCIP_Bool hasrelaxvar;
3003    SCIP_CONFTYPE conflicttype;
3004    char name[SCIP_MAXSTRLEN];
3005    int nnz;
3006    int i;
3007 
3008    assert(conflict != NULL);
3009    assert(conflictstore != NULL);
3010    assert(proofset != NULL);
3011    assert(proofset->validdepth == 0 || proofset->validdepth < SCIPtreeGetFocusDepth(tree));
3012 
3013    nnz = proofsetGetNVars(proofset);
3014 
3015    if( nnz == 0 )
3016       return SCIP_OKAY;
3017 
3018    vars = SCIPprobGetVars(transprob);
3019 
3020    rhs = proofsetGetRhs(proofset);
3021    assert(!SCIPsetIsInfinity(set, rhs));
3022 
3023    coefs = proofsetGetVals(proofset);
3024    assert(coefs != NULL);
3025 
3026    inds = proofsetGetInds(proofset);
3027    assert(inds != NULL);
3028 
3029    conflicttype = proofsetGetConftype(proofset);
3030 
3031    applyglobal = (proofset->validdepth <= SCIPtreeGetEffectiveRootDepth(tree));
3032 
3033    if( applyglobal )
3034    {
3035       SCIP_Real globalmaxactivity = getMaxActivity(set, transprob, coefs, inds, nnz, NULL, NULL);
3036 
3037       /* check whether the alternative proof is redundant */
3038       if( SCIPsetIsLE(set, globalmaxactivity, rhs) )
3039          return SCIP_OKAY;
3040 
3041       /* check whether the constraint proves global infeasibility */
3042       globalminactivity = getMinActivity(set, transprob, coefs, inds, nnz, NULL, NULL);
3043       if( SCIPsetIsGT(set, globalminactivity, rhs) )
3044       {
3045          SCIPsetDebugMsg(set, "detect global infeasibility: minactivity=%g, rhs=%g\n", globalminactivity, rhs);
3046 
3047          SCIP_CALL( SCIPnodeCutoff(tree->path[proofset->validdepth], set, stat, tree, transprob, origprob, reopt, lp, blkmem) );
3048 
3049          goto UPDATESTATISTICS;
3050       }
3051    }
3052 
3053    if( set->conf_minmaxvars >= nnz  )
3054       toolong = FALSE;
3055    else
3056    {
3057       SCIP_Real maxnnz;
3058 
3059       if( transprob->startnconss < 100 )
3060          maxnnz = 0.85 * transprob->nvars;
3061       else
3062          maxnnz = (SCIP_Real)transprob->nvars;
3063 
3064       fillin = nnz;
3065       if( conflicttype == SCIP_CONFTYPE_INFEASLP || conflicttype == SCIP_CONFTYPE_ALTINFPROOF )
3066       {
3067          fillin += SCIPconflictstoreGetNDualInfProofs(conflictstore) * SCIPconflictstoreGetAvgNnzDualInfProofs(conflictstore);
3068          fillin /= (SCIPconflictstoreGetNDualInfProofs(conflictstore) + 1.0);
3069          toolong = (fillin > MIN(2.0 * stat->avgnnz, maxnnz));
3070       }
3071       else
3072       {
3073          assert(conflicttype == SCIP_CONFTYPE_BNDEXCEEDING || conflicttype == SCIP_CONFTYPE_ALTBNDPROOF);
3074 
3075          fillin += SCIPconflictstoreGetNDualBndProofs(conflictstore) * SCIPconflictstoreGetAvgNnzDualBndProofs(conflictstore);
3076          fillin /= (SCIPconflictstoreGetNDualBndProofs(conflictstore) + 1.0);
3077          toolong = (fillin > MIN(1.5 * stat->avgnnz, maxnnz));
3078       }
3079 
3080       toolong = (toolong && (nnz > set->conf_maxvarsfac * transprob->nvars));
3081    }
3082 
3083    /* don't store global dual proofs that are too long / have too many non-zeros */
3084    if( toolong )
3085    {
3086       if( applyglobal )
3087       {
3088          SCIP_CALL( propagateLongProof(conflict, set, stat, reopt, tree, blkmem, origprob, transprob, lp, branchcand,
3089                eventqueue, cliquetable, coefs, inds, nnz, rhs, conflicttype, proofset->validdepth) );
3090       }
3091       return SCIP_OKAY;
3092    }
3093 
3094    /* check if conflict contains variables that are invalid after a restart to label it appropriately */
3095    hasrelaxvar = FALSE;
3096    contonly = TRUE;
3097    for( i = 0; i < nnz && (!hasrelaxvar || contonly); ++i )
3098    {
3099       hasrelaxvar |= SCIPvarIsRelaxationOnly(vars[inds[i]]);
3100 
3101       if( SCIPvarIsIntegral(vars[inds[i]]) )
3102          contonly = FALSE;
3103    }
3104 
3105    if( !applyglobal && contonly )
3106       return SCIP_OKAY;
3107 
3108    if( conflicttype == SCIP_CONFTYPE_INFEASLP || conflicttype == SCIP_CONFTYPE_ALTINFPROOF )
3109       (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "dualproof_inf_%" SCIP_LONGINT_FORMAT, conflict->ndualproofsinfsuccess);
3110    else if( conflicttype == SCIP_CONFTYPE_BNDEXCEEDING || conflicttype == SCIP_CONFTYPE_ALTBNDPROOF )
3111       (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "dualproof_bnd_%" SCIP_LONGINT_FORMAT, conflict->ndualproofsbndsuccess);
3112    else
3113       return SCIP_INVALIDCALL;
3114 
3115    SCIP_CALL( SCIPcreateConsLinear(set->scip, &cons, name, 0, NULL, NULL, -SCIPsetInfinity(set), rhs,
3116          FALSE, FALSE, FALSE, FALSE, TRUE, !applyglobal,
3117          FALSE, TRUE, TRUE, FALSE) );
3118 
3119    for( i = 0; i < nnz; i++ )
3120    {
3121       int v = inds[i];
3122       SCIP_CALL( SCIPaddCoefLinear(set->scip, cons, vars[v], coefs[i]) );
3123    }
3124 
3125    /* do not upgrade linear constraints of size 1 */
3126    if( nnz > 1 )
3127    {
3128       upgdcons = NULL;
3129       /* try to automatically convert a linear constraint into a more specific and more specialized constraint */
3130       SCIP_CALL( SCIPupgradeConsLinear(set->scip, cons, &upgdcons) );
3131       if( upgdcons != NULL )
3132       {
3133          SCIP_CALL( SCIPreleaseCons(set->scip, &cons) );
3134          cons = upgdcons;
3135 
3136          if( conflicttype == SCIP_CONFTYPE_INFEASLP )
3137             conflicttype = SCIP_CONFTYPE_ALTINFPROOF;
3138          else if( conflicttype == SCIP_CONFTYPE_BNDEXCEEDING )
3139             conflicttype = SCIP_CONFTYPE_ALTBNDPROOF;
3140       }
3141    }
3142 
3143    /* mark constraint to be a conflict */
3144    SCIPconsMarkConflict(cons);
3145 
3146    /* add constraint to storage */
3147    if( conflicttype == SCIP_CONFTYPE_INFEASLP || conflicttype == SCIP_CONFTYPE_ALTINFPROOF )
3148    {
3149       /* add dual proof to storage */
3150       SCIP_CALL( SCIPconflictstoreAddDualraycons(conflictstore, cons, blkmem, set, stat, transprob, reopt, hasrelaxvar) );
3151    }
3152    else
3153    {
3154       SCIP_Real scale = 1.0;
3155       SCIP_Bool updateside = FALSE;
3156 
3157       /* In some cases the constraint could not be updated to a more special type. However, it is possible that
3158        * constraint got scaled. Therefore, we need to be very careful when updating the lhs/rhs after the incumbent
3159        * solution has improved.
3160        */
3161       if( conflicttype == SCIP_CONFTYPE_BNDEXCEEDING )
3162       {
3163          SCIP_Real side;
3164 
3165 #ifndef NDEBUG
3166          SCIP_CONSHDLR* conshdlr = SCIPconsGetHdlr(cons);
3167 
3168          assert(conshdlr != NULL);
3169          assert(strcmp(SCIPconshdlrGetName(conshdlr), "linear") == 0);
3170 #endif
3171          side = SCIPgetLhsLinear(set->scip, cons);
3172 
3173          if( !SCIPsetIsInfinity(set, -side) )
3174          {
3175             if( SCIPsetIsZero(set, side) )
3176             {
3177                scale = -1.0;
3178             }
3179             else
3180             {
3181                scale = proofsetGetRhs(proofset) / side;
3182                assert(SCIPsetIsNegative(set, scale));
3183             }
3184          }
3185          else
3186          {
3187             side = SCIPgetRhsLinear(set->scip, cons);
3188             assert(!SCIPsetIsInfinity(set, side));
3189 
3190             if( SCIPsetIsZero(set, side) )
3191             {
3192                scale = 1.0;
3193             }
3194             else
3195             {
3196                scale = proofsetGetRhs(proofset) / side;
3197                assert(SCIPsetIsPositive(set, scale));
3198             }
3199          }
3200          updateside = TRUE;
3201       }
3202 
3203       /* add dual proof to storage */
3204       SCIP_CALL( SCIPconflictstoreAddDualsolcons(conflictstore, cons, blkmem, set, stat, transprob, reopt, scale, updateside, hasrelaxvar) );
3205    }
3206 
3207    if( applyglobal ) /*lint !e774*/
3208    {
3209       /* add the constraint to the global problem */
3210       SCIP_CALL( SCIPprobAddCons(transprob, set, stat, cons) );
3211    }
3212    else
3213    {
3214       SCIP_CALL( SCIPnodeAddCons(tree->path[proofset->validdepth], blkmem, set, stat, tree, cons) );
3215    }
3216 
3217    SCIPsetDebugMsg(set, "added proof-constraint to node %p (#%lld) in depth %d (nproofconss %d)\n",
3218          (void*)tree->path[proofset->validdepth], SCIPnodeGetNumber(tree->path[proofset->validdepth]),
3219          proofset->validdepth,
3220          (conflicttype == SCIP_CONFTYPE_INFEASLP || conflicttype == SCIP_CONFTYPE_ALTINFPROOF)
3221             ? SCIPconflictstoreGetNDualInfProofs(conflictstore) : SCIPconflictstoreGetNDualBndProofs(conflictstore));
3222 
3223    /* release the constraint */
3224    SCIP_CALL( SCIPreleaseCons(set->scip, &cons) );
3225 
3226   UPDATESTATISTICS:
3227    /* update statistics */
3228    if( conflicttype == SCIP_CONFTYPE_INFEASLP || conflicttype == SCIP_CONFTYPE_ALTINFPROOF )
3229    {
3230       conflict->dualproofsinfnnonzeros += nnz;
3231       if( applyglobal ) /*lint !e774*/
3232          ++conflict->ndualproofsinfglobal;
3233       else
3234          ++conflict->ndualproofsinflocal;
3235       ++conflict->ndualproofsinfsuccess;
3236    }
3237    else
3238    {
3239       assert(conflicttype == SCIP_CONFTYPE_BNDEXCEEDING || conflicttype == SCIP_CONFTYPE_ALTBNDPROOF);
3240       conflict->dualproofsbndnnonzeros += nnz;
3241       if( applyglobal ) /*lint !e774*/
3242          ++conflict->ndualproofsbndglobal;
3243       else
3244          ++conflict->ndualproofsbndlocal;
3245 
3246       ++conflict->ndualproofsbndsuccess;
3247    }
3248    return SCIP_OKAY;
3249 }
3250 
3251 /* create proof constraints out of proof sets */
3252 static
conflictFlushProofset(SCIP_CONFLICT * conflict,SCIP_CONFLICTSTORE * conflictstore,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * transprob,SCIP_PROB * origprob,SCIP_TREE * tree,SCIP_REOPT * reopt,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_EVENTQUEUE * eventqueue,SCIP_CLIQUETABLE * cliquetable)3253 SCIP_RETCODE conflictFlushProofset(
3254    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
3255    SCIP_CONFLICTSTORE*   conflictstore,      /**< conflict store */
3256    BMS_BLKMEM*           blkmem,             /**< block memory */
3257    SCIP_SET*             set,                /**< global SCIP settings */
3258    SCIP_STAT*            stat,               /**< dynamic problem statistics */
3259    SCIP_PROB*            transprob,          /**< transformed problem after presolve */
3260    SCIP_PROB*            origprob,           /**< original problem */
3261    SCIP_TREE*            tree,               /**< branch and bound tree */
3262    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
3263    SCIP_LP*              lp,                 /**< current LP data */
3264    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
3265    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
3266    SCIP_CLIQUETABLE*     cliquetable         /**< clique table data structure */
3267    )
3268 {
3269    assert(conflict != NULL);
3270 
3271    if( proofsetGetConftype(conflict->proofset) != SCIP_CONFTYPE_UNKNOWN )
3272    {
3273       /* only one variable has a coefficient different to zero, we add this bound change instead of a constraint */
3274       if( proofsetGetNVars(conflict->proofset) == 1 )
3275       {
3276          SCIP_VAR** vars;
3277          SCIP_Real* coefs;
3278          int* inds;
3279          SCIP_Real rhs;
3280 
3281          vars = SCIPprobGetVars(transprob);
3282 
3283          coefs = proofsetGetVals(conflict->proofset);
3284          inds = proofsetGetInds(conflict->proofset);
3285          rhs = proofsetGetRhs(conflict->proofset);
3286 
3287          SCIP_CALL( tightenSingleVar(conflict, set, stat, tree, blkmem, origprob, transprob, reopt, lp, \
3288                branchcand, eventqueue, cliquetable, vars[inds[0]], coefs[0], rhs, conflict->proofset->conflicttype,
3289                conflict->proofset->validdepth) );
3290       }
3291       else
3292       {
3293          SCIP_Bool skipinitialproof = FALSE;
3294 
3295          /* prefer an infeasibility proof
3296           *
3297           * todo: check whether this is really what we want
3298           */
3299          if( set->conf_prefinfproof && proofsetGetConftype(conflict->proofset) == SCIP_CONFTYPE_BNDEXCEEDING )
3300          {
3301             int i;
3302 
3303             for( i = 0; i < conflict->nproofsets; i++ )
3304             {
3305                if( proofsetGetConftype(conflict->proofsets[i]) == SCIP_CONFTYPE_INFEASLP )
3306                {
3307                   skipinitialproof = TRUE;
3308                   break;
3309                }
3310             }
3311          }
3312 
3313          if( !skipinitialproof )
3314          {
3315             /* create and add the original proof */
3316             SCIP_CALL( createAndAddProofcons(conflict, conflictstore, conflict->proofset, set, stat, origprob, transprob, \
3317                   tree, reopt, lp, branchcand, eventqueue, cliquetable, blkmem) );
3318          }
3319       }
3320 
3321       /* clear the proof set anyway */
3322       proofsetClear(conflict->proofset);
3323    }
3324 
3325    if( conflict->nproofsets > 0 )
3326    {
3327       int i;
3328 
3329       for( i = 0; i < conflict->nproofsets; i++ )
3330       {
3331          assert(conflict->proofsets[i] != NULL);
3332          assert(proofsetGetConftype(conflict->proofsets[i]) != SCIP_CONFTYPE_UNKNOWN);
3333 
3334          /* only one variable has a coefficient different to zero, we add this bound change instead of a constraint */
3335          if( proofsetGetNVars(conflict->proofsets[i]) == 1 )
3336          {
3337             SCIP_VAR** vars;
3338             SCIP_Real* coefs;
3339             int* inds;
3340             SCIP_Real rhs;
3341 
3342             vars = SCIPprobGetVars(transprob);
3343 
3344             coefs = proofsetGetVals(conflict->proofsets[i]);
3345             inds = proofsetGetInds(conflict->proofsets[i]);
3346             rhs = proofsetGetRhs(conflict->proofsets[i]);
3347 
3348             SCIP_CALL( tightenSingleVar(conflict, set, stat, tree, blkmem, origprob, transprob, reopt, lp,
3349                   branchcand, eventqueue, cliquetable, vars[inds[0]], coefs[0], rhs,
3350                   conflict->proofsets[i]->conflicttype, conflict->proofsets[i]->validdepth) );
3351          }
3352          else
3353          {
3354             /* create and add proof constraint */
3355             SCIP_CALL( createAndAddProofcons(conflict, conflictstore, conflict->proofsets[i], set, stat, origprob, \
3356                   transprob, tree, reopt, lp, branchcand, eventqueue, cliquetable, blkmem) );
3357          }
3358       }
3359 
3360       /* free all proofsets */
3361       for( i = 0; i < conflict->nproofsets; i++ )
3362          proofsetFree(&conflict->proofsets[i], blkmem);
3363 
3364       conflict->nproofsets = 0;
3365    }
3366 
3367    return SCIP_OKAY;
3368 }
3369 
3370 /** adds the given conflict set as conflict constraint to the problem */
3371 static
conflictAddConflictCons(SCIP_CONFLICT * conflict,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * transprob,SCIP_PROB * origprob,SCIP_TREE * tree,SCIP_REOPT * reopt,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_EVENTQUEUE * eventqueue,SCIP_CLIQUETABLE * cliquetable,SCIP_CONFLICTSET * conflictset,int insertdepth,SCIP_Bool * success)3372 SCIP_RETCODE conflictAddConflictCons(
3373    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
3374    BMS_BLKMEM*           blkmem,             /**< block memory */
3375    SCIP_SET*             set,                /**< global SCIP settings */
3376    SCIP_STAT*            stat,               /**< dynamic problem statistics */
3377    SCIP_PROB*            transprob,          /**< transformed problem after presolve */
3378    SCIP_PROB*            origprob,           /**< original problem */
3379    SCIP_TREE*            tree,               /**< branch and bound tree */
3380    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
3381    SCIP_LP*              lp,                 /**< current LP data */
3382    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
3383    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
3384    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
3385    SCIP_CONFLICTSET*     conflictset,        /**< conflict set to add to the tree */
3386    int                   insertdepth,        /**< depth level at which the conflict set should be added */
3387    SCIP_Bool*            success             /**< pointer to store whether the addition was successful */
3388    )
3389 {
3390    SCIP_Bool redundant;
3391    int h;
3392 
3393    assert(conflict != NULL);
3394    assert(tree != NULL);
3395    assert(tree->path != NULL);
3396    assert(conflictset != NULL);
3397    assert(conflictset->validdepth <= insertdepth);
3398    assert(success != NULL);
3399 
3400    *success = FALSE;
3401    redundant = FALSE;
3402 
3403    /* try to derive global bound changes and shorten the conflictset by using implication and clique and variable bound
3404     * information
3405     */
3406    if( conflictset->nbdchginfos > 1 && insertdepth == 0 && !lp->strongbranching )
3407    {
3408       int nbdchgs;
3409       int nredvars;
3410 #ifdef SCIP_DEBUG
3411       int oldnbdchginfos = conflictset->nbdchginfos;
3412 #endif
3413       assert(conflictset->validdepth == 0);
3414 
3415       /* check conflict set on debugging solution */
3416       SCIP_CALL( SCIPdebugCheckConflict(blkmem, set, tree->root, conflictset->bdchginfos, conflictset->relaxedbds, conflictset->nbdchginfos) );
3417 
3418       SCIPclockStart(conflict->dIBclock, set);
3419 
3420       /* find global bound changes which can be derived from the new conflict set */
3421       SCIP_CALL( detectImpliedBounds(set, transprob, conflictset, &nbdchgs, &nredvars, &redundant) );
3422 
3423       /* all variables where removed, we have an infeasibility proof */
3424       if( conflictset->nbdchginfos == 0 )
3425          return SCIP_OKAY;
3426 
3427       /* debug check for reduced conflict set */
3428       if( nredvars > 0 )
3429       {
3430          /* check conflict set on debugging solution */
3431          SCIP_CALL( SCIPdebugCheckConflict(blkmem, set, tree->root, conflictset->bdchginfos, conflictset->relaxedbds, conflictset->nbdchginfos) ); /*lint !e506 !e774*/
3432       }
3433 
3434 #ifdef SCIP_DEBUG
3435       SCIPsetDebugMsg(set, " -> conflict set removed %d redundant variables (old nvars %d, new nvars = %d)\n", nredvars, oldnbdchginfos, conflictset->nbdchginfos);
3436       SCIPsetDebugMsg(set, " -> conflict set led to %d global bound changes %s(cdpt:%d, fdpt:%d, confdpt:%d, len:%d):\n",
3437          nbdchgs, redundant ? "(conflict became redundant) " : "", SCIPtreeGetCurrentDepth(tree), SCIPtreeGetFocusDepth(tree),
3438          conflictset->conflictdepth, conflictset->nbdchginfos);
3439       conflictsetPrint(conflictset);
3440 #endif
3441 
3442       SCIPclockStop(conflict->dIBclock, set);
3443 
3444       if( redundant )
3445       {
3446          if( nbdchgs > 0 )
3447             *success = TRUE;
3448 
3449          return SCIP_OKAY;
3450       }
3451    }
3452 
3453    /* in case the conflict set contains only one bound change which is globally valid we apply that bound change
3454     * directly (except if we are in strong branching or diving - in this case a bound change would yield an unflushed LP
3455     * and is not handled when restoring the information)
3456     *
3457     * @note A bound change can only be applied if it is are related to the active node or if is a global bound
3458     *       change. Bound changes which are related to any other node cannot be handled at point due to the internal
3459     *       data structure
3460     */
3461    if( conflictset->nbdchginfos == 1 && insertdepth == 0 && !lp->strongbranching && !lp->diving )
3462    {
3463       SCIP_VAR* var;
3464       SCIP_Real bound;
3465       SCIP_BOUNDTYPE boundtype;
3466 
3467       var = conflictset->bdchginfos[0]->var;
3468       assert(var != NULL);
3469 
3470       boundtype = SCIPboundtypeOpposite((SCIP_BOUNDTYPE) conflictset->bdchginfos[0]->boundtype);
3471       bound = conflictset->relaxedbds[0];
3472 
3473       /* for continuous variables, we can only use the relaxed version of the bounds negation: !(x <= u) -> x >= u */
3474       if( SCIPvarIsIntegral(var) )
3475       {
3476          assert(SCIPsetIsIntegral(set, bound));
3477          bound += (boundtype == SCIP_BOUNDTYPE_LOWER ? +1.0 : -1.0);
3478       }
3479 
3480       SCIPsetDebugMsg(set, " -> apply global bound change: <%s> %s %g\n",
3481          SCIPvarGetName(var), boundtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", bound);
3482 
3483       SCIP_CALL( SCIPnodeAddBoundchg(tree->path[conflictset->validdepth], blkmem, set, stat, transprob, origprob, tree,
3484             reopt, lp, branchcand, eventqueue, cliquetable, var, bound, boundtype, FALSE) );
3485 
3486       *success = TRUE;
3487       SCIP_CALL( updateStatistics(conflict, blkmem, set, stat, conflictset, insertdepth) );
3488    }
3489    else if( !conflictset->hasrelaxonlyvar )
3490    {
3491       /* sort conflict handlers by priority */
3492       SCIPsetSortConflicthdlrs(set);
3493 
3494       /* call conflict handlers to create a conflict constraint */
3495       for( h = 0; h < set->nconflicthdlrs; ++h )
3496       {
3497          SCIP_RESULT result;
3498 
3499          assert(conflictset->conflicttype != SCIP_CONFTYPE_UNKNOWN);
3500 
3501          SCIP_CALL( SCIPconflicthdlrExec(set->conflicthdlrs[h], set, tree->path[insertdepth],
3502                tree->path[conflictset->validdepth], conflictset->bdchginfos, conflictset->relaxedbds,
3503                conflictset->nbdchginfos, conflictset->conflicttype, conflictset->usescutoffbound, *success, &result) );
3504          if( result == SCIP_CONSADDED )
3505          {
3506             *success = TRUE;
3507             SCIP_CALL( updateStatistics(conflict, blkmem, set, stat, conflictset, insertdepth) );
3508          }
3509 
3510          SCIPsetDebugMsg(set, " -> call conflict handler <%s> (prio=%d) to create conflict set with %d bounds returned result %d\n",
3511             SCIPconflicthdlrGetName(set->conflicthdlrs[h]), SCIPconflicthdlrGetPriority(set->conflicthdlrs[h]),
3512             conflictset->nbdchginfos, result);
3513       }
3514    }
3515    else
3516    {
3517       SCIPsetDebugMsg(set, " -> skip conflict set with relaxation-only variable\n");
3518       /* TODO would be nice to still create a constraint?, if we can make sure that we the constraint does not survive a restart */
3519    }
3520 
3521    return SCIP_OKAY;
3522 }
3523 
3524 /** adds the collected conflict constraints to the corresponding nodes; the best set->conf_maxconss conflict constraints
3525  *  are added to the node of their validdepth; additionally (if not yet added, and if repropagation is activated), the
3526  *  conflict constraint that triggers the earliest repropagation is added to the node of its validdepth
3527  */
SCIPconflictFlushConss(SCIP_CONFLICT * conflict,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * transprob,SCIP_PROB * origprob,SCIP_TREE * tree,SCIP_REOPT * reopt,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_EVENTQUEUE * eventqueue,SCIP_CLIQUETABLE * cliquetable)3528 SCIP_RETCODE SCIPconflictFlushConss(
3529    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
3530    BMS_BLKMEM*           blkmem,             /**< block memory of transformed problem */
3531    SCIP_SET*             set,                /**< global SCIP settings */
3532    SCIP_STAT*            stat,               /**< dynamic problem statistics */
3533    SCIP_PROB*            transprob,          /**< transformed problem */
3534    SCIP_PROB*            origprob,           /**< original problem */
3535    SCIP_TREE*            tree,               /**< branch and bound tree */
3536    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
3537    SCIP_LP*              lp,                 /**< current LP data */
3538    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
3539    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
3540    SCIP_CLIQUETABLE*     cliquetable         /**< clique table data structure */
3541    )
3542 {
3543    assert(conflict != NULL);
3544    assert(set != NULL);
3545    assert(stat != NULL);
3546    assert(transprob != NULL);
3547    assert(tree != NULL);
3548 
3549    /* is there anything to do? */
3550    if( conflict->nconflictsets > 0 )
3551    {
3552       SCIP_CONFLICTSET* repropconflictset;
3553       int nconflictsetsused;
3554       int focusdepth;
3555 #ifndef NDEBUG
3556       int currentdepth;
3557 #endif
3558       int cutoffdepth;
3559       int repropdepth;
3560       int maxconflictsets;
3561       int maxsize;
3562       int i;
3563 
3564       /* calculate the maximal number of conflict sets to accept, and the maximal size of each accepted conflict set */
3565       maxconflictsets = (set->conf_maxconss == -1 ? INT_MAX : set->conf_maxconss);
3566       maxsize = conflictCalcMaxsize(set, transprob);
3567 
3568       focusdepth = SCIPtreeGetFocusDepth(tree);
3569 #ifndef NDEBUG
3570       currentdepth = SCIPtreeGetCurrentDepth(tree);
3571       assert(focusdepth <= currentdepth);
3572       assert(currentdepth == tree->pathlen-1);
3573 #endif
3574 
3575       SCIPsetDebugMsg(set, "flushing %d conflict sets at focus depth %d (maxconflictsets: %d, maxsize: %d)\n",
3576          conflict->nconflictsets, focusdepth, maxconflictsets, maxsize);
3577 
3578       /* mark the focus node to have produced conflict sets in the visualization output */
3579       SCIPvisualFoundConflict(stat->visual, stat, tree->path[focusdepth]);
3580 
3581       /* insert the conflict sets at the corresponding nodes */
3582       nconflictsetsused = 0;
3583       cutoffdepth = INT_MAX;
3584       repropdepth = INT_MAX;
3585       repropconflictset = NULL;
3586       for( i = 0; i < conflict->nconflictsets && nconflictsetsused < maxconflictsets; ++i )
3587       {
3588          SCIP_CONFLICTSET* conflictset;
3589 
3590          conflictset = conflict->conflictsets[i];
3591          assert(conflictset != NULL);
3592          assert(0 <= conflictset->validdepth);
3593          assert(conflictset->validdepth <= conflictset->insertdepth);
3594          assert(conflictset->insertdepth <= focusdepth);
3595          assert(conflictset->insertdepth <= conflictset->repropdepth);
3596          assert(conflictset->repropdepth <= currentdepth || conflictset->repropdepth == INT_MAX); /* INT_MAX for dive/probing/strong */
3597          assert(conflictset->conflictdepth <= currentdepth || conflictset->conflictdepth == INT_MAX); /* INT_MAX for dive/probing/strong */
3598 
3599          /* ignore conflict sets that are only valid at a node that was already cut off */
3600          if( conflictset->insertdepth >= cutoffdepth )
3601          {
3602             SCIPsetDebugMsg(set, " -> ignoring conflict set with insertdepth %d >= cutoffdepth %d\n",
3603                conflictset->validdepth, cutoffdepth);
3604             continue;
3605          }
3606 
3607          /* if no conflict bounds exist, the node and its sub tree in the conflict set's valid depth can be
3608           * cut off completely
3609           */
3610          if( conflictset->nbdchginfos == 0 )
3611          {
3612             SCIPsetDebugMsg(set, " -> empty conflict set in depth %d cuts off sub tree at depth %d\n",
3613                focusdepth, conflictset->validdepth);
3614 
3615             SCIP_CALL( SCIPnodeCutoff(tree->path[conflictset->validdepth], set, stat, tree, transprob, origprob, reopt, lp, blkmem) );
3616             cutoffdepth = conflictset->validdepth;
3617             continue;
3618          }
3619 
3620          /* if the conflict set is too long, use the conflict set only if it decreases the repropagation depth */
3621          if( conflictset->nbdchginfos > maxsize )
3622          {
3623             SCIPsetDebugMsg(set, " -> conflict set is too long: %d > %d literals\n", conflictset->nbdchginfos, maxsize);
3624             if( set->conf_keepreprop && conflictset->repropagate && conflictset->repropdepth < repropdepth )
3625             {
3626                repropdepth = conflictset->repropdepth;
3627                repropconflictset = conflictset;
3628             }
3629          }
3630          else
3631          {
3632             SCIP_Bool success;
3633 
3634             /* call conflict handlers to create a conflict constraint */
3635             SCIP_CALL( conflictAddConflictCons(conflict, blkmem, set, stat, transprob, origprob, tree, reopt, lp, \
3636                   branchcand, eventqueue, cliquetable, conflictset, conflictset->insertdepth, &success) );
3637 
3638             /* if no conflict bounds exist, the node and its sub tree in the conflict set's valid depth can be
3639              * cut off completely
3640              */
3641             if( conflictset->nbdchginfos == 0 )
3642             {
3643                assert(!success);
3644 
3645                SCIPsetDebugMsg(set, " -> empty conflict set in depth %d cuts off sub tree at depth %d\n",
3646                   focusdepth, conflictset->validdepth);
3647 
3648                SCIP_CALL( SCIPnodeCutoff(tree->path[conflictset->validdepth], set, stat, tree, transprob, origprob, \
3649                      reopt, lp, blkmem) );
3650                cutoffdepth = conflictset->validdepth;
3651                continue;
3652             }
3653 
3654             if( success )
3655             {
3656                SCIPsetDebugMsg(set, " -> conflict set %d/%d added (cdpt:%d, fdpt:%d, insert:%d, valid:%d, conf:%d, reprop:%d, len:%d):\n",
3657                   nconflictsetsused+1, maxconflictsets, SCIPtreeGetCurrentDepth(tree), SCIPtreeGetFocusDepth(tree),
3658                   conflictset->insertdepth, conflictset->validdepth, conflictset->conflictdepth, conflictset->repropdepth,
3659                   conflictset->nbdchginfos);
3660                SCIPdebug(conflictsetPrint(conflictset));
3661 
3662                if( conflictset->repropagate && conflictset->repropdepth <= repropdepth )
3663                {
3664                   repropdepth = conflictset->repropdepth;
3665                   repropconflictset = NULL;
3666                }
3667                nconflictsetsused++;
3668             }
3669          }
3670       }
3671 
3672       /* reactivate propagation on the first node where one of the new conflict sets trigger a deduction */
3673       if( set->conf_repropagate && repropdepth < cutoffdepth && repropdepth < tree->pathlen )
3674       {
3675          assert(0 <= repropdepth && repropdepth < tree->pathlen);
3676          assert((int) tree->path[repropdepth]->depth == repropdepth);
3677 
3678          /* if the conflict constraint of smallest repropagation depth was not yet added, insert it now */
3679          if( repropconflictset != NULL )
3680          {
3681             SCIP_Bool success;
3682 
3683             assert(repropconflictset->repropagate);
3684             assert(repropconflictset->repropdepth == repropdepth);
3685 
3686             SCIP_CALL( conflictAddConflictCons(conflict, blkmem, set, stat, transprob, origprob, tree, reopt, lp, \
3687                   branchcand, eventqueue, cliquetable, repropconflictset, repropdepth, &success) );
3688 
3689             /* if no conflict bounds exist, the node and its sub tree in the conflict set's valid depth can be
3690              * cut off completely
3691              */
3692             if( repropconflictset->nbdchginfos == 0 )
3693             {
3694                assert(!success);
3695 
3696                SCIPsetDebugMsg(set, " -> empty reprop conflict set in depth %d cuts off sub tree at depth %d\n",
3697                   focusdepth, repropconflictset->validdepth);
3698 
3699                SCIP_CALL( SCIPnodeCutoff(tree->path[repropconflictset->validdepth], set, stat, tree, transprob, \
3700                      origprob, reopt, lp, blkmem) );
3701             }
3702 
3703 #ifdef SCIP_DEBUG
3704             if( success )
3705             {
3706                SCIPsetDebugMsg(set, " -> additional reprop conflict set added (cdpt:%d, fdpt:%d, insert:%d, valid:%d, conf:%d, reprop:%d, len:%d):\n",
3707                   SCIPtreeGetCurrentDepth(tree), SCIPtreeGetFocusDepth(tree),
3708                   repropconflictset->insertdepth, repropconflictset->validdepth, repropconflictset->conflictdepth,
3709                   repropconflictset->repropdepth, repropconflictset->nbdchginfos);
3710                SCIPdebug(conflictsetPrint(repropconflictset));
3711             }
3712 #endif
3713          }
3714 
3715          /* mark the node in the repropdepth to be propagated again */
3716          SCIPnodePropagateAgain(tree->path[repropdepth], set, stat, tree);
3717 
3718          SCIPsetDebugMsg(set, "marked node %p in depth %d to be repropagated due to conflicts found in depth %d\n",
3719             (void*)tree->path[repropdepth], repropdepth, focusdepth);
3720       }
3721 
3722       /* free the conflict store */
3723       for( i = 0; i < conflict->nconflictsets; ++i )
3724       {
3725          conflictsetFree(&conflict->conflictsets[i], blkmem);
3726       }
3727       conflict->nconflictsets = 0;
3728    }
3729 
3730    /* free all temporarily created bound change information data */
3731    conflictFreeTmpBdchginfos(conflict, blkmem);
3732 
3733    return SCIP_OKAY;
3734 }
3735 
3736 /** returns the current number of conflict sets in the conflict set storage */
SCIPconflictGetNConflicts(SCIP_CONFLICT * conflict)3737 int SCIPconflictGetNConflicts(
3738    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
3739    )
3740 {
3741    assert(conflict != NULL);
3742 
3743    return conflict->nconflictsets;
3744 }
3745 
3746 /** returns the total number of conflict constraints that were added to the problem */
SCIPconflictGetNAppliedConss(SCIP_CONFLICT * conflict)3747 SCIP_Longint SCIPconflictGetNAppliedConss(
3748    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
3749    )
3750 {
3751    assert(conflict != NULL);
3752 
3753    return conflict->nappliedglbconss + conflict->nappliedlocconss;
3754 }
3755 
3756 /** returns the total number of literals in conflict constraints that were added to the problem */
SCIPconflictGetNAppliedLiterals(SCIP_CONFLICT * conflict)3757 SCIP_Longint SCIPconflictGetNAppliedLiterals(
3758    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
3759    )
3760 {
3761    assert(conflict != NULL);
3762 
3763    return conflict->nappliedglbliterals + conflict->nappliedlocliterals;
3764 }
3765 
3766 /** returns the total number of global bound changes applied by the conflict analysis */
SCIPconflictGetNGlobalChgBds(SCIP_CONFLICT * conflict)3767 SCIP_Longint SCIPconflictGetNGlobalChgBds(
3768    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
3769    )
3770 {
3771    assert(conflict != NULL);
3772 
3773    return conflict->nglbchgbds;
3774 }
3775 
3776 /** returns the total number of conflict constraints that were added globally to the problem */
SCIPconflictGetNAppliedGlobalConss(SCIP_CONFLICT * conflict)3777 SCIP_Longint SCIPconflictGetNAppliedGlobalConss(
3778    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
3779    )
3780 {
3781    assert(conflict != NULL);
3782 
3783    return conflict->nappliedglbconss;
3784 }
3785 
3786 /** returns the total number of literals in conflict constraints that were added globally to the problem */
SCIPconflictGetNAppliedGlobalLiterals(SCIP_CONFLICT * conflict)3787 SCIP_Longint SCIPconflictGetNAppliedGlobalLiterals(
3788    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
3789    )
3790 {
3791    assert(conflict != NULL);
3792 
3793    return conflict->nappliedglbliterals;
3794 }
3795 
3796 /** returns the total number of local bound changes applied by the conflict analysis */
SCIPconflictGetNLocalChgBds(SCIP_CONFLICT * conflict)3797 SCIP_Longint SCIPconflictGetNLocalChgBds(
3798    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
3799    )
3800 {
3801    assert(conflict != NULL);
3802 
3803    return conflict->nlocchgbds;
3804 }
3805 
3806 /** returns the total number of conflict constraints that were added locally to the problem */
SCIPconflictGetNAppliedLocalConss(SCIP_CONFLICT * conflict)3807 SCIP_Longint SCIPconflictGetNAppliedLocalConss(
3808    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
3809    )
3810 {
3811    assert(conflict != NULL);
3812 
3813    return conflict->nappliedlocconss;
3814 }
3815 
3816 /** returns the total number of literals in conflict constraints that were added locally to the problem */
SCIPconflictGetNAppliedLocalLiterals(SCIP_CONFLICT * conflict)3817 SCIP_Longint SCIPconflictGetNAppliedLocalLiterals(
3818    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
3819    )
3820 {
3821    assert(conflict != NULL);
3822 
3823    return conflict->nappliedlocliterals;
3824 }
3825 
3826 
3827 
3828 
3829 /*
3830  * Propagation Conflict Analysis
3831  */
3832 
3833 /** returns whether bound change has a valid reason that can be resolved in conflict analysis */
3834 static
bdchginfoIsResolvable(SCIP_BDCHGINFO * bdchginfo)3835 SCIP_Bool bdchginfoIsResolvable(
3836    SCIP_BDCHGINFO*       bdchginfo           /**< bound change information */
3837    )
3838 {
3839    assert(bdchginfo != NULL);
3840    assert(!SCIPbdchginfoIsRedundant(bdchginfo));
3841 
3842    return (SCIPbdchginfoGetChgtype(bdchginfo) == SCIP_BOUNDCHGTYPE_CONSINFER
3843       || (SCIPbdchginfoGetChgtype(bdchginfo) == SCIP_BOUNDCHGTYPE_PROPINFER
3844          && SCIPbdchginfoGetInferProp(bdchginfo) != NULL));
3845 }
3846 
3847 /** compares two conflict set entries, such that bound changes infered later are
3848  *  ordered prior to ones that were infered earlier
3849  */
3850 static
SCIP_DECL_SORTPTRCOMP(conflictBdchginfoComp)3851 SCIP_DECL_SORTPTRCOMP(conflictBdchginfoComp)
3852 {  /*lint --e{715}*/
3853    SCIP_BDCHGINFO* bdchginfo1;
3854    SCIP_BDCHGINFO* bdchginfo2;
3855 
3856    bdchginfo1 = (SCIP_BDCHGINFO*)elem1;
3857    bdchginfo2 = (SCIP_BDCHGINFO*)elem2;
3858    assert(bdchginfo1 != NULL);
3859    assert(bdchginfo2 != NULL);
3860    assert(!SCIPbdchginfoIsRedundant(bdchginfo1));
3861    assert(!SCIPbdchginfoIsRedundant(bdchginfo2));
3862 
3863    if( bdchginfo1 == bdchginfo2 )
3864       return 0;
3865 
3866    if( !SCIPbdchgidxIsEarlierNonNull(SCIPbdchginfoGetIdx(bdchginfo1), SCIPbdchginfoGetIdx(bdchginfo2)) )
3867       return -1;
3868    else
3869       return +1;
3870 }
3871 
3872 /** return TRUE if conflict analysis is applicable; In case the function return FALSE there is no need to initialize the
3873  *  conflict analysis since it will not be applied
3874  */
SCIPconflictApplicable(SCIP_SET * set)3875 SCIP_Bool SCIPconflictApplicable(
3876    SCIP_SET*             set                 /**< global SCIP settings */
3877    )
3878 {
3879    /* check, if propagation conflict analysis is enabled */
3880    if( !set->conf_enable || !set->conf_useprop )
3881       return FALSE;
3882 
3883    /* check, if there are any conflict handlers to use a conflict set */
3884    if( set->nconflicthdlrs == 0 )
3885       return FALSE;
3886 
3887    return TRUE;
3888 }
3889 
3890 /** creates conflict analysis data for propagation conflicts */
SCIPconflictCreate(SCIP_CONFLICT ** conflict,BMS_BLKMEM * blkmem,SCIP_SET * set)3891 SCIP_RETCODE SCIPconflictCreate(
3892    SCIP_CONFLICT**       conflict,           /**< pointer to conflict analysis data */
3893    BMS_BLKMEM*           blkmem,             /**< block memory of transformed problem */
3894    SCIP_SET*             set                 /**< global SCIP settings */
3895    )
3896 {
3897    assert(conflict != NULL);
3898 
3899    SCIP_ALLOC( BMSallocMemory(conflict) );
3900 
3901    SCIP_CALL( SCIPclockCreate(&(*conflict)->dIBclock, SCIP_CLOCKTYPE_DEFAULT) );
3902    SCIP_CALL( SCIPclockCreate(&(*conflict)->propanalyzetime, SCIP_CLOCKTYPE_DEFAULT) );
3903    SCIP_CALL( SCIPclockCreate(&(*conflict)->inflpanalyzetime, SCIP_CLOCKTYPE_DEFAULT) );
3904    SCIP_CALL( SCIPclockCreate(&(*conflict)->boundlpanalyzetime, SCIP_CLOCKTYPE_DEFAULT) );
3905    SCIP_CALL( SCIPclockCreate(&(*conflict)->sbanalyzetime, SCIP_CLOCKTYPE_DEFAULT) );
3906    SCIP_CALL( SCIPclockCreate(&(*conflict)->pseudoanalyzetime, SCIP_CLOCKTYPE_DEFAULT) );
3907 
3908    /* enable or disable timing depending on the parameter statistic timing */
3909    SCIPconflictEnableOrDisableClocks((*conflict), set->time_statistictiming);
3910 
3911    SCIP_CALL( SCIPpqueueCreate(&(*conflict)->bdchgqueue, set->mem_arraygrowinit, set->mem_arraygrowfac,
3912          conflictBdchginfoComp, NULL) );
3913    SCIP_CALL( SCIPpqueueCreate(&(*conflict)->forcedbdchgqueue, set->mem_arraygrowinit, set->mem_arraygrowfac,
3914          conflictBdchginfoComp, NULL) );
3915    SCIP_CALL( conflictsetCreate(&(*conflict)->conflictset, blkmem) );
3916    (*conflict)->conflictsets = NULL;
3917    (*conflict)->conflictsetscores = NULL;
3918    (*conflict)->tmpbdchginfos = NULL;
3919    (*conflict)->conflictsetssize = 0;
3920    (*conflict)->nconflictsets = 0;
3921    (*conflict)->proofsets = NULL;
3922    (*conflict)->proofsetssize = 0;
3923    (*conflict)->nproofsets = 0;
3924    (*conflict)->tmpbdchginfossize = 0;
3925    (*conflict)->ntmpbdchginfos = 0;
3926    (*conflict)->count = 0;
3927    (*conflict)->nglbchgbds = 0;
3928    (*conflict)->nappliedglbconss = 0;
3929    (*conflict)->nappliedglbliterals = 0;
3930    (*conflict)->nlocchgbds = 0;
3931    (*conflict)->nappliedlocconss = 0;
3932    (*conflict)->nappliedlocliterals = 0;
3933    (*conflict)->npropcalls = 0;
3934    (*conflict)->npropsuccess = 0;
3935    (*conflict)->npropconfconss = 0;
3936    (*conflict)->npropconfliterals = 0;
3937    (*conflict)->npropreconvconss = 0;
3938    (*conflict)->npropreconvliterals = 0;
3939    (*conflict)->ninflpcalls = 0;
3940    (*conflict)->ninflpsuccess = 0;
3941    (*conflict)->ninflpconfconss = 0;
3942    (*conflict)->ninflpconfliterals = 0;
3943    (*conflict)->ninflpreconvconss = 0;
3944    (*conflict)->ninflpreconvliterals = 0;
3945    (*conflict)->ninflpiterations = 0;
3946    (*conflict)->nboundlpcalls = 0;
3947    (*conflict)->nboundlpsuccess = 0;
3948    (*conflict)->nboundlpconfconss = 0;
3949    (*conflict)->nboundlpconfliterals = 0;
3950    (*conflict)->nboundlpreconvconss = 0;
3951    (*conflict)->nboundlpreconvliterals = 0;
3952    (*conflict)->nboundlpiterations = 0;
3953    (*conflict)->nsbcalls = 0;
3954    (*conflict)->nsbsuccess = 0;
3955    (*conflict)->nsbconfconss = 0;
3956    (*conflict)->nsbconfliterals = 0;
3957    (*conflict)->nsbreconvconss = 0;
3958    (*conflict)->nsbreconvliterals = 0;
3959    (*conflict)->nsbiterations = 0;
3960    (*conflict)->npseudocalls = 0;
3961    (*conflict)->npseudosuccess = 0;
3962    (*conflict)->npseudoconfconss = 0;
3963    (*conflict)->npseudoconfliterals = 0;
3964    (*conflict)->npseudoreconvconss = 0;
3965    (*conflict)->npseudoreconvliterals = 0;
3966    (*conflict)->ndualproofsinfglobal = 0;
3967    (*conflict)->ndualproofsinflocal = 0;
3968    (*conflict)->ndualproofsinfsuccess = 0;
3969    (*conflict)->dualproofsinfnnonzeros = 0;
3970    (*conflict)->ndualproofsbndglobal = 0;
3971    (*conflict)->ndualproofsbndlocal = 0;
3972    (*conflict)->ndualproofsbndsuccess = 0;
3973    (*conflict)->dualproofsbndnnonzeros = 0;
3974 
3975    SCIP_CALL( conflictInitProofset((*conflict), blkmem) );
3976 
3977    return SCIP_OKAY;
3978 }
3979 
3980 /** frees conflict analysis data for propagation conflicts */
SCIPconflictFree(SCIP_CONFLICT ** conflict,BMS_BLKMEM * blkmem)3981 SCIP_RETCODE SCIPconflictFree(
3982    SCIP_CONFLICT**       conflict,           /**< pointer to conflict analysis data */
3983    BMS_BLKMEM*           blkmem              /**< block memory of transformed problem */
3984    )
3985 {
3986    assert(conflict != NULL);
3987    assert(*conflict != NULL);
3988    assert((*conflict)->nconflictsets == 0);
3989    assert((*conflict)->ntmpbdchginfos == 0);
3990 
3991 #ifdef SCIP_CONFGRAPH
3992    confgraphFree();
3993 #endif
3994 
3995    SCIPclockFree(&(*conflict)->dIBclock);
3996    SCIPclockFree(&(*conflict)->propanalyzetime);
3997    SCIPclockFree(&(*conflict)->inflpanalyzetime);
3998    SCIPclockFree(&(*conflict)->boundlpanalyzetime);
3999    SCIPclockFree(&(*conflict)->sbanalyzetime);
4000    SCIPclockFree(&(*conflict)->pseudoanalyzetime);
4001    SCIPpqueueFree(&(*conflict)->bdchgqueue);
4002    SCIPpqueueFree(&(*conflict)->forcedbdchgqueue);
4003    conflictsetFree(&(*conflict)->conflictset, blkmem);
4004    proofsetFree(&(*conflict)->proofset, blkmem);
4005 
4006    BMSfreeMemoryArrayNull(&(*conflict)->conflictsets);
4007    BMSfreeMemoryArrayNull(&(*conflict)->conflictsetscores);
4008    BMSfreeMemoryArrayNull(&(*conflict)->proofsets);
4009    BMSfreeMemoryArrayNull(&(*conflict)->tmpbdchginfos);
4010    BMSfreeMemory(conflict);
4011 
4012    return SCIP_OKAY;
4013 }
4014 
4015 /** clears the conflict queue and the current conflict set */
4016 static
conflictClear(SCIP_CONFLICT * conflict)4017 void conflictClear(
4018    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
4019    )
4020 {
4021    assert(conflict != NULL);
4022 
4023    SCIPpqueueClear(conflict->bdchgqueue);
4024    SCIPpqueueClear(conflict->forcedbdchgqueue);
4025    conflictsetClear(conflict->conflictset);
4026 }
4027 
4028 /** initializes the propagation conflict analysis by clearing the conflict candidate queue */
SCIPconflictInit(SCIP_CONFLICT * conflict,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * prob,SCIP_CONFTYPE conftype,SCIP_Bool usescutoffbound)4029 SCIP_RETCODE SCIPconflictInit(
4030    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
4031    SCIP_SET*             set,                /**< global SCIP settings */
4032    SCIP_STAT*            stat,               /**< problem statistics */
4033    SCIP_PROB*            prob,               /**< problem data */
4034    SCIP_CONFTYPE         conftype,           /**< type of the conflict */
4035    SCIP_Bool             usescutoffbound     /**< depends the conflict on a cutoff bound? */
4036    )
4037 {
4038    assert(conflict != NULL);
4039    assert(set != NULL);
4040    assert(stat != NULL);
4041    assert(prob != NULL);
4042 
4043    SCIPsetDebugMsg(set, "initializing conflict analysis\n");
4044 
4045    /* clear the conflict candidate queue and the conflict set */
4046    conflictClear(conflict);
4047 
4048    /* set conflict type */
4049    assert(conftype == SCIP_CONFTYPE_BNDEXCEEDING || conftype == SCIP_CONFTYPE_INFEASLP
4050        || conftype == SCIP_CONFTYPE_PROPAGATION);
4051    conflict->conflictset->conflicttype = conftype;
4052 
4053    /* set whether a cutoff bound is involved */
4054    conflict->conflictset->usescutoffbound = usescutoffbound;
4055 
4056    /* increase the conflict counter, such that binary variables of new conflict set and new conflict queue are labeled
4057     * with this new counter
4058     */
4059    conflict->count++;
4060    if( conflict->count == 0 ) /* make sure, 0 is not a valid conflict counter (may happen due to integer overflow) */
4061       conflict->count = 1;
4062 
4063    /* increase the conflict score weight for history updates of future conflict reasons */
4064    if( stat->nnodes > stat->lastconflictnode )
4065    {
4066       assert(0.0 < set->conf_scorefac && set->conf_scorefac <= 1.0);
4067       stat->vsidsweight /= set->conf_scorefac;
4068       assert(stat->vsidsweight > 0.0);
4069 
4070       /* if the conflict score for the next conflict exceeds 1000.0, rescale all history conflict scores */
4071       if( stat->vsidsweight >= 1000.0 )
4072       {
4073          int v;
4074 
4075          for( v = 0; v < prob->nvars; ++v )
4076          {
4077             SCIP_CALL( SCIPvarScaleVSIDS(prob->vars[v], 1.0/stat->vsidsweight) );
4078          }
4079          SCIPhistoryScaleVSIDS(stat->glbhistory, 1.0/stat->vsidsweight);
4080          SCIPhistoryScaleVSIDS(stat->glbhistorycrun, 1.0/stat->vsidsweight);
4081          stat->vsidsweight = 1.0;
4082       }
4083       stat->lastconflictnode = stat->nnodes;
4084    }
4085 
4086 #ifdef SCIP_CONFGRAPH
4087    confgraphFree();
4088    SCIP_CALL( confgraphCreate(set, conflict) );
4089 #endif
4090 
4091    return SCIP_OKAY;
4092 }
4093 
4094 /** marks bound to be present in the current conflict and returns whether a bound which is at least as tight was already
4095  *  member of the current conflict (i.e., the given bound change does not need to be added)
4096  */
4097 static
conflictMarkBoundCheckPresence(SCIP_CONFLICT * conflict,SCIP_SET * set,SCIP_BDCHGINFO * bdchginfo,SCIP_Real relaxedbd)4098 SCIP_Bool conflictMarkBoundCheckPresence(
4099    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
4100    SCIP_SET*             set,                /**< global SCIP settings */
4101    SCIP_BDCHGINFO*       bdchginfo,          /**< bound change to add to the conflict set */
4102    SCIP_Real             relaxedbd           /**< relaxed bound */
4103    )
4104 {
4105    SCIP_VAR* var;
4106    SCIP_Real newbound;
4107 
4108    assert(conflict != NULL);
4109 
4110    var = SCIPbdchginfoGetVar(bdchginfo);
4111    newbound = SCIPbdchginfoGetNewbound(bdchginfo);
4112    assert(var != NULL);
4113 
4114    switch( SCIPbdchginfoGetBoundtype(bdchginfo) )
4115    {
4116    case SCIP_BOUNDTYPE_LOWER:
4117       /* check if the variables lower bound is already member of the conflict */
4118       if( var->conflictlbcount == conflict->count )
4119       {
4120          /* the variable is already member of the conflict; hence check if the new bound is redundant */
4121          if( var->conflictlb > newbound )
4122          {
4123             SCIPsetDebugMsg(set, "ignoring redundant bound change <%s> >= %g since a stronger lower bound exist <%s> >= %g\n",
4124                SCIPvarGetName(var), newbound, SCIPvarGetName(var), var->conflictlb);
4125             return TRUE;
4126          }
4127          else if( var->conflictlb == newbound ) /*lint !e777*/
4128          {
4129             SCIPsetDebugMsg(set, "ignoring redundant bound change <%s> >= %g since this lower bound is already present\n", SCIPvarGetName(var), newbound);
4130             SCIPsetDebugMsg(set, "adjust relaxed lower bound <%g> -> <%g>\n", var->conflictlb, relaxedbd);
4131             var->conflictrelaxedlb = MAX(var->conflictrelaxedlb, relaxedbd);
4132             return TRUE;
4133          }
4134       }
4135 
4136       /* add the variable lower bound to the current conflict */
4137       var->conflictlbcount = conflict->count;
4138 
4139       /* remember the lower bound and relaxed bound to allow only better/tighter lower bounds for that variables
4140        * w.r.t. this conflict
4141        */
4142       var->conflictlb = newbound;
4143       var->conflictrelaxedlb = relaxedbd;
4144 
4145       return FALSE;
4146 
4147    case SCIP_BOUNDTYPE_UPPER:
4148       /* check if the variables upper bound is already member of the conflict */
4149       if( var->conflictubcount == conflict->count )
4150       {
4151          /* the variable is already member of the conflict; hence check if the new bound is redundant */
4152          if( var->conflictub < newbound )
4153          {
4154             SCIPsetDebugMsg(set, "ignoring redundant bound change <%s> <= %g since a stronger upper bound exist <%s> <= %g\n",
4155                SCIPvarGetName(var), newbound, SCIPvarGetName(var), var->conflictub);
4156             return TRUE;
4157          }
4158          else if( var->conflictub == newbound ) /*lint !e777*/
4159          {
4160             SCIPsetDebugMsg(set, "ignoring redundant bound change <%s> <= %g since this upper bound is already present\n", SCIPvarGetName(var), newbound);
4161             SCIPsetDebugMsg(set, "adjust relaxed upper bound <%g> -> <%g>\n", var->conflictub, relaxedbd);
4162             var->conflictrelaxedub = MIN(var->conflictrelaxedub, relaxedbd);
4163             return TRUE;
4164          }
4165       }
4166 
4167       /* add the variable upper bound to the current conflict */
4168       var->conflictubcount = conflict->count;
4169 
4170       /* remember the upper bound and relaxed bound to allow only better/tighter upper bounds for that variables
4171        * w.r.t. this conflict
4172        */
4173       var->conflictub = newbound;
4174       var->conflictrelaxedub = relaxedbd;
4175 
4176       return FALSE;
4177 
4178    default:
4179       SCIPerrorMessage("invalid bound type %d\n", SCIPbdchginfoGetBoundtype(bdchginfo));
4180       SCIPABORT();
4181       return FALSE; /*lint !e527*/
4182    }
4183 }
4184 
4185 /** puts bound change into the current conflict set */
4186 static
conflictAddConflictBound(SCIP_CONFLICT * conflict,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_BDCHGINFO * bdchginfo,SCIP_Real relaxedbd)4187 SCIP_RETCODE conflictAddConflictBound(
4188    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
4189    BMS_BLKMEM*           blkmem,             /**< block memory of transformed problem */
4190    SCIP_SET*             set,                /**< global SCIP settings */
4191    SCIP_BDCHGINFO*       bdchginfo,          /**< bound change to add to the conflict set */
4192    SCIP_Real             relaxedbd           /**< relaxed bound */
4193    )
4194 {
4195    assert(conflict != NULL);
4196    assert(!SCIPbdchginfoIsRedundant(bdchginfo));
4197 
4198    /* check if the relaxed bound is really a relaxed bound */
4199    assert(SCIPbdchginfoGetBoundtype(bdchginfo) == SCIP_BOUNDTYPE_LOWER || SCIPsetIsGE(set, relaxedbd, SCIPbdchginfoGetNewbound(bdchginfo)));
4200    assert(SCIPbdchginfoGetBoundtype(bdchginfo) == SCIP_BOUNDTYPE_UPPER || SCIPsetIsLE(set, relaxedbd, SCIPbdchginfoGetNewbound(bdchginfo)));
4201 
4202    SCIPsetDebugMsg(set, "putting bound change <%s> %s %g(%g) at depth %d to current conflict set\n",
4203       SCIPvarGetName(SCIPbdchginfoGetVar(bdchginfo)),
4204       SCIPbdchginfoGetBoundtype(bdchginfo) == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", SCIPbdchginfoGetNewbound(bdchginfo),
4205       relaxedbd, SCIPbdchginfoGetDepth(bdchginfo));
4206 
4207    /* mark the bound to be member of the conflict and check if a bound which is at least as tight is already member of
4208     * the conflict
4209     */
4210    if( !conflictMarkBoundCheckPresence(conflict, set, bdchginfo, relaxedbd) )
4211    {
4212       /* add the bound change to the current conflict set */
4213       SCIP_CALL( conflictsetAddBound(conflict->conflictset, blkmem, set, bdchginfo, relaxedbd) );
4214 
4215 #ifdef SCIP_CONFGRAPH
4216       if( bdchginfo != confgraphcurrentbdchginfo )
4217          confgraphAddBdchg(bdchginfo);
4218 #endif
4219    }
4220 #ifdef SCIP_CONFGRAPH
4221    else
4222       confgraphLinkBdchg(bdchginfo);
4223 #endif
4224 
4225    return SCIP_OKAY;
4226 }
4227 
4228 /** returns whether the negation of the given bound change would lead to a globally valid literal */
4229 static
isBoundchgUseless(SCIP_SET * set,SCIP_BDCHGINFO * bdchginfo)4230 SCIP_Bool isBoundchgUseless(
4231    SCIP_SET*             set,                /**< global SCIP settings */
4232    SCIP_BDCHGINFO*       bdchginfo           /**< bound change information */
4233    )
4234 {
4235    SCIP_VAR* var;
4236    SCIP_BOUNDTYPE boundtype;
4237    SCIP_Real bound;
4238 
4239    var = SCIPbdchginfoGetVar(bdchginfo);
4240    boundtype = SCIPbdchginfoGetBoundtype(bdchginfo);
4241    bound = SCIPbdchginfoGetNewbound(bdchginfo);
4242 
4243    return (SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS
4244       && ((boundtype == SCIP_BOUNDTYPE_LOWER && SCIPsetIsFeasGE(set, bound, SCIPvarGetUbGlobal(var)))
4245          || (boundtype == SCIP_BOUNDTYPE_UPPER && SCIPsetIsFeasLE(set, bound, SCIPvarGetLbGlobal(var)))));
4246 }
4247 
4248 /** adds given bound change information to the conflict candidate queue */
4249 static
conflictQueueBound(SCIP_CONFLICT * conflict,SCIP_SET * set,SCIP_BDCHGINFO * bdchginfo,SCIP_Real relaxedbd)4250 SCIP_RETCODE conflictQueueBound(
4251    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
4252    SCIP_SET*             set,                /**< global SCIP settings */
4253    SCIP_BDCHGINFO*       bdchginfo,          /**< bound change information */
4254    SCIP_Real             relaxedbd           /**< relaxed bound */
4255    )
4256 {
4257    assert(conflict != NULL);
4258    assert(set != NULL);
4259    assert(bdchginfo != NULL);
4260    assert(!SCIPbdchginfoIsRedundant(bdchginfo));
4261 
4262    /* check if the relaxed bound is really a relaxed bound */
4263    assert(SCIPbdchginfoGetBoundtype(bdchginfo) == SCIP_BOUNDTYPE_LOWER || SCIPsetIsGE(set, relaxedbd, SCIPbdchginfoGetNewbound(bdchginfo)));
4264    assert(SCIPbdchginfoGetBoundtype(bdchginfo) == SCIP_BOUNDTYPE_UPPER || SCIPsetIsLE(set, relaxedbd, SCIPbdchginfoGetNewbound(bdchginfo)));
4265 
4266    /* mark the bound to be member of the conflict and check if a bound which is at least as tight is already member of
4267     * the conflict
4268     */
4269    if( !conflictMarkBoundCheckPresence(conflict, set, bdchginfo, relaxedbd) )
4270    {
4271       /* insert the bound change into the conflict queue */
4272       if( (!set->conf_preferbinary || SCIPvarIsBinary(SCIPbdchginfoGetVar(bdchginfo)))
4273          && !isBoundchgUseless(set, bdchginfo) )
4274       {
4275          SCIP_CALL( SCIPpqueueInsert(conflict->bdchgqueue, (void*)bdchginfo) );
4276       }
4277       else
4278       {
4279          SCIP_CALL( SCIPpqueueInsert(conflict->forcedbdchgqueue, (void*)bdchginfo) );
4280       }
4281 
4282 #ifdef SCIP_CONFGRAPH
4283       confgraphAddBdchg(bdchginfo);
4284 #endif
4285    }
4286 #ifdef SCIP_CONFGRAPH
4287    else
4288       confgraphLinkBdchg(bdchginfo);
4289 #endif
4290 
4291    return SCIP_OKAY;
4292 }
4293 
4294 /** convert variable and bound change to active variable */
4295 static
convertToActiveVar(SCIP_VAR ** var,SCIP_SET * set,SCIP_BOUNDTYPE * boundtype,SCIP_Real * bound)4296 SCIP_RETCODE convertToActiveVar(
4297    SCIP_VAR**            var,                /**< pointer to variable */
4298    SCIP_SET*             set,                /**< global SCIP settings */
4299    SCIP_BOUNDTYPE*       boundtype,          /**< pointer to type of bound that was changed: lower or upper bound */
4300    SCIP_Real*            bound               /**< pointer to bound to convert, or NULL */
4301    )
4302 {
4303    SCIP_Real scalar;
4304    SCIP_Real constant;
4305 
4306    scalar = 1.0;
4307    constant = 0.0;
4308 
4309    /* transform given varibale to active varibale */
4310    SCIP_CALL( SCIPvarGetProbvarSum(var, set, &scalar, &constant) );
4311    assert(SCIPvarGetStatus(*var) == SCIP_VARSTATUS_FIXED || scalar != 0.0); /*lint !e777*/
4312 
4313    if( SCIPvarGetStatus(*var) == SCIP_VARSTATUS_FIXED )
4314       return SCIP_OKAY;
4315 
4316    /* if the scalar of the aggregation is negative, we have to switch the bound type */
4317    if( scalar < 0.0 )
4318       (*boundtype) = SCIPboundtypeOpposite(*boundtype);
4319 
4320    if( bound != NULL )
4321    {
4322       (*bound) -= constant;
4323       (*bound) /= scalar;
4324    }
4325 
4326    return SCIP_OKAY;
4327 }
4328 
4329 /** adds variable's bound to conflict candidate queue */
4330 static
conflictAddBound(SCIP_CONFLICT * conflict,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_VAR * var,SCIP_BOUNDTYPE boundtype,SCIP_BDCHGINFO * bdchginfo,SCIP_Real relaxedbd)4331 SCIP_RETCODE conflictAddBound(
4332    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
4333    BMS_BLKMEM*           blkmem,             /**< block memory */
4334    SCIP_SET*             set,                /**< global SCIP settings */
4335    SCIP_STAT*            stat,               /**< dynamic problem statistics */
4336    SCIP_VAR*             var,                /**< problem variable */
4337    SCIP_BOUNDTYPE        boundtype,          /**< type of bound that was changed: lower or upper bound */
4338    SCIP_BDCHGINFO*       bdchginfo,          /**< bound change info, or NULL */
4339    SCIP_Real             relaxedbd           /**< relaxed bound */
4340    )
4341 {
4342    assert(SCIPvarIsActive(var));
4343    assert(bdchginfo != NULL);
4344    assert(!SCIPbdchginfoIsRedundant(bdchginfo));
4345 
4346    SCIPsetDebugMsg(set, " -> adding bound <%s> %s %.15g(%.15g) [status:%d, type:%d, depth:%d, pos:%d, reason:<%s>, info:%d] to candidates\n",
4347       SCIPvarGetName(var),
4348       boundtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=",
4349       SCIPbdchginfoGetNewbound(bdchginfo), relaxedbd,
4350       SCIPvarGetStatus(var), SCIPvarGetType(var),
4351       SCIPbdchginfoGetDepth(bdchginfo), SCIPbdchginfoGetPos(bdchginfo),
4352       SCIPbdchginfoGetChgtype(bdchginfo) == SCIP_BOUNDCHGTYPE_BRANCHING ? "branch"
4353       : (SCIPbdchginfoGetChgtype(bdchginfo) == SCIP_BOUNDCHGTYPE_CONSINFER
4354          ? SCIPconsGetName(SCIPbdchginfoGetInferCons(bdchginfo))
4355          : (SCIPbdchginfoGetInferProp(bdchginfo) != NULL ? SCIPpropGetName(SCIPbdchginfoGetInferProp(bdchginfo))
4356             : "none")),
4357       SCIPbdchginfoGetChgtype(bdchginfo) != SCIP_BOUNDCHGTYPE_BRANCHING ? SCIPbdchginfoGetInferInfo(bdchginfo) : -1);
4358 
4359    /* the local bound change may be resolved and has to be put on the candidate queue;
4360     * we even put bound changes without inference information on the queue in order to automatically
4361     * eliminate multiple insertions of the same bound change
4362     */
4363    assert(SCIPbdchginfoGetVar(bdchginfo) == var);
4364    assert(SCIPbdchginfoGetBoundtype(bdchginfo) == boundtype);
4365    assert(SCIPbdchginfoGetDepth(bdchginfo) >= 0);
4366    assert(SCIPbdchginfoGetPos(bdchginfo) >= 0);
4367 
4368    /* the relaxed bound should be a relaxation */
4369    assert(boundtype == SCIP_BOUNDTYPE_LOWER ? SCIPsetIsLE(set, relaxedbd, SCIPbdchginfoGetNewbound(bdchginfo)) : SCIPsetIsGE(set, relaxedbd, SCIPbdchginfoGetNewbound(bdchginfo)));
4370 
4371    /* the relaxed bound should be worse then the old bound of the bound change info */
4372    assert(boundtype == SCIP_BOUNDTYPE_LOWER ? SCIPsetIsGT(set, relaxedbd, SCIPbdchginfoGetOldbound(bdchginfo)) : SCIPsetIsLT(set, relaxedbd, SCIPbdchginfoGetOldbound(bdchginfo)));
4373 
4374    /* put bound change information into priority queue */
4375    SCIP_CALL( conflictQueueBound(conflict, set, bdchginfo, relaxedbd) );
4376 
4377    /* each variable which is add to the conflict graph gets an increase in the VSIDS
4378     *
4379     * @note That is different to the VSIDS preseted in the literature
4380     */
4381    SCIP_CALL( incVSIDS(var, blkmem, set, stat, boundtype, relaxedbd, set->conf_conflictgraphweight) );
4382 
4383    return SCIP_OKAY;
4384 }
4385 
4386 /** adds variable's bound to conflict candidate queue */
SCIPconflictAddBound(SCIP_CONFLICT * conflict,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_VAR * var,SCIP_BOUNDTYPE boundtype,SCIP_BDCHGIDX * bdchgidx)4387 SCIP_RETCODE SCIPconflictAddBound(
4388    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
4389    BMS_BLKMEM*           blkmem,             /**< block memory */
4390    SCIP_SET*             set,                /**< global SCIP settings */
4391    SCIP_STAT*            stat,               /**< dynamic problem statistics */
4392    SCIP_VAR*             var,                /**< problem variable */
4393    SCIP_BOUNDTYPE        boundtype,          /**< type of bound that was changed: lower or upper bound */
4394    SCIP_BDCHGIDX*        bdchgidx            /**< bound change index (time stamp of bound change), or NULL for current time */
4395    )
4396 {
4397    SCIP_BDCHGINFO* bdchginfo;
4398 
4399    assert(conflict != NULL);
4400    assert(stat != NULL);
4401    assert(var != NULL);
4402 
4403    /* convert bound to active problem variable */
4404    SCIP_CALL( convertToActiveVar(&var, set, &boundtype, NULL) );
4405 
4406    /* we can ignore fixed variables */
4407    if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED )
4408       return SCIP_OKAY;
4409 
4410    /* if the variable is multi-aggregated, add the bounds of all aggregation variables */
4411    if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR )
4412    {
4413       SCIP_VAR** vars;
4414       SCIP_Real* scalars;
4415       int nvars;
4416       int i;
4417 
4418       vars = SCIPvarGetMultaggrVars(var);
4419       scalars = SCIPvarGetMultaggrScalars(var);
4420       nvars = SCIPvarGetMultaggrNVars(var);
4421       for( i = 0; i < nvars; ++i )
4422       {
4423          SCIP_CALL( SCIPconflictAddBound(conflict, blkmem, set, stat, vars[i],
4424                (scalars[i] < 0.0 ? SCIPboundtypeOpposite(boundtype) : boundtype), bdchgidx) );
4425       }
4426 
4427       return SCIP_OKAY;
4428    }
4429    assert(SCIPvarIsActive(var));
4430 
4431    /* get bound change information */
4432    bdchginfo = SCIPvarGetBdchgInfo(var, boundtype, bdchgidx, FALSE);
4433 
4434    /* if bound of variable was not changed (this means it is still the global bound), we can ignore the conflicting
4435     * bound
4436     */
4437    if( bdchginfo == NULL )
4438       return SCIP_OKAY;
4439 
4440    assert(SCIPbdchgidxIsEarlier(SCIPbdchginfoGetIdx(bdchginfo), bdchgidx));
4441 
4442    SCIP_CALL( conflictAddBound(conflict, blkmem, set, stat, var, boundtype, bdchginfo, SCIPbdchginfoGetNewbound(bdchginfo)) );
4443 
4444    return SCIP_OKAY;
4445 }
4446 
4447 /** adds variable's bound to conflict candidate queue */
SCIPconflictAddRelaxedBound(SCIP_CONFLICT * conflict,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_VAR * var,SCIP_BOUNDTYPE boundtype,SCIP_BDCHGIDX * bdchgidx,SCIP_Real relaxedbd)4448 SCIP_RETCODE SCIPconflictAddRelaxedBound(
4449    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
4450    BMS_BLKMEM*           blkmem,             /**< block memory */
4451    SCIP_SET*             set,                /**< global SCIP settings */
4452    SCIP_STAT*            stat,               /**< dynamic problem statistics */
4453    SCIP_VAR*             var,                /**< problem variable */
4454    SCIP_BOUNDTYPE        boundtype,          /**< type of bound that was changed: lower or upper bound */
4455    SCIP_BDCHGIDX*        bdchgidx,           /**< bound change index (time stamp of bound change), or NULL for current time */
4456    SCIP_Real             relaxedbd           /**< the relaxed bound */
4457    )
4458 {
4459    SCIP_BDCHGINFO* bdchginfo;
4460    int nbdchgs;
4461 
4462    assert(conflict != NULL);
4463    assert(stat != NULL);
4464    assert(var != NULL);
4465 
4466    if( !SCIPvarIsActive(var) )
4467    {
4468       /* convert bound to active problem variable */
4469       SCIP_CALL( convertToActiveVar(&var, set, &boundtype, &relaxedbd) );
4470 
4471       /* we can ignore fixed variables */
4472       if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED )
4473          return SCIP_OKAY;
4474 
4475       /* if the variable is multi-aggregated, add the bounds of all aggregation variables */
4476       if(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR )
4477       {
4478          SCIPsetDebugMsg(set, "ignoring relaxed bound information since variable <%s> is multi-aggregated active\n", SCIPvarGetName(var));
4479 
4480          SCIP_CALL( SCIPconflictAddBound(conflict, blkmem, set, stat, var, boundtype, bdchgidx) );
4481 
4482          return SCIP_OKAY;
4483       }
4484    }
4485    assert(SCIPvarIsActive(var));
4486 
4487    /* get bound change information */
4488    bdchginfo = SCIPvarGetBdchgInfo(var, boundtype, bdchgidx, FALSE);
4489 
4490    /* if bound of variable was not changed (this means it is still the global bound), we can ignore the conflicting
4491     * bound
4492     */
4493    if( bdchginfo == NULL )
4494       return SCIP_OKAY;
4495 
4496    /* check that the bound change info is not a temporary one */
4497    assert(SCIPbdchgidxGetPos(&bdchginfo->bdchgidx) >= 0);
4498 
4499    /* get the position of the bound change information within the bound change array of the variable */
4500    nbdchgs = (int) bdchginfo->pos;
4501    assert(nbdchgs >= 0);
4502 
4503    /* if the relaxed bound should be ignored, set the relaxed bound to the bound given by the bdchgidx; that ensures
4504     * that the loop(s) below will be skipped
4505     */
4506    if( set->conf_ignorerelaxedbd )
4507       relaxedbd = SCIPbdchginfoGetNewbound(bdchginfo);
4508 
4509    /* search for the bound change information which includes the relaxed bound */
4510    if( boundtype == SCIP_BOUNDTYPE_LOWER )
4511    {
4512       SCIP_Real newbound;
4513 
4514       /* adjust relaxed lower bound w.r.t. variable type */
4515       SCIPvarAdjustLb(var, set, &relaxedbd);
4516 
4517       /* due to numericis we compare the relaxed lower bound to the one present at the particular time point and take
4518        * the better one
4519        */
4520       newbound = SCIPbdchginfoGetNewbound(bdchginfo);
4521       relaxedbd = MIN(relaxedbd, newbound);
4522 
4523       /* check if relaxed lower bound is smaller or equal to global lower bound; if so we can ignore the conflicting
4524        * bound
4525        */
4526       if( SCIPsetIsLE(set, relaxedbd, SCIPvarGetLbGlobal(var)) )
4527          return SCIP_OKAY;
4528 
4529       while( nbdchgs > 0 )
4530       {
4531          assert(SCIPsetIsLE(set, relaxedbd, SCIPbdchginfoGetNewbound(bdchginfo)));
4532 
4533          /* check if the old lower bound is greater than or equal to relaxed lower bound; if not we found the bound
4534           * change info which we need to report
4535           */
4536          if( SCIPsetIsGT(set, relaxedbd, SCIPbdchginfoGetOldbound(bdchginfo)) )
4537             break;
4538 
4539          bdchginfo = SCIPvarGetBdchgInfoLb(var, nbdchgs-1);
4540 
4541          SCIPsetDebugMsg(set, "lower bound change %d oldbd=%.15g, newbd=%.15g, depth=%d, pos=%d, redundant=%u\n",
4542             nbdchgs, SCIPbdchginfoGetOldbound(bdchginfo), SCIPbdchginfoGetNewbound(bdchginfo),
4543             SCIPbdchginfoGetDepth(bdchginfo), SCIPbdchginfoGetPos(bdchginfo),
4544             SCIPbdchginfoIsRedundant(bdchginfo));
4545 
4546          /* if bound change is redundant (this means it now a global bound), we can ignore the conflicting bound */
4547          if( SCIPbdchginfoIsRedundant(bdchginfo) )
4548             return SCIP_OKAY;
4549 
4550          nbdchgs--;
4551       }
4552       assert(SCIPsetIsGT(set, relaxedbd, SCIPbdchginfoGetOldbound(bdchginfo)));
4553    }
4554    else
4555    {
4556       SCIP_Real newbound;
4557 
4558       assert(boundtype == SCIP_BOUNDTYPE_UPPER);
4559 
4560       /* adjust relaxed upper bound w.r.t. variable type */
4561       SCIPvarAdjustUb(var, set, &relaxedbd);
4562 
4563       /* due to numericis we compare the relaxed upper bound to the one present at the particular time point and take
4564        * the better one
4565        */
4566       newbound = SCIPbdchginfoGetNewbound(bdchginfo);
4567       relaxedbd = MAX(relaxedbd, newbound);
4568 
4569       /* check if relaxed upper bound is greater or equal to global upper bound; if so we can ignore the conflicting
4570        * bound
4571        */
4572       if( SCIPsetIsGE(set, relaxedbd, SCIPvarGetUbGlobal(var)) )
4573          return SCIP_OKAY;
4574 
4575       while( nbdchgs > 0 )
4576       {
4577          assert(SCIPsetIsGE(set, relaxedbd, SCIPbdchginfoGetNewbound(bdchginfo)));
4578 
4579          /* check if the old upper bound is smaller than or equal to the relaxed upper bound; if not we found the
4580           * bound change info which we need to report
4581           */
4582          if( SCIPsetIsLT(set, relaxedbd, SCIPbdchginfoGetOldbound(bdchginfo)) )
4583             break;
4584 
4585          bdchginfo = SCIPvarGetBdchgInfoUb(var, nbdchgs-1);
4586 
4587          SCIPsetDebugMsg(set, "upper bound change %d oldbd=%.15g, newbd=%.15g, depth=%d, pos=%d, redundant=%u\n",
4588             nbdchgs, SCIPbdchginfoGetOldbound(bdchginfo), SCIPbdchginfoGetNewbound(bdchginfo),
4589             SCIPbdchginfoGetDepth(bdchginfo), SCIPbdchginfoGetPos(bdchginfo),
4590             SCIPbdchginfoIsRedundant(bdchginfo));
4591 
4592          /* if bound change is redundant (this means it now a global bound), we can ignore the conflicting bound */
4593          if( SCIPbdchginfoIsRedundant(bdchginfo) )
4594             return SCIP_OKAY;
4595 
4596          nbdchgs--;
4597       }
4598       assert(SCIPsetIsLT(set, relaxedbd, SCIPbdchginfoGetOldbound(bdchginfo)));
4599    }
4600 
4601    assert(SCIPbdchgidxIsEarlier(SCIPbdchginfoGetIdx(bdchginfo), bdchgidx));
4602 
4603    /* put bound change information into priority queue */
4604    SCIP_CALL( conflictAddBound(conflict, blkmem, set, stat, var, boundtype, bdchginfo, relaxedbd) );
4605 
4606    return SCIP_OKAY;
4607 }
4608 
4609 /** checks if the given variable is already part of the current conflict set or queued for resolving with the same or
4610  *  even stronger bound
4611  */
SCIPconflictIsVarUsed(SCIP_CONFLICT * conflict,SCIP_VAR * var,SCIP_SET * set,SCIP_BOUNDTYPE boundtype,SCIP_BDCHGIDX * bdchgidx,SCIP_Bool * used)4612 SCIP_RETCODE SCIPconflictIsVarUsed(
4613    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
4614    SCIP_VAR*             var,                /**< problem variable */
4615    SCIP_SET*             set,                /**< global SCIP settings */
4616    SCIP_BOUNDTYPE        boundtype,          /**< type of bound for which the score should be increased */
4617    SCIP_BDCHGIDX*        bdchgidx,           /**< bound change index (time stamp of bound change), or NULL for current time */
4618    SCIP_Bool*            used                /**< pointer to store if the variable is already used */
4619    )
4620 {
4621    SCIP_Real newbound;
4622 
4623    /* convert bound to active problem variable */
4624    SCIP_CALL( convertToActiveVar(&var, set, &boundtype, NULL) );
4625 
4626    if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED || SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR )
4627       *used = FALSE;
4628    else
4629    {
4630       assert(SCIPvarIsActive(var));
4631       assert(var != NULL);
4632 
4633       switch( boundtype )
4634       {
4635       case SCIP_BOUNDTYPE_LOWER:
4636 
4637          newbound = SCIPgetVarLbAtIndex(set->scip, var, bdchgidx, FALSE);
4638 
4639          if( var->conflictlbcount == conflict->count && var->conflictlb >= newbound )
4640          {
4641             SCIPsetDebugMsg(set, "already queued bound change <%s> >= %g\n", SCIPvarGetName(var), newbound);
4642             *used = TRUE;
4643          }
4644          else
4645             *used = FALSE;
4646          break;
4647       case SCIP_BOUNDTYPE_UPPER:
4648 
4649          newbound = SCIPgetVarUbAtIndex(set->scip, var, bdchgidx, FALSE);
4650 
4651          if( var->conflictubcount == conflict->count && var->conflictub <= newbound )
4652          {
4653             SCIPsetDebugMsg(set, "already queued bound change <%s> <= %g\n", SCIPvarGetName(var), newbound);
4654             *used = TRUE;
4655          }
4656          else
4657             *used = FALSE;
4658          break;
4659       default:
4660          SCIPerrorMessage("invalid bound type %d\n", boundtype);
4661          SCIPABORT();
4662          *used = FALSE; /*lint !e527*/
4663       }
4664    }
4665 
4666    return SCIP_OKAY;
4667 }
4668 
4669 /** returns the conflict lower bound if the variable is present in the current conflict set; otherwise the global lower
4670  *  bound
4671  */
SCIPconflictGetVarLb(SCIP_CONFLICT * conflict,SCIP_VAR * var)4672 SCIP_Real SCIPconflictGetVarLb(
4673    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
4674    SCIP_VAR*             var                 /**< problem variable */
4675    )
4676 {
4677    if( var->conflictlbcount == conflict->count )
4678    {
4679       assert(EPSGE(var->conflictlb, var->conflictrelaxedlb, 1e-09));
4680       return var->conflictrelaxedlb;
4681    }
4682 
4683    return SCIPvarGetLbGlobal(var);
4684 }
4685 
4686 /** returns the conflict upper bound if the variable is present in the current conflict set; otherwise the global upper
4687  *  bound
4688  */
SCIPconflictGetVarUb(SCIP_CONFLICT * conflict,SCIP_VAR * var)4689 SCIP_Real SCIPconflictGetVarUb(
4690    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
4691    SCIP_VAR*             var                 /**< problem variable */
4692    )
4693 {
4694    if( var->conflictubcount == conflict->count )
4695    {
4696       assert(EPSLE(var->conflictub, var->conflictrelaxedub, 1e-09));
4697       return var->conflictrelaxedub;
4698    }
4699 
4700    return SCIPvarGetUbGlobal(var);
4701 }
4702 
4703 /** removes and returns next conflict analysis candidate from the candidate queue */
4704 static
conflictRemoveCand(SCIP_CONFLICT * conflict)4705 SCIP_BDCHGINFO* conflictRemoveCand(
4706    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
4707    )
4708 {
4709    SCIP_BDCHGINFO* bdchginfo;
4710    SCIP_VAR* var;
4711 
4712    assert(conflict != NULL);
4713 
4714    if( SCIPpqueueNElems(conflict->forcedbdchgqueue) > 0 )
4715       bdchginfo = (SCIP_BDCHGINFO*)(SCIPpqueueRemove(conflict->forcedbdchgqueue));
4716    else
4717       bdchginfo = (SCIP_BDCHGINFO*)(SCIPpqueueRemove(conflict->bdchgqueue));
4718 
4719    assert(!SCIPbdchginfoIsRedundant(bdchginfo));
4720 
4721    /* if we have a candidate this one should be valid for the current conflict analysis */
4722    assert(!bdchginfoIsInvalid(conflict, bdchginfo));
4723 
4724    /* mark the bound change to be no longer in the conflict (it will be either added again to the conflict set or
4725     * replaced by resolving, which might add a weaker change on the same bound to the queue)
4726     */
4727    var = SCIPbdchginfoGetVar(bdchginfo);
4728    if( SCIPbdchginfoGetBoundtype(bdchginfo) == SCIP_BOUNDTYPE_LOWER )
4729    {
4730       var->conflictlbcount = 0;
4731       var->conflictrelaxedlb = SCIP_REAL_MIN;
4732    }
4733    else
4734    {
4735       assert(SCIPbdchginfoGetBoundtype(bdchginfo) == SCIP_BOUNDTYPE_UPPER);
4736       var->conflictubcount = 0;
4737       var->conflictrelaxedub = SCIP_REAL_MAX;
4738    }
4739 
4740 #ifdef SCIP_CONFGRAPH
4741    confgraphSetCurrentBdchg(bdchginfo);
4742 #endif
4743 
4744    return bdchginfo;
4745 }
4746 
4747 /** returns next conflict analysis candidate from the candidate queue without removing it */
4748 static
conflictFirstCand(SCIP_CONFLICT * conflict)4749 SCIP_BDCHGINFO* conflictFirstCand(
4750    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
4751    )
4752 {
4753    SCIP_BDCHGINFO* bdchginfo;
4754 
4755    assert(conflict != NULL);
4756 
4757    if( SCIPpqueueNElems(conflict->forcedbdchgqueue) > 0 )
4758    {
4759       /* get next potetioal candidate */
4760       bdchginfo = (SCIP_BDCHGINFO*)(SCIPpqueueFirst(conflict->forcedbdchgqueue));
4761 
4762       /* check if this candidate is valid */
4763       if( bdchginfoIsInvalid(conflict, bdchginfo) )
4764       {
4765          SCIPdebugMessage("bound change info [%d:<%s> %s %g] is invaild -> pop it from the force queue\n", SCIPbdchginfoGetDepth(bdchginfo),
4766             SCIPvarGetName(SCIPbdchginfoGetVar(bdchginfo)),
4767             SCIPbdchginfoGetBoundtype(bdchginfo) == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=",
4768             SCIPbdchginfoGetNewbound(bdchginfo));
4769 
4770          /* pop the invalid bound change info from the queue */
4771          (void)(SCIPpqueueRemove(conflict->forcedbdchgqueue));
4772 
4773          /* call method recursively to get next conflict analysis candidate */
4774          bdchginfo = conflictFirstCand(conflict);
4775       }
4776    }
4777    else
4778    {
4779       bdchginfo = (SCIP_BDCHGINFO*)(SCIPpqueueFirst(conflict->bdchgqueue));
4780 
4781       /* check if this candidate is valid */
4782       if( bdchginfo != NULL && bdchginfoIsInvalid(conflict, bdchginfo) )
4783       {
4784          SCIPdebugMessage("bound change info [%d:<%s> %s %g] is invaild -> pop it from the queue\n", SCIPbdchginfoGetDepth(bdchginfo),
4785             SCIPvarGetName(SCIPbdchginfoGetVar(bdchginfo)),
4786             SCIPbdchginfoGetBoundtype(bdchginfo) == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=",
4787             SCIPbdchginfoGetNewbound(bdchginfo));
4788 
4789          /* pop the invalid bound change info from the queue */
4790          (void)(SCIPpqueueRemove(conflict->bdchgqueue));
4791 
4792          /* call method recursively to get next conflict analysis candidate */
4793          bdchginfo = conflictFirstCand(conflict);
4794       }
4795    }
4796    assert(bdchginfo == NULL || !SCIPbdchginfoIsRedundant(bdchginfo));
4797 
4798    return bdchginfo;
4799 }
4800 
4801 /** adds the current conflict set (extended by all remaining bound changes in the queue) to the pool of conflict sets */
4802 static
conflictAddConflictset(SCIP_CONFLICT * conflict,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_TREE * tree,int validdepth,SCIP_Bool diving,SCIP_Bool repropagate,SCIP_Bool * success,int * nliterals)4803 SCIP_RETCODE conflictAddConflictset(
4804    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
4805    BMS_BLKMEM*           blkmem,             /**< block memory of transformed problem */
4806    SCIP_SET*             set,                /**< global SCIP settings */
4807    SCIP_STAT*            stat,               /**< dynamic problem statistics */
4808    SCIP_TREE*            tree,               /**< branch and bound tree */
4809    int                   validdepth,         /**< minimal depth level at which the conflict set is valid */
4810    SCIP_Bool             diving,             /**< are we in strong branching or diving mode? */
4811    SCIP_Bool             repropagate,        /**< should the constraint trigger a repropagation? */
4812    SCIP_Bool*            success,            /**< pointer to store whether the conflict set is valid */
4813    int*                  nliterals           /**< pointer to store the number of literals in the generated conflictset */
4814    )
4815 {
4816    SCIP_CONFLICTSET* conflictset;
4817    SCIP_BDCHGINFO** bdchginfos;
4818    int nbdchginfos;
4819    int currentdepth;
4820    int focusdepth;
4821 
4822    assert(conflict != NULL);
4823    assert(conflict->conflictset != NULL);
4824    assert(set != NULL);
4825    assert(stat != NULL);
4826    assert(tree != NULL);
4827    assert(success != NULL);
4828    assert(nliterals != NULL);
4829    assert(SCIPpqueueNElems(conflict->forcedbdchgqueue) == 0);
4830 
4831    *success = FALSE;
4832    *nliterals = 0;
4833 
4834    /* check, whether local conflicts are allowed */
4835    validdepth = MAX(validdepth, conflict->conflictset->validdepth);
4836    if( !set->conf_allowlocal && validdepth > 0 )
4837       return SCIP_OKAY;
4838 
4839    focusdepth = SCIPtreeGetFocusDepth(tree);
4840    currentdepth = SCIPtreeGetCurrentDepth(tree);
4841    assert(currentdepth == tree->pathlen-1);
4842    assert(focusdepth <= currentdepth);
4843    assert(0 <= conflict->conflictset->validdepth && conflict->conflictset->validdepth <= currentdepth);
4844    assert(0 <= validdepth && validdepth <= currentdepth);
4845 
4846    /* get the elements of the bound change queue */
4847    bdchginfos = (SCIP_BDCHGINFO**)SCIPpqueueElems(conflict->bdchgqueue);
4848    nbdchginfos = SCIPpqueueNElems(conflict->bdchgqueue);
4849 
4850    /* create a copy of the current conflict set, allocating memory for the additional elements of the queue */
4851    SCIP_CALL( conflictsetCopy(&conflictset, blkmem, conflict->conflictset, nbdchginfos) );
4852    conflictset->validdepth = validdepth;
4853    conflictset->repropagate = repropagate;
4854 
4855    /* add the valid queue elements to the conflict set  */
4856    SCIPsetDebugMsg(set, "adding %d variables from the queue as temporary conflict variables\n", nbdchginfos);
4857    SCIP_CALL( conflictsetAddBounds(conflict, conflictset, blkmem, set, bdchginfos, nbdchginfos) );
4858 
4859    /* calculate the depth, at which the conflictset should be inserted */
4860    SCIP_CALL( conflictsetCalcInsertDepth(conflictset, set, tree) );
4861    assert(conflictset->validdepth <= conflictset->insertdepth && conflictset->insertdepth <= currentdepth);
4862    SCIPsetDebugMsg(set, " -> conflict with %d literals found at depth %d is active in depth %d and valid in depth %d\n",
4863       conflictset->nbdchginfos, currentdepth, conflictset->insertdepth, conflictset->validdepth);
4864 
4865    /* if all branching variables are in the conflict set, the conflict set is of no use;
4866     * don't use conflict sets that are only valid in the probing path but not in the problem tree
4867     */
4868    if( (diving || conflictset->insertdepth < currentdepth) && conflictset->insertdepth <= focusdepth )
4869    {
4870       /* if the conflict should not be located only in the subtree where it is useful, put it to its valid depth level */
4871       if( !set->conf_settlelocal )
4872          conflictset->insertdepth = conflictset->validdepth;
4873 
4874       *nliterals = conflictset->nbdchginfos;
4875       SCIPsetDebugMsg(set, " -> final conflict set has %d literals\n", *nliterals);
4876 
4877       /* check conflict set on debugging solution */
4878       SCIP_CALL( SCIPdebugCheckConflict(blkmem, set, tree->path[validdepth], \
4879             conflictset->bdchginfos, conflictset->relaxedbds, conflictset->nbdchginfos) ); /*lint !e506 !e774*/
4880 
4881       /* move conflictset to the conflictset storage */
4882       SCIP_CALL( conflictInsertConflictset(conflict, blkmem, set, &conflictset) );
4883       *success = TRUE;
4884    }
4885    else
4886    {
4887       /* free the temporary conflict set */
4888       conflictsetFree(&conflictset, blkmem);
4889    }
4890 
4891    return SCIP_OKAY;
4892 }
4893 
4894 /** tries to resolve given bound change
4895  *   - resolutions on local constraints are only applied, if the constraint is valid at the
4896  *     current minimal valid depth level, because this depth level is the topmost level to add the conflict
4897  *     constraint to anyways
4898  *
4899  *  @note it is sufficient to explain the relaxed bound change
4900  */
4901 static
conflictResolveBound(SCIP_CONFLICT * conflict,SCIP_SET * set,SCIP_BDCHGINFO * bdchginfo,SCIP_Real relaxedbd,int validdepth,SCIP_Bool * resolved)4902 SCIP_RETCODE conflictResolveBound(
4903    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
4904    SCIP_SET*             set,                /**< global SCIP settings */
4905    SCIP_BDCHGINFO*       bdchginfo,          /**< bound change to resolve */
4906    SCIP_Real             relaxedbd,          /**< the relaxed bound */
4907    int                   validdepth,         /**< minimal depth level at which the conflict is valid */
4908    SCIP_Bool*            resolved            /**< pointer to store whether the bound change was resolved */
4909    )
4910 {
4911    SCIP_VAR* actvar;
4912    SCIP_CONS* infercons;
4913    SCIP_PROP* inferprop;
4914    SCIP_RESULT result;
4915 
4916 #ifndef NDEBUG
4917    int nforcedbdchgqueue;
4918    int nbdchgqueue;
4919 
4920    /* store the current size of the conflict queues */
4921    assert(conflict != NULL);
4922    nforcedbdchgqueue = SCIPpqueueNElems(conflict->forcedbdchgqueue);
4923    nbdchgqueue = SCIPpqueueNElems(conflict->bdchgqueue);
4924 #else
4925    assert(conflict != NULL);
4926 #endif
4927 
4928    assert(resolved != NULL);
4929    assert(!SCIPbdchginfoIsRedundant(bdchginfo));
4930 
4931    *resolved = FALSE;
4932 
4933    actvar = SCIPbdchginfoGetVar(bdchginfo);
4934    assert(actvar != NULL);
4935    assert(SCIPvarIsActive(actvar));
4936 
4937 #ifdef SCIP_DEBUG
4938    {
4939       int i;
4940       SCIPsetDebugMsg(set, "processing next conflicting bound (depth: %d, valid depth: %d, bdchgtype: %s [%s], vartype: %d): [<%s> %s %g(%g)]\n",
4941          SCIPbdchginfoGetDepth(bdchginfo), validdepth,
4942          SCIPbdchginfoGetChgtype(bdchginfo) == SCIP_BOUNDCHGTYPE_BRANCHING ? "branch"
4943             : SCIPbdchginfoGetChgtype(bdchginfo) == SCIP_BOUNDCHGTYPE_CONSINFER ? "cons" : "prop",
4944                SCIPbdchginfoGetChgtype(bdchginfo) == SCIP_BOUNDCHGTYPE_BRANCHING ? "-"
4945                         : SCIPbdchginfoGetChgtype(bdchginfo) == SCIP_BOUNDCHGTYPE_CONSINFER
4946                           ? SCIPconsGetName(SCIPbdchginfoGetInferCons(bdchginfo))
4947                                 : SCIPbdchginfoGetInferProp(bdchginfo) == NULL ? "-"
4948                                       : SCIPpropGetName(SCIPbdchginfoGetInferProp(bdchginfo)),
4949                                         SCIPvarGetType(actvar), SCIPvarGetName(actvar),
4950                                         SCIPbdchginfoGetBoundtype(bdchginfo) == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=",
4951                                               SCIPbdchginfoGetNewbound(bdchginfo), relaxedbd);
4952       SCIPsetDebugMsg(set, " - conflict set       :");
4953 
4954       for( i = 0; i < conflict->conflictset->nbdchginfos; ++i )
4955       {
4956          SCIPsetDebugMsgPrint(set, " [%d:<%s> %s %g(%g)]", SCIPbdchginfoGetDepth(conflict->conflictset->bdchginfos[i]),
4957                SCIPvarGetName(SCIPbdchginfoGetVar(conflict->conflictset->bdchginfos[i])),
4958                SCIPbdchginfoGetBoundtype(conflict->conflictset->bdchginfos[i]) == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=",
4959                      SCIPbdchginfoGetNewbound(conflict->conflictset->bdchginfos[i]), conflict->conflictset->relaxedbds[i]);
4960       }
4961       SCIPsetDebugMsgPrint(set, "\n");
4962       SCIPsetDebugMsg(set, " - forced candidates  :");
4963 
4964       for( i = 0; i < SCIPpqueueNElems(conflict->forcedbdchgqueue); ++i )
4965       {
4966          SCIP_BDCHGINFO* info = (SCIP_BDCHGINFO*)(SCIPpqueueElems(conflict->forcedbdchgqueue)[i]);
4967          SCIPsetDebugMsgPrint(set, " [%d:<%s> %s %g(%g)]", SCIPbdchginfoGetDepth(info), SCIPvarGetName(SCIPbdchginfoGetVar(info)),
4968                bdchginfoIsInvalid(conflict, info) ? "<!>" : SCIPbdchginfoGetBoundtype(info) == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=",
4969                      SCIPbdchginfoGetNewbound(info), SCIPbdchginfoGetRelaxedBound(info));
4970       }
4971       SCIPsetDebugMsgPrint(set, "\n");
4972       SCIPsetDebugMsg(set, " - optional candidates:");
4973 
4974       for( i = 0; i < SCIPpqueueNElems(conflict->bdchgqueue); ++i )
4975       {
4976          SCIP_BDCHGINFO* info = (SCIP_BDCHGINFO*)(SCIPpqueueElems(conflict->bdchgqueue)[i]);
4977          SCIPsetDebugMsgPrint(set, " [%d:<%s> %s %g(%g)]", SCIPbdchginfoGetDepth(info), SCIPvarGetName(SCIPbdchginfoGetVar(info)),
4978                bdchginfoIsInvalid(conflict, info) ? "<!>" : SCIPbdchginfoGetBoundtype(info) == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=",
4979                      SCIPbdchginfoGetNewbound(info), SCIPbdchginfoGetRelaxedBound(info));
4980       }
4981       SCIPsetDebugMsgPrint(set, "\n");
4982    }
4983 #endif
4984 
4985    /* check, if the bound change can and should be resolved:
4986     *  - resolutions on local constraints should only be applied, if the constraint is valid at the
4987     *    current minimal valid depth level (which is initialized with the valid depth level of the initial
4988     *    conflict set), because this depth level is the topmost level to add the conflict constraint to anyways
4989     */
4990    switch( SCIPbdchginfoGetChgtype(bdchginfo) )
4991    {
4992    case SCIP_BOUNDCHGTYPE_CONSINFER:
4993       infercons = SCIPbdchginfoGetInferCons(bdchginfo);
4994       assert(infercons != NULL);
4995 
4996       if( SCIPconsIsGlobal(infercons) || SCIPconsGetValidDepth(infercons) <= validdepth )
4997       {
4998          SCIP_VAR* infervar;
4999          int inferinfo;
5000          SCIP_BOUNDTYPE inferboundtype;
5001          SCIP_BDCHGIDX* bdchgidx;
5002 
5003          /* resolve bound change by asking the constraint that infered the bound to put all bounds that were
5004           * the reasons for the conflicting bound change on the priority queue
5005           */
5006          infervar = SCIPbdchginfoGetInferVar(bdchginfo);
5007          inferinfo = SCIPbdchginfoGetInferInfo(bdchginfo);
5008          inferboundtype = SCIPbdchginfoGetInferBoundtype(bdchginfo);
5009          bdchgidx = SCIPbdchginfoGetIdx(bdchginfo);
5010          assert(infervar != NULL);
5011 
5012          SCIPsetDebugMsg(set, "resolving bound <%s> %s %g(%g) [status:%d, type:%d, depth:%d, pos:%d]: <%s> %s %g [cons:<%s>(%s), info:%d]\n",
5013             SCIPvarGetName(actvar),
5014             SCIPbdchginfoGetBoundtype(bdchginfo) == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=",
5015             SCIPbdchginfoGetNewbound(bdchginfo), relaxedbd,
5016             SCIPvarGetStatus(actvar), SCIPvarGetType(actvar),
5017             SCIPbdchginfoGetDepth(bdchginfo), SCIPbdchginfoGetPos(bdchginfo),
5018             SCIPvarGetName(infervar),
5019             inferboundtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=",
5020             SCIPgetVarBdAtIndex(set->scip, infervar, inferboundtype, bdchgidx, TRUE),
5021             SCIPconsGetName(infercons),
5022             SCIPconsIsGlobal(infercons) ? "global" : "local",
5023             inferinfo);
5024 
5025          /* in case the inference variables is not an active variables, we need to transform the relaxed bound */
5026          if( actvar != infervar )
5027          {
5028             SCIP_VAR* var;
5029             SCIP_Real scalar;
5030             SCIP_Real constant;
5031 
5032             assert(SCIPvarGetStatus(infervar) == SCIP_VARSTATUS_AGGREGATED
5033                || SCIPvarGetStatus(infervar) == SCIP_VARSTATUS_NEGATED
5034                || (SCIPvarGetStatus(infervar) == SCIP_VARSTATUS_MULTAGGR && SCIPvarGetMultaggrNVars(infervar) == 1));
5035 
5036             scalar = 1.0;
5037             constant = 0.0;
5038 
5039             var = infervar;
5040 
5041             /* transform given varibale to active varibale */
5042             SCIP_CALL( SCIPvarGetProbvarSum(&var, set, &scalar, &constant) );
5043             assert(var == actvar);
5044 
5045             relaxedbd *= scalar;
5046             relaxedbd += constant;
5047          }
5048 
5049          SCIP_CALL( SCIPconsResolvePropagation(infercons, set, infervar, inferinfo, inferboundtype, bdchgidx, relaxedbd, &result) );
5050          *resolved = (result == SCIP_SUCCESS);
5051       }
5052       break;
5053 
5054    case SCIP_BOUNDCHGTYPE_PROPINFER:
5055       inferprop = SCIPbdchginfoGetInferProp(bdchginfo);
5056       if( inferprop != NULL )
5057       {
5058          SCIP_VAR* infervar;
5059          int inferinfo;
5060          SCIP_BOUNDTYPE inferboundtype;
5061          SCIP_BDCHGIDX* bdchgidx;
5062 
5063          /* resolve bound change by asking the propagator that infered the bound to put all bounds that were
5064           * the reasons for the conflicting bound change on the priority queue
5065           */
5066          infervar = SCIPbdchginfoGetInferVar(bdchginfo);
5067          inferinfo = SCIPbdchginfoGetInferInfo(bdchginfo);
5068          inferboundtype = SCIPbdchginfoGetInferBoundtype(bdchginfo);
5069          bdchgidx = SCIPbdchginfoGetIdx(bdchginfo);
5070          assert(infervar != NULL);
5071 
5072          SCIPsetDebugMsg(set, "resolving bound <%s> %s %g(%g) [status:%d, depth:%d, pos:%d]: <%s> %s %g [prop:<%s>, info:%d]\n",
5073             SCIPvarGetName(actvar),
5074             SCIPbdchginfoGetBoundtype(bdchginfo) == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=",
5075             SCIPbdchginfoGetNewbound(bdchginfo), relaxedbd,
5076             SCIPvarGetStatus(actvar), SCIPbdchginfoGetDepth(bdchginfo), SCIPbdchginfoGetPos(bdchginfo),
5077             SCIPvarGetName(infervar),
5078             inferboundtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=",
5079             SCIPgetVarBdAtIndex(set->scip, infervar, inferboundtype, bdchgidx, TRUE),
5080             SCIPpropGetName(inferprop), inferinfo);
5081 
5082          SCIP_CALL( SCIPpropResolvePropagation(inferprop, set, infervar, inferinfo, inferboundtype, bdchgidx, relaxedbd, &result) );
5083          *resolved = (result == SCIP_SUCCESS);
5084       }
5085       break;
5086 
5087    case SCIP_BOUNDCHGTYPE_BRANCHING:
5088       assert(!(*resolved));
5089       break;
5090 
5091    default:
5092       SCIPerrorMessage("invalid bound change type <%d>\n", SCIPbdchginfoGetChgtype(bdchginfo));
5093       return SCIP_INVALIDDATA;
5094    }
5095 
5096    SCIPsetDebugMsg(set, "resolving status: %u\n", *resolved);
5097 
5098 #ifndef NDEBUG
5099    /* subtract the size of the conflicq queues */
5100    nforcedbdchgqueue -= SCIPpqueueNElems(conflict->forcedbdchgqueue);
5101    nbdchgqueue -= SCIPpqueueNElems(conflict->bdchgqueue);
5102 
5103    /* in case the bound change was not resolved, the conflict queues should have the same size (contents) */
5104    assert((*resolved) || (nforcedbdchgqueue == 0 && nbdchgqueue == 0));
5105 #endif
5106 
5107    return SCIP_OKAY;
5108 }
5109 
5110 /** if only one conflicting bound change of the last depth level was used, and if this can be resolved,
5111  *  creates GRASP-like reconvergence conflict constraints in the conflict graph up to the branching variable of this
5112  *  depth level
5113  */
5114 static
conflictCreateReconvergenceConss(SCIP_CONFLICT * conflict,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * prob,SCIP_TREE * tree,SCIP_Bool diving,int validdepth,SCIP_BDCHGINFO * firstuip,int * nreconvconss,int * nreconvliterals)5115 SCIP_RETCODE conflictCreateReconvergenceConss(
5116    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
5117    BMS_BLKMEM*           blkmem,             /**< block memory of transformed problem */
5118    SCIP_SET*             set,                /**< global SCIP settings */
5119    SCIP_STAT*            stat,               /**< problem statistics */
5120    SCIP_PROB*            prob,               /**< problem data */
5121    SCIP_TREE*            tree,               /**< branch and bound tree */
5122    SCIP_Bool             diving,             /**< are we in strong branching or diving mode? */
5123    int                   validdepth,         /**< minimal depth level at which the initial conflict set is valid */
5124    SCIP_BDCHGINFO*       firstuip,           /**< first UIP of conflict graph */
5125    int*                  nreconvconss,       /**< pointer to store the number of generated reconvergence constraints */
5126    int*                  nreconvliterals     /**< pointer to store the number of literals generated reconvergence constraints */
5127    )
5128 {
5129    SCIP_BDCHGINFO* uip;
5130    SCIP_CONFTYPE conftype;
5131    SCIP_Bool usescutoffbound;
5132    int firstuipdepth;
5133    int focusdepth;
5134    int currentdepth;
5135    int maxvaliddepth;
5136 
5137    assert(conflict != NULL);
5138    assert(firstuip != NULL);
5139    assert(nreconvconss != NULL);
5140    assert(nreconvliterals != NULL);
5141    assert(!SCIPbdchginfoIsRedundant(firstuip));
5142 
5143    focusdepth = SCIPtreeGetFocusDepth(tree);
5144    currentdepth = SCIPtreeGetCurrentDepth(tree);
5145    assert(currentdepth == tree->pathlen-1);
5146    assert(focusdepth <= currentdepth);
5147 
5148    /* check, whether local constraints are allowed; however, don't generate reconvergence constraints that are only valid
5149     * in the probing path and not in the problem tree (i.e. that exceed the focusdepth)
5150     */
5151    maxvaliddepth = (set->conf_allowlocal ? MIN(currentdepth-1, focusdepth) : 0);
5152    if( validdepth > maxvaliddepth )
5153       return SCIP_OKAY;
5154 
5155    firstuipdepth = SCIPbdchginfoGetDepth(firstuip);
5156 
5157    conftype = conflict->conflictset->conflicttype;
5158    usescutoffbound = conflict->conflictset->usescutoffbound;
5159 
5160    /* for each succeeding UIP pair of the last depth level, create one reconvergence constraint */
5161    uip = firstuip;
5162    while( uip != NULL && SCIPbdchginfoGetDepth(uip) == SCIPbdchginfoGetDepth(firstuip) && bdchginfoIsResolvable(uip) )
5163    {
5164       SCIP_BDCHGINFO* oppositeuip;
5165       SCIP_BDCHGINFO* bdchginfo;
5166       SCIP_BDCHGINFO* nextuip;
5167       SCIP_VAR* uipvar;
5168       SCIP_Real oppositeuipbound;
5169       SCIP_BOUNDTYPE oppositeuipboundtype;
5170       int nresolutions;
5171 
5172       assert(!SCIPbdchginfoIsRedundant(uip));
5173 
5174       SCIPsetDebugMsg(set, "creating reconvergence constraint for UIP <%s> %s %g in depth %d pos %d\n",
5175          SCIPvarGetName(SCIPbdchginfoGetVar(uip)), SCIPbdchginfoGetBoundtype(uip) == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=",
5176          SCIPbdchginfoGetNewbound(uip), SCIPbdchginfoGetDepth(uip), SCIPbdchginfoGetPos(uip));
5177 
5178       /* initialize conflict data */
5179       SCIP_CALL( SCIPconflictInit(conflict, set, stat, prob, conftype, usescutoffbound) );
5180 
5181       conflict->conflictset->conflicttype = conftype;
5182       conflict->conflictset->usescutoffbound = usescutoffbound;
5183 
5184       /* create a temporary bound change information for the negation of the UIP's bound change;
5185        * this bound change information is freed in the SCIPconflictFlushConss() call;
5186        * for reconvergence constraints for continuous variables we can only use the "negation" !(x <= u) == (x >= u);
5187        * during conflict analysis, we treat a continuous bound "x >= u" in the conflict set as "x > u", and in the
5188        * generated constraint this is negated again to "x <= u" which is correct.
5189        */
5190       uipvar = SCIPbdchginfoGetVar(uip);
5191       oppositeuipboundtype = SCIPboundtypeOpposite(SCIPbdchginfoGetBoundtype(uip));
5192       oppositeuipbound = SCIPbdchginfoGetNewbound(uip);
5193       if( SCIPvarIsIntegral(uipvar) )
5194       {
5195          assert(SCIPsetIsIntegral(set, oppositeuipbound));
5196          oppositeuipbound += (oppositeuipboundtype == SCIP_BOUNDTYPE_LOWER ? +1.0 : -1.0);
5197       }
5198       SCIP_CALL( conflictCreateTmpBdchginfo(conflict, blkmem, set, uipvar, oppositeuipboundtype, \
5199             oppositeuipboundtype == SCIP_BOUNDTYPE_LOWER ? SCIP_REAL_MIN : SCIP_REAL_MAX, oppositeuipbound, &oppositeuip) );
5200 
5201       /* put the negated UIP into the conflict set */
5202       SCIP_CALL( conflictAddConflictBound(conflict, blkmem, set, oppositeuip, oppositeuipbound) );
5203 
5204       /* put positive UIP into priority queue */
5205       SCIP_CALL( conflictQueueBound(conflict, set, uip, SCIPbdchginfoGetNewbound(uip) ) );
5206 
5207       /* resolve the queue until the next UIP is reached */
5208       bdchginfo = conflictFirstCand(conflict);
5209       nextuip = NULL;
5210       nresolutions = 0;
5211       while( bdchginfo != NULL && validdepth <= maxvaliddepth )
5212       {
5213          SCIP_BDCHGINFO* nextbdchginfo;
5214          SCIP_Real relaxedbd;
5215          SCIP_Bool forceresolve;
5216          int bdchgdepth;
5217 
5218          /* check if the next bound change must be resolved in every case */
5219          forceresolve = (SCIPpqueueNElems(conflict->forcedbdchgqueue) > 0);
5220 
5221          /* remove currently processed candidate and get next conflicting bound from the conflict candidate queue before
5222           * we remove the candidate we have to collect the relaxed bound since removing the candidate from the queue
5223           * invalidates the relaxed bound
5224           */
5225          assert(bdchginfo == conflictFirstCand(conflict));
5226          relaxedbd = SCIPbdchginfoGetRelaxedBound(bdchginfo);
5227          bdchginfo = conflictRemoveCand(conflict);
5228          nextbdchginfo = conflictFirstCand(conflict);
5229          bdchgdepth = SCIPbdchginfoGetDepth(bdchginfo);
5230          assert(bdchginfo != NULL);
5231          assert(!SCIPbdchginfoIsRedundant(bdchginfo));
5232          assert(nextbdchginfo == NULL || SCIPbdchginfoGetDepth(bdchginfo) >= SCIPbdchginfoGetDepth(nextbdchginfo)
5233             || forceresolve);
5234          assert(bdchgdepth <= firstuipdepth);
5235 
5236          /* bound changes that are higher in the tree than the valid depth of the conflict can be ignored;
5237           * multiple insertions of the same bound change can be ignored
5238           */
5239          if( bdchgdepth > validdepth && bdchginfo != nextbdchginfo )
5240          {
5241             SCIP_VAR* actvar;
5242             SCIP_Bool resolved;
5243 
5244             actvar = SCIPbdchginfoGetVar(bdchginfo);
5245             assert(actvar != NULL);
5246             assert(SCIPvarIsActive(actvar));
5247 
5248             /* check if we have to resolve the bound change in this depth level
5249              *  - the starting uip has to be resolved
5250              *  - a bound change should be resolved, if it is in the fuip's depth level and not the
5251              *    next uip (i.e., if it is not the last bound change in the fuip's depth level)
5252              *  - a forced bound change must be resolved in any case
5253              */
5254             resolved = FALSE;
5255             if( bdchginfo == uip
5256                || (bdchgdepth == firstuipdepth
5257                   && nextbdchginfo != NULL
5258                   && SCIPbdchginfoGetDepth(nextbdchginfo) == bdchgdepth)
5259                || forceresolve )
5260             {
5261                SCIP_CALL( conflictResolveBound(conflict, set, bdchginfo, relaxedbd, validdepth, &resolved) );
5262             }
5263 
5264             if( resolved )
5265                nresolutions++;
5266             else if( forceresolve )
5267             {
5268                /* variable cannot enter the conflict clause: we have to make the conflict clause local, s.t.
5269                 * the unresolved bound change is active in the whole sub tree of the conflict clause
5270                 */
5271                assert(bdchgdepth >= validdepth);
5272                validdepth = bdchgdepth;
5273 
5274                SCIPsetDebugMsg(set, "couldn't resolve forced bound change on <%s> -> new valid depth: %d\n",
5275                   SCIPvarGetName(actvar), validdepth);
5276             }
5277             else if( bdchginfo != uip )
5278             {
5279                assert(conflict->conflictset != NULL);
5280                assert(conflict->conflictset->nbdchginfos >= 1); /* starting UIP is already member of the conflict set */
5281 
5282                /* if this is the first variable of the conflict set besides the current starting UIP, it is the next
5283                 * UIP (or the first unresolvable bound change)
5284                 */
5285                if( bdchgdepth == firstuipdepth && conflict->conflictset->nbdchginfos == 1 )
5286                {
5287                   assert(nextuip == NULL);
5288                   nextuip = bdchginfo;
5289                }
5290 
5291                /* put bound change into the conflict set */
5292                SCIP_CALL( conflictAddConflictBound(conflict, blkmem, set, bdchginfo, relaxedbd) );
5293                assert(conflict->conflictset->nbdchginfos >= 2);
5294             }
5295             else
5296                assert(conflictFirstCand(conflict) == NULL); /* the starting UIP was not resolved */
5297          }
5298 
5299          /* get next conflicting bound from the conflict candidate queue (this does not need to be nextbdchginfo, because
5300           * due to resolving the bound changes, a variable could be added to the queue which must be
5301           * resolved before nextbdchginfo)
5302           */
5303          bdchginfo = conflictFirstCand(conflict);
5304       }
5305       assert(nextuip != uip);
5306 
5307       /* if only one propagation was resolved, the reconvergence constraint is already member of the constraint set
5308        * (it is exactly the constraint that produced the propagation)
5309        */
5310       if( nextuip != NULL && nresolutions >= 2 && bdchginfo == NULL && validdepth <= maxvaliddepth )
5311       {
5312          int nlits;
5313          SCIP_Bool success;
5314 
5315          assert(SCIPbdchginfoGetDepth(nextuip) == SCIPbdchginfoGetDepth(uip));
5316 
5317          /* check conflict graph frontier on debugging solution */
5318          SCIP_CALL( SCIPdebugCheckConflictFrontier(blkmem, set, tree->path[validdepth], \
5319                bdchginfo, conflict->conflictset->bdchginfos, conflict->conflictset->relaxedbds, \
5320                conflict->conflictset->nbdchginfos, conflict->bdchgqueue, conflict->forcedbdchgqueue) ); /*lint !e506 !e774*/
5321 
5322          SCIPsetDebugMsg(set, "creating reconvergence constraint from UIP <%s> to UIP <%s> in depth %d with %d literals after %d resolutions\n",
5323             SCIPvarGetName(SCIPbdchginfoGetVar(uip)), SCIPvarGetName(SCIPbdchginfoGetVar(nextuip)),
5324             SCIPbdchginfoGetDepth(uip), conflict->conflictset->nbdchginfos, nresolutions);
5325 
5326          /* call the conflict handlers to create a conflict set */
5327          SCIP_CALL( conflictAddConflictset(conflict, blkmem, set, stat, tree, validdepth, diving, FALSE, &success, &nlits) );
5328          if( success )
5329          {
5330             (*nreconvconss)++;
5331             (*nreconvliterals) += nlits;
5332          }
5333       }
5334 
5335       /* clear the conflict candidate queue and the conflict set (to make sure, oppositeuip is not referenced anymore) */
5336       conflictClear(conflict);
5337 
5338       uip = nextuip;
5339    }
5340 
5341    conflict->conflictset->conflicttype = conftype;
5342    conflict->conflictset->usescutoffbound = usescutoffbound;
5343 
5344    return SCIP_OKAY;
5345 }
5346 
5347 /** analyzes conflicting bound changes that were added with calls to SCIPconflictAddBound() and
5348  *  SCIPconflictAddRelaxedBound(), and on success, calls the conflict handlers to create a conflict constraint out of
5349  *  the resulting conflict set; afterwards the conflict queue and the conflict set is cleared
5350  */
5351 static
conflictAnalyze(SCIP_CONFLICT * conflict,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * prob,SCIP_TREE * tree,SCIP_Bool diving,int validdepth,SCIP_Bool mustresolve,int * nconss,int * nliterals,int * nreconvconss,int * nreconvliterals)5352 SCIP_RETCODE conflictAnalyze(
5353    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
5354    BMS_BLKMEM*           blkmem,             /**< block memory of transformed problem */
5355    SCIP_SET*             set,                /**< global SCIP settings */
5356    SCIP_STAT*            stat,               /**< problem statistics */
5357    SCIP_PROB*            prob,               /**< problem data */
5358    SCIP_TREE*            tree,               /**< branch and bound tree */
5359    SCIP_Bool             diving,             /**< are we in strong branching or diving mode? */
5360    int                   validdepth,         /**< minimal depth level at which the initial conflict set is valid */
5361    SCIP_Bool             mustresolve,        /**< should the conflict set only be used, if a resolution was applied? */
5362    int*                  nconss,             /**< pointer to store the number of generated conflict constraints */
5363    int*                  nliterals,          /**< pointer to store the number of literals in generated conflict constraints */
5364    int*                  nreconvconss,       /**< pointer to store the number of generated reconvergence constraints */
5365    int*                  nreconvliterals     /**< pointer to store the number of literals generated reconvergence constraints */
5366    )
5367 {
5368    SCIP_BDCHGINFO* bdchginfo;
5369    SCIP_BDCHGINFO** firstuips;
5370    SCIP_CONFTYPE conftype;
5371    int nfirstuips;
5372    int focusdepth;
5373    int currentdepth;
5374    int maxvaliddepth;
5375    int resolvedepth;
5376    int nresolutions;
5377    int lastconsnresolutions;
5378    int lastconsresoldepth;
5379 
5380    assert(conflict != NULL);
5381    assert(conflict->conflictset != NULL);
5382    assert(conflict->conflictset->nbdchginfos >= 0);
5383    assert(set != NULL);
5384    assert(stat != NULL);
5385    assert(0 <= validdepth && validdepth <= SCIPtreeGetCurrentDepth(tree));
5386    assert(nconss != NULL);
5387    assert(nliterals != NULL);
5388    assert(nreconvconss != NULL);
5389    assert(nreconvliterals != NULL);
5390 
5391    focusdepth = SCIPtreeGetFocusDepth(tree);
5392    currentdepth = SCIPtreeGetCurrentDepth(tree);
5393    assert(currentdepth == tree->pathlen-1);
5394    assert(focusdepth <= currentdepth);
5395 
5396    resolvedepth = ((set->conf_fuiplevels >= 0 && set->conf_fuiplevels <= currentdepth)
5397       ? currentdepth - set->conf_fuiplevels + 1 : 0);
5398    assert(0 <= resolvedepth && resolvedepth <= currentdepth + 1);
5399 
5400    /* if we must resolve at least one bound change, find the first UIP at least in the last depth level */
5401    if( mustresolve )
5402       resolvedepth = MIN(resolvedepth, currentdepth);
5403 
5404    SCIPsetDebugMsg(set, "analyzing conflict with %d+%d conflict candidates and starting conflict set of size %d in depth %d (resolvedepth=%d)\n",
5405       SCIPpqueueNElems(conflict->forcedbdchgqueue), SCIPpqueueNElems(conflict->bdchgqueue),
5406       conflict->conflictset->nbdchginfos, currentdepth, resolvedepth);
5407 
5408    *nconss = 0;
5409    *nliterals = 0;
5410    *nreconvconss = 0;
5411    *nreconvliterals = 0;
5412 
5413    /* check, whether local conflicts are allowed; however, don't generate conflict constraints that are only valid in the
5414     * probing path and not in the problem tree (i.e. that exceed the focusdepth)
5415     */
5416    maxvaliddepth = (set->conf_allowlocal ? MIN(currentdepth-1, focusdepth) : 0);
5417    if( validdepth > maxvaliddepth )
5418       return SCIP_OKAY;
5419 
5420    /* allocate temporary memory for storing first UIPs (in each depth level, at most two bound changes can be flagged
5421     * as UIP, namely a binary and a non-binary bound change)
5422     */
5423    SCIP_CALL( SCIPsetAllocBufferArray(set, &firstuips, 2*(currentdepth+1)) ); /*lint !e647*/
5424 
5425    /* process all bound changes in the conflict candidate queue */
5426    nresolutions = 0;
5427    lastconsnresolutions = (mustresolve ? 0 : -1);
5428    lastconsresoldepth = (mustresolve ? currentdepth : INT_MAX);
5429    bdchginfo = conflictFirstCand(conflict);
5430    nfirstuips = 0;
5431 
5432    /* check if the initial reason on debugging solution */
5433    SCIP_CALL( SCIPdebugCheckConflictFrontier(blkmem, set, tree->path[validdepth], \
5434          NULL, conflict->conflictset->bdchginfos, conflict->conflictset->relaxedbds, conflict->conflictset->nbdchginfos, \
5435          conflict->bdchgqueue, conflict->forcedbdchgqueue) ); /*lint !e506 !e774*/
5436 
5437    while( bdchginfo != NULL && validdepth <= maxvaliddepth )
5438    {
5439       SCIP_BDCHGINFO* nextbdchginfo;
5440       SCIP_Real relaxedbd;
5441       SCIP_Bool forceresolve;
5442       int bdchgdepth;
5443 
5444       assert(!SCIPbdchginfoIsRedundant(bdchginfo));
5445 
5446       /* check if the next bound change must be resolved in every case */
5447       forceresolve = (SCIPpqueueNElems(conflict->forcedbdchgqueue) > 0);
5448 
5449       /* resolve next bound change in queue */
5450       bdchgdepth = SCIPbdchginfoGetDepth(bdchginfo);
5451       assert(0 <= bdchgdepth && bdchgdepth <= currentdepth);
5452       assert(SCIPvarIsActive(SCIPbdchginfoGetVar(bdchginfo)));
5453       assert(bdchgdepth < tree->pathlen);
5454       assert(tree->path[bdchgdepth] != NULL);
5455       assert(tree->path[bdchgdepth]->domchg != NULL);
5456       assert(SCIPbdchginfoGetPos(bdchginfo) < (int)tree->path[bdchgdepth]->domchg->domchgbound.nboundchgs);
5457       assert(tree->path[bdchgdepth]->domchg->domchgbound.boundchgs[SCIPbdchginfoGetPos(bdchginfo)].var
5458          == SCIPbdchginfoGetVar(bdchginfo));
5459       assert(tree->path[bdchgdepth]->domchg->domchgbound.boundchgs[SCIPbdchginfoGetPos(bdchginfo)].newbound
5460          == SCIPbdchginfoGetNewbound(bdchginfo)
5461          || (SCIPbdchginfoGetBoundtype(bdchginfo) == SCIP_BOUNDTYPE_LOWER
5462             ? SCIPvarGetLbGlobal(SCIPbdchginfoGetVar(bdchginfo)) : SCIPvarGetUbGlobal(SCIPbdchginfoGetVar(bdchginfo)))
5463          == SCIPbdchginfoGetNewbound(bdchginfo)); /*lint !e777*/
5464       assert((SCIP_BOUNDTYPE)tree->path[bdchgdepth]->domchg->domchgbound.boundchgs[SCIPbdchginfoGetPos(bdchginfo)].boundtype
5465          == SCIPbdchginfoGetBoundtype(bdchginfo));
5466 
5467       /* create intermediate conflict constraint */
5468       assert(nresolutions >= lastconsnresolutions);
5469       if( !forceresolve )
5470       {
5471          if( nresolutions == lastconsnresolutions )
5472             lastconsresoldepth = bdchgdepth; /* all intermediate depth levels consisted of only unresolved bound changes */
5473          else if( bdchgdepth < lastconsresoldepth && (set->conf_interconss == -1 || *nconss < set->conf_interconss) )
5474          {
5475             int nlits;
5476             SCIP_Bool success;
5477 
5478             /* call the conflict handlers to create a conflict set */
5479             SCIPsetDebugMsg(set, "creating intermediate conflictset after %d resolutions up to depth %d (valid at depth %d): %d conflict bounds, %d bounds in queue\n",
5480                nresolutions, bdchgdepth, validdepth, conflict->conflictset->nbdchginfos,
5481                SCIPpqueueNElems(conflict->bdchgqueue));
5482 
5483             SCIP_CALL( conflictAddConflictset(conflict, blkmem, set, stat, tree, validdepth, diving, TRUE, &success, &nlits) );
5484             lastconsnresolutions = nresolutions;
5485             lastconsresoldepth = bdchgdepth;
5486             if( success )
5487             {
5488                (*nconss)++;
5489                (*nliterals) += nlits;
5490             }
5491          }
5492       }
5493 
5494       /* remove currently processed candidate and get next conflicting bound from the conflict candidate queue before
5495        * we remove the candidate we have to collect the relaxed bound since removing the candidate from the queue
5496        * invalidates the relaxed bound
5497        */
5498       assert(bdchginfo == conflictFirstCand(conflict));
5499       relaxedbd = SCIPbdchginfoGetRelaxedBound(bdchginfo);
5500       bdchginfo = conflictRemoveCand(conflict);
5501       nextbdchginfo = conflictFirstCand(conflict);
5502       assert(bdchginfo != NULL);
5503       assert(!SCIPbdchginfoIsRedundant(bdchginfo));
5504       assert(nextbdchginfo == NULL || SCIPbdchginfoGetDepth(bdchginfo) >= SCIPbdchginfoGetDepth(nextbdchginfo)
5505          || forceresolve);
5506 
5507       /* we don't need to resolve bound changes that are already active in the valid depth of the current conflict set,
5508        * because the conflict set can only be added locally at the valid depth, and all bound changes applied in this
5509        * depth or earlier can be removed from the conflict constraint, since they are already applied in the constraint's
5510        * subtree;
5511        * if the next bound change on the remaining queue is equal to the current bound change,
5512        * this is a multiple insertion in the conflict candidate queue and we can ignore the current
5513        * bound change
5514        */
5515       if( bdchgdepth > validdepth && bdchginfo != nextbdchginfo )
5516       {
5517          SCIP_VAR* actvar;
5518          SCIP_Bool resolved;
5519 
5520          actvar = SCIPbdchginfoGetVar(bdchginfo);
5521          assert(actvar != NULL);
5522          assert(SCIPvarIsActive(actvar));
5523 
5524          /* check if we want to resolve the bound change in this depth level
5525           *  - bound changes should be resolved, if
5526           *     (i)   we must apply at least one resolution and didn't resolve a bound change yet, or
5527           *     (ii)  their depth level is at least equal to the minimal resolving depth, and
5528           *           they are not the last remaining conflicting bound change in their depth level
5529           *     (iii) the bound change resolving is forced (i.e., the forced queue was non-empty)
5530           */
5531          resolved = FALSE;
5532          if( (mustresolve && nresolutions == 0)
5533             || (bdchgdepth >= resolvedepth
5534                && nextbdchginfo != NULL
5535                && SCIPbdchginfoGetDepth(nextbdchginfo) == bdchgdepth)
5536             || forceresolve )
5537          {
5538             SCIP_CALL( conflictResolveBound(conflict, set, bdchginfo, relaxedbd, validdepth, &resolved) );
5539          }
5540 
5541          if( resolved )
5542             nresolutions++;
5543          else if( forceresolve )
5544          {
5545             /* variable cannot enter the conflict clause: we have to make the conflict clause local, s.t.
5546              * the unresolved bound change is active in the whole sub tree of the conflict clause
5547              */
5548             assert(bdchgdepth >= validdepth);
5549             validdepth = bdchgdepth;
5550 
5551             SCIPsetDebugMsg(set, "couldn't resolve forced bound change on <%s> -> new valid depth: %d\n",
5552                SCIPvarGetName(actvar), validdepth);
5553          }
5554          else
5555          {
5556             /* if this is a UIP (the last bound change in its depth level), it can be used to generate a
5557              * UIP reconvergence constraint
5558              */
5559             if( nextbdchginfo == NULL || SCIPbdchginfoGetDepth(nextbdchginfo) != bdchgdepth )
5560             {
5561                assert(nfirstuips < 2*(currentdepth+1));
5562                firstuips[nfirstuips] = bdchginfo;
5563                nfirstuips++;
5564             }
5565 
5566             /* put variable into the conflict set, using the literal that is currently fixed to FALSE */
5567             SCIP_CALL( conflictAddConflictBound(conflict, blkmem, set, bdchginfo, relaxedbd) );
5568          }
5569       }
5570 
5571       /* check conflict graph frontier on debugging solution */
5572       SCIP_CALL( SCIPdebugCheckConflictFrontier(blkmem, set, tree->path[validdepth], \
5573             bdchginfo, conflict->conflictset->bdchginfos, conflict->conflictset->relaxedbds, conflict->conflictset->nbdchginfos, \
5574             conflict->bdchgqueue, conflict->forcedbdchgqueue) ); /*lint !e506 !e774*/
5575 
5576       /* get next conflicting bound from the conflict candidate queue (this needs not to be nextbdchginfo, because
5577        * due to resolving the bound changes, a bound change could be added to the queue which must be
5578        * resolved before nextbdchginfo)
5579        */
5580       bdchginfo = conflictFirstCand(conflict);
5581    }
5582 
5583    /* check, if a valid conflict set was found */
5584    if( bdchginfo == NULL
5585       && nresolutions > lastconsnresolutions
5586       && validdepth <= maxvaliddepth
5587       && (!mustresolve || nresolutions > 0 || conflict->conflictset->nbdchginfos == 0)
5588       && SCIPpqueueNElems(conflict->forcedbdchgqueue) == 0 )
5589    {
5590       int nlits;
5591       SCIP_Bool success;
5592 
5593       /* call the conflict handlers to create a conflict set */
5594       SCIP_CALL( conflictAddConflictset(conflict, blkmem, set, stat, tree, validdepth, diving, TRUE, &success, &nlits) );
5595       if( success )
5596       {
5597          (*nconss)++;
5598          (*nliterals) += nlits;
5599       }
5600    }
5601 
5602    /* produce reconvergence constraints defined by succeeding UIP's of the last depth level */
5603    if( set->conf_reconvlevels != 0 && validdepth <= maxvaliddepth )
5604    {
5605       int reconvlevels;
5606       int i;
5607 
5608       reconvlevels = (set->conf_reconvlevels == -1 ? INT_MAX : set->conf_reconvlevels);
5609       for( i = 0; i < nfirstuips; ++i )
5610       {
5611          if( SCIPbdchginfoHasInferenceReason(firstuips[i])
5612             && currentdepth - SCIPbdchginfoGetDepth(firstuips[i]) < reconvlevels )
5613          {
5614             SCIP_CALL( conflictCreateReconvergenceConss(conflict, blkmem, set, stat, prob, tree, diving, \
5615                   validdepth, firstuips[i], nreconvconss, nreconvliterals) );
5616          }
5617       }
5618    }
5619 
5620    /* free the temporary memory */
5621    SCIPsetFreeBufferArray(set, &firstuips);
5622 
5623    /* store last conflict type */
5624    conftype = conflict->conflictset->conflicttype;
5625 
5626    /* clear the conflict candidate queue and the conflict set */
5627    conflictClear(conflict);
5628 
5629    /* restore last conflict type */
5630    conflict->conflictset->conflicttype = conftype;
5631 
5632    return SCIP_OKAY;
5633 }
5634 
5635 /** analyzes conflicting bound changes that were added with calls to SCIPconflictAddBound(), and on success, calls the
5636  *  conflict handlers to create a conflict constraint out of the resulting conflict set;
5637  *  updates statistics for propagation conflict analysis
5638  */
SCIPconflictAnalyze(SCIP_CONFLICT * conflict,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * prob,SCIP_TREE * tree,int validdepth,SCIP_Bool * success)5639 SCIP_RETCODE SCIPconflictAnalyze(
5640    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
5641    BMS_BLKMEM*           blkmem,             /**< block memory of transformed problem */
5642    SCIP_SET*             set,                /**< global SCIP settings */
5643    SCIP_STAT*            stat,               /**< problem statistics */
5644    SCIP_PROB*            prob,               /**< problem data */
5645    SCIP_TREE*            tree,               /**< branch and bound tree */
5646    int                   validdepth,         /**< minimal depth level at which the initial conflict set is valid */
5647    SCIP_Bool*            success             /**< pointer to store whether a conflict constraint was created, or NULL */
5648    )
5649 {
5650    int nconss;
5651    int nliterals;
5652    int nreconvconss;
5653    int nreconvliterals;
5654 
5655    assert(conflict != NULL);
5656    assert(conflict->conflictset != NULL);
5657    assert(set != NULL);
5658    assert(prob != NULL);
5659 
5660    if( success != NULL )
5661       *success = FALSE;
5662 
5663    /* check if the conflict analysis is applicable */
5664    if( !SCIPconflictApplicable(set) )
5665       return SCIP_OKAY;
5666 
5667    /* check, if the conflict set will get too large with high probability */
5668    if( conflict->conflictset->nbdchginfos + SCIPpqueueNElems(conflict->bdchgqueue)
5669       + SCIPpqueueNElems(conflict->forcedbdchgqueue) >= 2*conflictCalcMaxsize(set, prob) )
5670       return SCIP_OKAY;
5671 
5672    SCIPsetDebugMsg(set, "analyzing conflict after infeasible propagation in depth %d\n", SCIPtreeGetCurrentDepth(tree));
5673 
5674    /* start timing */
5675    SCIPclockStart(conflict->propanalyzetime, set);
5676 
5677    conflict->npropcalls++;
5678 
5679    /* analyze the conflict set, and create a conflict constraint on success */
5680    SCIP_CALL( conflictAnalyze(conflict, blkmem, set, stat, prob, tree, FALSE, validdepth, TRUE, &nconss, &nliterals, \
5681          &nreconvconss, &nreconvliterals) );
5682    conflict->npropsuccess += (nconss > 0 ? 1 : 0);
5683    conflict->npropconfconss += nconss;
5684    conflict->npropconfliterals += nliterals;
5685    conflict->npropreconvconss += nreconvconss;
5686    conflict->npropreconvliterals += nreconvliterals;
5687    if( success != NULL )
5688       *success = (nconss > 0);
5689 
5690    /* stop timing */
5691    SCIPclockStop(conflict->propanalyzetime, set);
5692 
5693    return SCIP_OKAY;
5694 }
5695 
5696 /** gets time in seconds used for preprocessing global conflict constraint before appliance */
SCIPconflictGetGlobalApplTime(SCIP_CONFLICT * conflict)5697 SCIP_Real SCIPconflictGetGlobalApplTime(
5698    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
5699    )
5700 {
5701    assert(conflict != NULL);
5702 
5703    return SCIPclockGetTime(conflict->dIBclock);
5704 }
5705 
5706 /** gets time in seconds used for analyzing propagation conflicts */
SCIPconflictGetPropTime(SCIP_CONFLICT * conflict)5707 SCIP_Real SCIPconflictGetPropTime(
5708    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
5709    )
5710 {
5711    assert(conflict != NULL);
5712 
5713    return SCIPclockGetTime(conflict->propanalyzetime);
5714 }
5715 
5716 /** gets number of calls to propagation conflict analysis */
SCIPconflictGetNPropCalls(SCIP_CONFLICT * conflict)5717 SCIP_Longint SCIPconflictGetNPropCalls(
5718    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
5719    )
5720 {
5721    assert(conflict != NULL);
5722 
5723    return conflict->npropcalls;
5724 }
5725 
5726 /** gets number of calls to propagation conflict analysis that yield at least one conflict constraint */
SCIPconflictGetNPropSuccess(SCIP_CONFLICT * conflict)5727 SCIP_Longint SCIPconflictGetNPropSuccess(
5728    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
5729    )
5730 {
5731    assert(conflict != NULL);
5732 
5733    return conflict->npropsuccess;
5734 }
5735 
5736 /** gets number of conflict constraints detected in propagation conflict analysis */
SCIPconflictGetNPropConflictConss(SCIP_CONFLICT * conflict)5737 SCIP_Longint SCIPconflictGetNPropConflictConss(
5738    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
5739    )
5740 {
5741    assert(conflict != NULL);
5742 
5743    return conflict->npropconfconss;
5744 }
5745 
5746 /** gets total number of literals in conflict constraints created in propagation conflict analysis */
SCIPconflictGetNPropConflictLiterals(SCIP_CONFLICT * conflict)5747 SCIP_Longint SCIPconflictGetNPropConflictLiterals(
5748    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
5749    )
5750 {
5751    assert(conflict != NULL);
5752 
5753    return conflict->npropconfliterals;
5754 }
5755 
5756 /** gets number of reconvergence constraints detected in propagation conflict analysis */
SCIPconflictGetNPropReconvergenceConss(SCIP_CONFLICT * conflict)5757 SCIP_Longint SCIPconflictGetNPropReconvergenceConss(
5758    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
5759    )
5760 {
5761    assert(conflict != NULL);
5762 
5763    return conflict->npropreconvconss;
5764 }
5765 
5766 /** gets total number of literals in reconvergence constraints created in propagation conflict analysis */
SCIPconflictGetNPropReconvergenceLiterals(SCIP_CONFLICT * conflict)5767 SCIP_Longint SCIPconflictGetNPropReconvergenceLiterals(
5768    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
5769    )
5770 {
5771    assert(conflict != NULL);
5772 
5773    return conflict->npropreconvliterals;
5774 }
5775 
5776 
5777 
5778 
5779 /*
5780  * Infeasible LP Conflict Analysis
5781  */
5782 
5783 /** ensures, that side change arrays can store at least num entries */
5784 static
ensureSidechgsSize(SCIP_SET * set,int ** sidechginds,SCIP_Real ** sidechgoldlhss,SCIP_Real ** sidechgoldrhss,SCIP_Real ** sidechgnewlhss,SCIP_Real ** sidechgnewrhss,int * sidechgssize,int num)5785 SCIP_RETCODE ensureSidechgsSize(
5786    SCIP_SET*             set,                /**< global SCIP settings */
5787    int**                 sidechginds,        /**< pointer to side change index array */
5788    SCIP_Real**           sidechgoldlhss,     /**< pointer to side change old left hand sides array */
5789    SCIP_Real**           sidechgoldrhss,     /**< pointer to side change old right hand sides array */
5790    SCIP_Real**           sidechgnewlhss,     /**< pointer to side change new left hand sides array */
5791    SCIP_Real**           sidechgnewrhss,     /**< pointer to side change new right hand sides array */
5792    int*                  sidechgssize,       /**< pointer to size of side change arrays */
5793    int                   num                 /**< minimal number of entries to be able to store in side change arrays */
5794    )
5795 {
5796    assert(sidechginds != NULL);
5797    assert(sidechgoldlhss != NULL);
5798    assert(sidechgoldrhss != NULL);
5799    assert(sidechgnewlhss != NULL);
5800    assert(sidechgnewrhss != NULL);
5801    assert(sidechgssize != NULL);
5802 
5803    if( num > *sidechgssize )
5804    {
5805       int newsize;
5806 
5807       newsize = SCIPsetCalcMemGrowSize(set, num);
5808       SCIP_CALL( SCIPsetReallocBufferArray(set, sidechginds, newsize) );
5809       SCIP_CALL( SCIPsetReallocBufferArray(set, sidechgoldlhss, newsize) );
5810       SCIP_CALL( SCIPsetReallocBufferArray(set, sidechgoldrhss, newsize) );
5811       SCIP_CALL( SCIPsetReallocBufferArray(set, sidechgnewlhss, newsize) );
5812       SCIP_CALL( SCIPsetReallocBufferArray(set, sidechgnewrhss, newsize) );
5813       *sidechgssize = newsize;
5814    }
5815    assert(num <= *sidechgssize);
5816 
5817    return SCIP_OKAY;
5818 }
5819 
5820 /** adds removal of row's side to side change arrays; finite sides are only replaced by near infinite sides, such
5821  *  that the row's sense in the LP solver is not changed
5822  */
5823 static
addSideRemoval(SCIP_SET * set,SCIP_ROW * row,SCIP_Real lpiinfinity,int ** sidechginds,SCIP_Real ** sidechgoldlhss,SCIP_Real ** sidechgoldrhss,SCIP_Real ** sidechgnewlhss,SCIP_Real ** sidechgnewrhss,int * sidechgssize,int * nsidechgs)5824 SCIP_RETCODE addSideRemoval(
5825    SCIP_SET*             set,                /**< global SCIP settings */
5826    SCIP_ROW*             row,                /**< LP row to change the sides for */
5827    SCIP_Real             lpiinfinity,        /**< value treated as infinity in LP solver */
5828    int**                 sidechginds,        /**< pointer to side change index array */
5829    SCIP_Real**           sidechgoldlhss,     /**< pointer to side change old left hand sides array */
5830    SCIP_Real**           sidechgoldrhss,     /**< pointer to side change old right hand sides array */
5831    SCIP_Real**           sidechgnewlhss,     /**< pointer to side change new left hand sides array */
5832    SCIP_Real**           sidechgnewrhss,     /**< pointer to side change new right hand sides array */
5833    int*                  sidechgssize,       /**< pointer to size of side change arrays */
5834    int*                  nsidechgs           /**< pointer to number of used slots in side change arrays */
5835    )
5836 {
5837    SCIP_Real lhs;
5838    SCIP_Real rhs;
5839    SCIP_Real constant;
5840 
5841    assert(sidechginds != NULL);
5842    assert(sidechgoldlhss != NULL);
5843    assert(sidechgoldrhss != NULL);
5844    assert(sidechgnewlhss != NULL);
5845    assert(sidechgnewrhss != NULL);
5846    assert(sidechgssize != NULL);
5847    assert(nsidechgs != NULL);
5848 
5849    lhs = SCIProwGetLhs(row);
5850    rhs = SCIProwGetRhs(row);
5851    constant = SCIProwGetConstant(row);
5852    assert(!SCIPsetIsInfinity(set, -lhs) || !SCIPsetIsInfinity(set, rhs));
5853 
5854    /* get memory to store additional side change */
5855    SCIP_CALL( ensureSidechgsSize(set, sidechginds, sidechgoldlhss, sidechgoldrhss, sidechgnewlhss, sidechgnewrhss, \
5856          sidechgssize, (*nsidechgs)+1) );
5857    assert(*nsidechgs < *sidechgssize);
5858    assert(*sidechginds != NULL);
5859    assert(*sidechgoldlhss != NULL);
5860    assert(*sidechgoldrhss != NULL);
5861    assert(*sidechgnewlhss != NULL);
5862    assert(*sidechgnewrhss != NULL);
5863 
5864    /* store side change */
5865    (*sidechginds)[*nsidechgs] = SCIProwGetLPPos(row);
5866    if( SCIPsetIsInfinity(set, -lhs) )
5867    {
5868       (*sidechgoldlhss)[*nsidechgs] = -lpiinfinity;
5869       (*sidechgnewlhss)[*nsidechgs] = -lpiinfinity;
5870    }
5871    else
5872    {
5873       (*sidechgoldlhss)[*nsidechgs] = lhs - constant;
5874       (*sidechgnewlhss)[*nsidechgs] = -lpiinfinity;
5875    }
5876    if( SCIPsetIsInfinity(set, rhs) )
5877    {
5878       (*sidechgoldrhss)[*nsidechgs] = lpiinfinity;
5879       (*sidechgnewrhss)[*nsidechgs] = lpiinfinity;
5880    }
5881    else
5882    {
5883       (*sidechgoldrhss)[*nsidechgs] = rhs - constant;
5884       (*sidechgnewrhss)[*nsidechgs] = lpiinfinity;
5885    }
5886    (*nsidechgs)++;
5887 
5888    return SCIP_OKAY;
5889 }
5890 
5891 /** inserts variable's new bounds into bound change arrays */
5892 static
addBdchg(SCIP_SET * set,SCIP_VAR * var,SCIP_Real newlb,SCIP_Real newub,SCIP_LPBDCHGS * oldlpbdchgs,SCIP_LPBDCHGS * relaxedlpbdchgs,SCIP_LPI * lpi)5893 SCIP_RETCODE addBdchg(
5894    SCIP_SET*             set,                /**< global SCIP settings */
5895    SCIP_VAR*             var,                /**< variable to change the LP bounds for */
5896    SCIP_Real             newlb,              /**< new lower bound */
5897    SCIP_Real             newub,              /**< new upper bound */
5898    SCIP_LPBDCHGS*        oldlpbdchgs,        /**< old LP bound changes used for reset the LP bound change */
5899    SCIP_LPBDCHGS*        relaxedlpbdchgs,    /**< relaxed LP bound changes used for reset the LP bound change */
5900    SCIP_LPI*             lpi                 /**< pointer to LPi to access infinity of LP solver; necessary to set correct value */
5901    )
5902 {
5903    assert(newlb <= newub);
5904    assert(oldlpbdchgs != NULL);
5905    assert(relaxedlpbdchgs != NULL);
5906 
5907    if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN )
5908    {
5909       SCIP_COL* col;
5910       int idx;
5911       int c;
5912 
5913       col = SCIPvarGetCol(var);
5914       c = SCIPcolGetLPPos(col);
5915 
5916       if( c >= 0 )
5917       {
5918          /* store old bound change for resetting the LP later */
5919          if( !oldlpbdchgs->usedcols[c] )
5920          {
5921             idx = oldlpbdchgs->nbdchgs;
5922             oldlpbdchgs->usedcols[c] = TRUE;
5923             oldlpbdchgs->bdchgcolinds[c] = idx;
5924             oldlpbdchgs->nbdchgs++;
5925 
5926             oldlpbdchgs->bdchginds[idx] = c;
5927             oldlpbdchgs->bdchglbs[idx] = SCIPvarGetLbLP(var, set);
5928             oldlpbdchgs->bdchgubs[idx] = SCIPvarGetUbLP(var, set);
5929          }
5930          assert(oldlpbdchgs->bdchginds[oldlpbdchgs->bdchgcolinds[c]] == c);
5931          assert((SCIPlpiIsInfinity(lpi, -oldlpbdchgs->bdchglbs[oldlpbdchgs->bdchgcolinds[c]]) && SCIPsetIsInfinity(set, -SCIPvarGetLbLP(var, set))) ||
5932             SCIPsetIsEQ(set, oldlpbdchgs->bdchglbs[oldlpbdchgs->bdchgcolinds[c]], SCIPvarGetLbLP(var, set)));
5933          assert((SCIPlpiIsInfinity(lpi, oldlpbdchgs->bdchgubs[oldlpbdchgs->bdchgcolinds[c]]) && SCIPsetIsInfinity(set, SCIPvarGetUbLP(var, set))) ||
5934             SCIPsetIsEQ(set, oldlpbdchgs->bdchgubs[oldlpbdchgs->bdchgcolinds[c]], SCIPvarGetUbLP(var, set)));
5935 
5936          /* store bound change for conflict analysis */
5937          if( !relaxedlpbdchgs->usedcols[c] )
5938          {
5939             idx = relaxedlpbdchgs->nbdchgs;
5940             relaxedlpbdchgs->usedcols[c] = TRUE;
5941             relaxedlpbdchgs->bdchgcolinds[c] = idx;
5942             relaxedlpbdchgs->nbdchgs++;
5943 
5944             /* remember the positive for later further bound widenings */
5945             relaxedlpbdchgs->bdchginds[idx] = c;
5946          }
5947          else
5948          {
5949             idx = relaxedlpbdchgs->bdchgcolinds[c];
5950             assert(relaxedlpbdchgs->bdchginds[idx] == c);
5951 
5952             /* the new bound should be the same or more relaxed */
5953             assert(relaxedlpbdchgs->bdchglbs[idx] >= newlb ||
5954                (SCIPlpiIsInfinity(lpi, -relaxedlpbdchgs->bdchglbs[idx]) && SCIPsetIsInfinity(set, -newlb)));
5955             assert(relaxedlpbdchgs->bdchgubs[idx] <= newub ||
5956                (SCIPlpiIsInfinity(lpi, relaxedlpbdchgs->bdchgubs[idx]) && SCIPsetIsInfinity(set, newub)));
5957          }
5958 
5959          /* set the new bounds for the LP with the correct infinity value */
5960          relaxedlpbdchgs->bdchglbs[idx] = SCIPsetIsInfinity(set, -newlb) ? -SCIPlpiInfinity(lpi) : newlb;
5961          relaxedlpbdchgs->bdchgubs[idx] = SCIPsetIsInfinity(set, newub) ? SCIPlpiInfinity(lpi) : newub;
5962          if( SCIPsetIsInfinity(set, -oldlpbdchgs->bdchglbs[idx]) )
5963             oldlpbdchgs->bdchglbs[idx] = -SCIPlpiInfinity(lpi);
5964          if( SCIPsetIsInfinity(set, oldlpbdchgs->bdchgubs[idx]) )
5965             oldlpbdchgs->bdchgubs[idx] = SCIPlpiInfinity(lpi);
5966       }
5967    }
5968 
5969    return SCIP_OKAY;
5970 }
5971 
5972 /** ensures, that candidate array can store at least num entries */
5973 static
ensureCandsSize(SCIP_SET * set,SCIP_VAR *** cands,SCIP_Real ** candscores,SCIP_Real ** newbounds,SCIP_Real ** proofactdeltas,int * candssize,int num)5974 SCIP_RETCODE ensureCandsSize(
5975    SCIP_SET*             set,                /**< global SCIP settings */
5976    SCIP_VAR***           cands,              /**< pointer to candidate array */
5977    SCIP_Real**           candscores,         /**< pointer to candidate score array */
5978    SCIP_Real**           newbounds,          /**< pointer to candidate new bounds array */
5979    SCIP_Real**           proofactdeltas,     /**< pointer to candidate proof delta array */
5980    int*                  candssize,          /**< pointer to size of array */
5981    int                   num                 /**< minimal number of candidates to store in array */
5982    )
5983 {
5984    assert(cands != NULL);
5985    assert(candssize != NULL);
5986 
5987    if( num > *candssize )
5988    {
5989       int newsize;
5990 
5991       newsize = SCIPsetCalcMemGrowSize(set, num);
5992       SCIP_CALL( SCIPsetReallocBufferArray(set, cands, newsize) );
5993       SCIP_CALL( SCIPsetReallocBufferArray(set, candscores, newsize) );
5994       SCIP_CALL( SCIPsetReallocBufferArray(set, newbounds, newsize) );
5995       SCIP_CALL( SCIPsetReallocBufferArray(set, proofactdeltas, newsize) );
5996       *candssize = newsize;
5997    }
5998    assert(num <= *candssize);
5999 
6000    return SCIP_OKAY;
6001 }
6002 
6003 /** adds variable to candidate list, if the current best bound corresponding to the proof coefficient is local;
6004  *  returns the array position in the candidate list, where the new candidate was inserted, or -1 if the
6005  *  variable can relaxed to global bounds immediately without increasing the proof's activity;
6006  *  the candidates are sorted with respect to the following two criteria:
6007  *  - prefer bound changes that have been applied deeper in the tree, to get a more global conflict
6008  *  - prefer variables with small Farkas coefficient to get rid of as many bound changes as possible
6009  */
6010 static
addCand(SCIP_SET * set,int currentdepth,SCIP_VAR * var,int lbchginfopos,int ubchginfopos,SCIP_Real proofcoef,SCIP_Real prooflhs,SCIP_Real proofact,SCIP_VAR *** cands,SCIP_Real ** candscores,SCIP_Real ** newbounds,SCIP_Real ** proofactdeltas,int * candssize,int * ncands,int firstcand)6011 SCIP_RETCODE addCand(
6012    SCIP_SET*             set,                /**< global SCIP settings */
6013    int                   currentdepth,       /**< current depth in the tree */
6014    SCIP_VAR*             var,                /**< variable to add to candidate array */
6015    int                   lbchginfopos,       /**< positions of currently active lower bound change information in variable's array */
6016    int                   ubchginfopos,       /**< positions of currently active upper bound change information in variable's array */
6017    SCIP_Real             proofcoef,          /**< coefficient of variable in infeasibility/bound proof */
6018    SCIP_Real             prooflhs,           /**< left hand side of infeasibility/bound proof */
6019    SCIP_Real             proofact,           /**< activity of infeasibility/bound proof row */
6020    SCIP_VAR***           cands,              /**< pointer to candidate array for undoing bound changes */
6021    SCIP_Real**           candscores,         /**< pointer to candidate score array for undoing bound changes */
6022    SCIP_Real**           newbounds,          /**< pointer to candidate new bounds array for undoing bound changes */
6023    SCIP_Real**           proofactdeltas,     /**< pointer to proof activity increase array for undoing bound changes */
6024    int*                  candssize,          /**< pointer to size of cands arrays */
6025    int*                  ncands,             /**< pointer to count number of candidates in bound change list */
6026    int                   firstcand           /**< position of first unprocessed bound change candidate */
6027    )
6028 {
6029    SCIP_Real oldbound;
6030    SCIP_Real newbound;
6031    SCIP_Real QUAD(proofactdelta);
6032    SCIP_Real score;
6033    int depth;
6034    int i;
6035    SCIP_Bool resolvable;
6036 
6037    assert(set != NULL);
6038    assert(var != NULL);
6039    assert(-1 <= lbchginfopos && lbchginfopos <= var->nlbchginfos);
6040    assert(-1 <= ubchginfopos && ubchginfopos <= var->nubchginfos);
6041    assert(!SCIPsetIsZero(set, proofcoef));
6042    assert(SCIPsetIsGT(set, prooflhs, proofact));
6043    assert(cands != NULL);
6044    assert(candscores != NULL);
6045    assert(newbounds != NULL);
6046    assert(proofactdeltas != NULL);
6047    assert(candssize != NULL);
6048    assert(ncands != NULL);
6049    assert(*ncands <= *candssize);
6050    assert(0 <= firstcand && firstcand <= *ncands);
6051 
6052    /* in the infeasibility or dual bound proof, the variable's bound is chosen to maximize the proof's activity */
6053    if( proofcoef > 0.0 )
6054    {
6055       assert(ubchginfopos >= 0); /* otherwise, undoBdchgsProof() should already have relaxed the local bound */
6056 
6057       /* calculate the difference of current bound to the previous bound the variable was set to */
6058       if( ubchginfopos == var->nubchginfos )
6059       {
6060          /* current bound is the strong branching or diving bound */
6061          oldbound = SCIPvarGetUbLP(var, set);
6062          newbound = SCIPvarGetUbLocal(var);
6063          depth = currentdepth+1;
6064          resolvable = FALSE;
6065       }
6066       else
6067       {
6068          /* current bound is the result of a local bound change */
6069          resolvable = bdchginfoIsResolvable(&var->ubchginfos[ubchginfopos]);
6070          depth = var->ubchginfos[ubchginfopos].bdchgidx.depth;
6071          oldbound = var->ubchginfos[ubchginfopos].newbound;
6072          newbound = var->ubchginfos[ubchginfopos].oldbound;
6073       }
6074    }
6075    else
6076    {
6077       assert(lbchginfopos >= 0); /* otherwise, undoBdchgsProof() should already have relaxed the local bound */
6078 
6079       /* calculate the difference of current bound to the previous bound the variable was set to */
6080       if( lbchginfopos == var->nlbchginfos )
6081       {
6082          /* current bound is the strong branching or diving bound */
6083          oldbound = SCIPvarGetLbLP(var, set);
6084          newbound = SCIPvarGetLbLocal(var);
6085          depth = currentdepth+1;
6086          resolvable = FALSE;
6087       }
6088       else
6089       {
6090          /* current bound is the result of a local bound change */
6091          resolvable = bdchginfoIsResolvable(&var->lbchginfos[lbchginfopos]);
6092          depth = var->lbchginfos[lbchginfopos].bdchgidx.depth;
6093          oldbound = var->lbchginfos[lbchginfopos].newbound;
6094          newbound = var->lbchginfos[lbchginfopos].oldbound;
6095       }
6096    }
6097 
6098    /* calculate the increase in the proof's activity */
6099    SCIPquadprecSumDD(proofactdelta, newbound, -oldbound);
6100    SCIPquadprecProdQD(proofactdelta, proofactdelta, proofcoef);
6101    assert(QUAD_TO_DBL(proofactdelta) > 0.0);
6102 
6103    /* calculate score for undoing the bound change */
6104    score = calcBdchgScore(prooflhs, proofact, QUAD_TO_DBL(proofactdelta), proofcoef, depth, currentdepth, var, set);
6105 
6106    if( !resolvable )
6107    {
6108       score += 10.0;
6109       if( !SCIPvarIsBinary(var) )
6110          score += 10.0;
6111    }
6112 
6113    /* get enough memory to store new candidate */
6114    SCIP_CALL( ensureCandsSize(set, cands, candscores, newbounds, proofactdeltas, candssize, (*ncands)+1) );
6115    assert(*cands != NULL);
6116    assert(*candscores != NULL);
6117    assert(*newbounds != NULL);
6118    assert(*proofactdeltas != NULL);
6119 
6120    SCIPsetDebugMsg(set, " -> local <%s> %s %g, relax <%s> %s %g, proofcoef=%g, dpt=%d, resolve=%u, delta=%g, score=%g\n",
6121       SCIPvarGetName(var), proofcoef > 0.0 ? "<=" : ">=", oldbound,
6122       SCIPvarGetName(var), proofcoef > 0.0 ? "<=" : ">=", newbound,
6123       proofcoef, depth, resolvable, QUAD_TO_DBL(proofactdelta), score);
6124 
6125    /* insert variable in candidate list without touching the already processed candidates */
6126    for( i = *ncands; i > firstcand && score > (*candscores)[i-1]; --i )
6127    {
6128       (*cands)[i] = (*cands)[i-1];
6129       (*candscores)[i] = (*candscores)[i-1];
6130       (*newbounds)[i] = (*newbounds)[i-1];
6131       (*proofactdeltas)[i] = (*proofactdeltas)[i-1];
6132    }
6133    (*cands)[i] = var;
6134    (*candscores)[i] = score;
6135    (*newbounds)[i] = newbound;
6136    (*proofactdeltas)[i] = QUAD_TO_DBL(proofactdelta);
6137    (*ncands)++;
6138 
6139    return SCIP_OKAY;
6140 }
6141 
6142 /** after changing the global bound of a variable, the bdchginfos that are now redundant are replaced with
6143  *  oldbound = newbound = global bound; if the current bdchginfo is of such kind, the bound is equal to the
6144  *  global bound and we can ignore it by installing a -1 as the corresponding bound change info position
6145  */
6146 static
skipRedundantBdchginfos(SCIP_VAR * var,int * lbchginfopos,int * ubchginfopos)6147 void skipRedundantBdchginfos(
6148    SCIP_VAR*             var,                /**< problem variable */
6149    int*                  lbchginfopos,       /**< pointer to lower bound change information position */
6150    int*                  ubchginfopos        /**< pointer to upper bound change information position */
6151    )
6152 {
6153    assert(var != NULL);
6154    assert(lbchginfopos != NULL);
6155    assert(ubchginfopos != NULL);
6156    assert(-1 <= *lbchginfopos && *lbchginfopos <= var->nlbchginfos);
6157    assert(-1 <= *ubchginfopos && *ubchginfopos <= var->nubchginfos);
6158    assert(*lbchginfopos == -1 || *lbchginfopos == var->nlbchginfos
6159       || var->lbchginfos[*lbchginfopos].redundant
6160       == (var->lbchginfos[*lbchginfopos].oldbound == var->lbchginfos[*lbchginfopos].newbound)); /*lint !e777*/
6161    assert(*ubchginfopos == -1 || *ubchginfopos == var->nubchginfos
6162       || var->ubchginfos[*ubchginfopos].redundant
6163       == (var->ubchginfos[*ubchginfopos].oldbound == var->ubchginfos[*ubchginfopos].newbound)); /*lint !e777*/
6164 
6165    if( *lbchginfopos >= 0 && *lbchginfopos < var->nlbchginfos && var->lbchginfos[*lbchginfopos].redundant )
6166    {
6167       assert(SCIPvarGetLbGlobal(var) == var->lbchginfos[*lbchginfopos].oldbound); /*lint !e777*/
6168       *lbchginfopos = -1;
6169    }
6170    if( *ubchginfopos >= 0 && *ubchginfopos < var->nubchginfos && var->ubchginfos[*ubchginfopos].redundant )
6171    {
6172       assert(SCIPvarGetUbGlobal(var) == var->ubchginfos[*ubchginfopos].oldbound); /*lint !e777*/
6173       *ubchginfopos = -1;
6174    }
6175 }
6176 
6177 /** undoes bound changes on variables, still leaving the given infeasibility proof valid */
6178 static
undoBdchgsProof(SCIP_SET * set,SCIP_PROB * prob,int currentdepth,SCIP_Real * proofcoefs,SCIP_Real prooflhs,SCIP_Real * proofact,SCIP_Real * curvarlbs,SCIP_Real * curvarubs,int * lbchginfoposs,int * ubchginfoposs,SCIP_LPBDCHGS * oldlpbdchgs,SCIP_LPBDCHGS * relaxedlpbdchgs,SCIP_Bool * resolve,SCIP_LPI * lpi)6179 SCIP_RETCODE undoBdchgsProof(
6180    SCIP_SET*             set,                /**< global SCIP settings */
6181    SCIP_PROB*            prob,               /**< problem data */
6182    int                   currentdepth,       /**< current depth in the tree */
6183    SCIP_Real*            proofcoefs,         /**< coefficients in infeasibility proof */
6184    SCIP_Real             prooflhs,           /**< left hand side of proof */
6185    SCIP_Real*            proofact,           /**< current activity of proof */
6186    SCIP_Real*            curvarlbs,          /**< current lower bounds of active problem variables */
6187    SCIP_Real*            curvarubs,          /**< current upper bounds of active problem variables */
6188    int*                  lbchginfoposs,      /**< positions of currently active lower bound change information in variables' arrays */
6189    int*                  ubchginfoposs,      /**< positions of currently active upper bound change information in variables' arrays */
6190    SCIP_LPBDCHGS*        oldlpbdchgs,        /**< old LP bound changes used for reset the LP bound change, or NULL */
6191    SCIP_LPBDCHGS*        relaxedlpbdchgs,    /**< relaxed LP bound changes used for reset the LP bound change, or NULL */
6192    SCIP_Bool*            resolve,            /**< pointer to store whether the changed LP should be resolved again, or NULL */
6193    SCIP_LPI*             lpi                 /**< pointer to LPi to access infinity of LP solver; necessary to set correct values */
6194    )
6195 {
6196    SCIP_VAR** vars;
6197    SCIP_VAR** cands;
6198    SCIP_Real* candscores;
6199    SCIP_Real* newbounds;
6200    SCIP_Real* proofactdeltas;
6201    int nvars;
6202    int ncands;
6203    int candssize;
6204    int v;
6205    int i;
6206 
6207    assert(prob != NULL);
6208    assert(proofcoefs != NULL);
6209    assert(SCIPsetIsFeasGT(set, prooflhs, (*proofact)));
6210    assert(curvarlbs != NULL);
6211    assert(curvarubs != NULL);
6212    assert(lbchginfoposs != NULL);
6213    assert(ubchginfoposs != NULL);
6214 
6215    if( resolve != NULL )
6216       *resolve = FALSE;
6217 
6218    vars = prob->vars;
6219    nvars = prob->nvars;
6220    assert(nvars == 0 || vars != NULL);
6221 
6222    /* calculate the order in which the bound changes are tried to be undone, and relax all bounds if this doesn't
6223     * increase the proof's activity
6224     */
6225    SCIP_CALL( SCIPsetAllocBufferArray(set, &cands, nvars) );
6226    SCIP_CALL( SCIPsetAllocBufferArray(set, &candscores, nvars) );
6227    SCIP_CALL( SCIPsetAllocBufferArray(set, &newbounds, nvars) );
6228    SCIP_CALL( SCIPsetAllocBufferArray(set, &proofactdeltas, nvars) );
6229    ncands = 0;
6230    candssize = nvars;
6231    for( v = 0; v < nvars; ++v )
6232    {
6233       SCIP_VAR* var;
6234       SCIP_Bool relaxed;
6235 
6236       var = vars[v];
6237 
6238       /* after changing the global bound of a variable, the bdchginfos that are now redundant are replaced with
6239        * oldbound = newbound = global bound; if the current bdchginfo is of such kind, the bound is equal to the
6240        * global bound and we can ignore it
6241        */
6242       skipRedundantBdchginfos(var, &lbchginfoposs[v], &ubchginfoposs[v]);
6243 
6244       /* ignore variables already relaxed to global bounds */
6245       if( (lbchginfoposs[v] == -1 && ubchginfoposs[v] == -1) )
6246       {
6247          proofcoefs[v] = 0.0;
6248          continue;
6249       }
6250 
6251       /* relax bounds that are not used in the proof to the global bounds */
6252       relaxed = FALSE;
6253       if( !SCIPsetIsNegative(set, proofcoefs[v]) )
6254       {
6255          /* the lower bound is not used */
6256          if( lbchginfoposs[v] >= 0 )
6257          {
6258             SCIPsetDebugMsg(set, " -> relaxing variable <%s>[%g,%g] to [%g,%g]: proofcoef=%g, %g <= %g\n",
6259                SCIPvarGetName(var), curvarlbs[v], curvarubs[v], SCIPvarGetLbGlobal(var), curvarubs[v],
6260                proofcoefs[v], prooflhs, (*proofact));
6261             curvarlbs[v] = SCIPvarGetLbGlobal(var);
6262             lbchginfoposs[v] = -1;
6263             relaxed = TRUE;
6264          }
6265       }
6266       if( !SCIPsetIsPositive(set, proofcoefs[v]) )
6267       {
6268          /* the upper bound is not used */
6269          if( ubchginfoposs[v] >= 0 )
6270          {
6271             SCIPsetDebugMsg(set, " -> relaxing variable <%s>[%g,%g] to [%g,%g]: proofcoef=%g, %g <= %g\n",
6272                SCIPvarGetName(var), curvarlbs[v], curvarubs[v], curvarlbs[v], SCIPvarGetUbGlobal(var),
6273                proofcoefs[v], prooflhs, (*proofact));
6274             curvarubs[v] = SCIPvarGetUbGlobal(var);
6275             ubchginfoposs[v] = -1;
6276             relaxed = TRUE;
6277          }
6278       }
6279       if( relaxed && oldlpbdchgs != NULL )
6280       {
6281          SCIP_CALL( addBdchg(set, var, curvarlbs[v], curvarubs[v], oldlpbdchgs, relaxedlpbdchgs, lpi) );
6282       }
6283 
6284       /* add bound to candidate list */
6285       if( lbchginfoposs[v] >= 0 || ubchginfoposs[v] >= 0 )
6286       {
6287          SCIP_CALL( addCand(set, currentdepth, var, lbchginfoposs[v], ubchginfoposs[v], proofcoefs[v],
6288                prooflhs, (*proofact), &cands, &candscores, &newbounds, &proofactdeltas, &candssize, &ncands, 0) );
6289       }
6290       /* we can set the proof coefficient to zero, because the variable is not needed */
6291       else
6292          proofcoefs[v] = 0.0;
6293    }
6294 
6295    /* try to undo remaining local bound changes while still keeping the proof row violated:
6296     * bound changes can be undone, if prooflhs > proofact + proofactdelta;
6297     * afterwards, the current proof activity has to be updated
6298     */
6299    for( i = 0; i < ncands; ++i )
6300    {
6301       assert(proofactdeltas[i] > 0.0);
6302       assert((lbchginfoposs[SCIPvarGetProbindex(cands[i])] >= 0) != (ubchginfoposs[SCIPvarGetProbindex(cands[i])] >= 0));
6303 
6304       /* when relaxing a constraint we still need to stay infeasible; therefore we need to do the comparison in
6305        * feasibility tolerance because if 'prooflhs' is (feas-))equal to 'proofact + proofactdeltas[i]' it would mean
6306        * that there is no violation
6307        */
6308       if( SCIPsetIsFeasGT(set, prooflhs, (*proofact) + proofactdeltas[i]) )
6309       {
6310          v = SCIPvarGetProbindex(cands[i]);
6311          assert(0 <= v && v < nvars);
6312          assert((lbchginfoposs[v] >= 0) != (ubchginfoposs[v] >= 0));
6313 
6314          SCIPsetDebugMsg(set, " -> relaxing variable <%s>[%g,%g] to [%g,%g]: proofcoef=%g, %g <= %g + %g\n",
6315             SCIPvarGetName(cands[i]), curvarlbs[v], curvarubs[v],
6316             proofcoefs[v] > 0.0 ? curvarlbs[v] : newbounds[i],
6317             proofcoefs[v] > 0.0 ? newbounds[i] : curvarubs[v],
6318             proofcoefs[v], prooflhs, (*proofact), proofactdeltas[i]);
6319 
6320 #ifndef NDEBUG
6321          {
6322             SCIP_Real QUAD(verifylb);
6323             SCIP_Real QUAD(verifyub);
6324 
6325             SCIPquadprecSumDD(verifylb, newbounds[i], -curvarlbs[v]);
6326             SCIPquadprecProdQD(verifylb, verifylb, proofcoefs[v]);
6327 
6328             SCIPquadprecSumDD(verifyub, newbounds[i], -curvarubs[v]);
6329             SCIPquadprecProdQD(verifyub, verifyub, proofcoefs[v]);
6330 
6331             assert((SCIPsetIsPositive(set, proofcoefs[v]) && SCIPsetIsGT(set, newbounds[i], curvarubs[v]))
6332                || (SCIPsetIsNegative(set, proofcoefs[v]) && SCIPsetIsLT(set, newbounds[i], curvarlbs[v])));
6333             assert((SCIPsetIsPositive(set, proofcoefs[v])
6334                   && SCIPsetIsEQ(set, proofactdeltas[i], QUAD_TO_DBL(verifyub)))
6335                || (SCIPsetIsNegative(set, proofcoefs[v])
6336                   && SCIPsetIsEQ(set, proofactdeltas[i], QUAD_TO_DBL(verifylb))));
6337             assert(!SCIPsetIsZero(set, proofcoefs[v]));
6338          }
6339 #endif
6340 
6341          if( proofcoefs[v] > 0.0 )
6342          {
6343             assert(ubchginfoposs[v] >= 0);
6344             assert(lbchginfoposs[v] == -1);
6345             curvarubs[v] = newbounds[i];
6346             ubchginfoposs[v]--;
6347          }
6348          else
6349          {
6350             assert(lbchginfoposs[v] >= 0);
6351             assert(ubchginfoposs[v] == -1);
6352             curvarlbs[v] = newbounds[i];
6353             lbchginfoposs[v]--;
6354          }
6355          if( oldlpbdchgs != NULL )
6356          {
6357             SCIP_CALL( addBdchg(set, cands[i], curvarlbs[v], curvarubs[v], oldlpbdchgs, relaxedlpbdchgs, lpi) );
6358          }
6359          (*proofact) += proofactdeltas[i];
6360          if( resolve != NULL && SCIPvarIsInLP(cands[i]) )
6361             *resolve = TRUE;
6362 
6363          /* after changing the global bound of a variable, the bdchginfos that are now redundant are replaced with
6364           * oldbound = newbound = global bound; if the current bdchginfo is of such kind, the bound is equal to the
6365           * global bound and we can ignore it
6366           */
6367          skipRedundantBdchginfos(cands[i], &lbchginfoposs[v], &ubchginfoposs[v]);
6368 
6369          /* insert the new local bound of the variable into the candidate list */
6370          if( lbchginfoposs[v] >= 0 || ubchginfoposs[v] >= 0 )
6371          {
6372             SCIP_CALL( addCand(set, currentdepth, cands[i], lbchginfoposs[v], ubchginfoposs[v], proofcoefs[v],
6373                   prooflhs, (*proofact), &cands, &candscores, &newbounds, &proofactdeltas, &candssize, &ncands, i+1) );
6374          }
6375          else
6376             proofcoefs[v] = 0.0;
6377       }
6378    }
6379 
6380    /* free the buffer for the sorted bound change candidates */
6381    SCIPsetFreeBufferArray(set, &proofactdeltas);
6382    SCIPsetFreeBufferArray(set, &newbounds);
6383    SCIPsetFreeBufferArray(set, &candscores);
6384    SCIPsetFreeBufferArray(set, &cands);
6385 
6386    return SCIP_OKAY;
6387 }
6388 
6389 /* because calculations might cancel out some values, we stop the infeasibility analysis if a value is bigger than
6390  * 2^53 = 9007199254740992
6391  */
6392 #define NUMSTOP 9007199254740992.0
6393 
6394 /** analyzes an infeasible LP and undoes additional bound changes while staying infeasible */
6395 static
undoBdchgsDualfarkas(SCIP_SET * set,SCIP_PROB * prob,SCIP_LP * lp,int currentdepth,SCIP_Real * curvarlbs,SCIP_Real * curvarubs,int * lbchginfoposs,int * ubchginfoposs,SCIP_LPBDCHGS * oldlpbdchgs,SCIP_LPBDCHGS * relaxedlpbdchgs,SCIP_Bool * valid,SCIP_Bool * resolve,SCIP_Real * farkascoefs,SCIP_Real farkaslhs,SCIP_Real * farkasactivity)6396 SCIP_RETCODE undoBdchgsDualfarkas(
6397    SCIP_SET*             set,                /**< global SCIP settings */
6398    SCIP_PROB*            prob,               /**< problem data */
6399    SCIP_LP*              lp,                 /**< LP data */
6400    int                   currentdepth,       /**< current depth in the tree */
6401    SCIP_Real*            curvarlbs,          /**< current lower bounds of active problem variables */
6402    SCIP_Real*            curvarubs,          /**< current upper bounds of active problem variables */
6403    int*                  lbchginfoposs,      /**< positions of currently active lower bound change information in variables' arrays */
6404    int*                  ubchginfoposs,      /**< positions of currently active upper bound change information in variables' arrays */
6405    SCIP_LPBDCHGS*        oldlpbdchgs,        /**< old LP bound changes used for reset the LP bound change, or NULL */
6406    SCIP_LPBDCHGS*        relaxedlpbdchgs,    /**< relaxed LP bound changes used for reset the LP bound change, or NULL */
6407    SCIP_Bool*            valid,              /**< pointer to store whether the unfixings are valid */
6408    SCIP_Bool*            resolve,            /**< pointer to store whether the changed LP should be resolved again */
6409    SCIP_Real*            farkascoefs,        /**< coefficients in the proof constraint */
6410    SCIP_Real             farkaslhs,          /**< lhs of the proof constraint */
6411    SCIP_Real*            farkasactivity      /**< maximal activity of the proof constraint */
6412    )
6413 {
6414    SCIP_LPI* lpi;
6415 
6416    assert(prob != NULL);
6417    assert(lp != NULL);
6418    assert(lp->flushed);
6419    assert(lp->solved);
6420    assert(curvarlbs != NULL);
6421    assert(curvarubs != NULL);
6422    assert(lbchginfoposs != NULL);
6423    assert(ubchginfoposs != NULL);
6424    assert(valid != NULL);
6425    assert(resolve != NULL);
6426 
6427    SCIPsetDebugMsg(set, "undoing bound changes in infeasible LP: cutoff=%g\n", lp->cutoffbound);
6428 
6429    *valid = FALSE;
6430    *resolve = FALSE;
6431 
6432    lpi = SCIPlpGetLPI(lp);
6433 
6434    /* check, if the Farkas row is still violated (using current bounds and ignoring local rows) */
6435    if( SCIPsetIsFeasGT(set, farkaslhs, *farkasactivity) )
6436    {
6437       /* undo bound changes while keeping the infeasibility proof valid */
6438       SCIP_CALL( undoBdchgsProof(set, prob, currentdepth, farkascoefs, farkaslhs, farkasactivity, \
6439             curvarlbs, curvarubs, lbchginfoposs, ubchginfoposs, oldlpbdchgs, relaxedlpbdchgs, resolve, lpi) );
6440 
6441       *valid = TRUE;
6442 
6443       /* resolving does not make sense: the old dual ray is still valid -> resolving will not change the solution */
6444       *resolve = FALSE;
6445    }
6446 
6447    return SCIP_OKAY;
6448 }
6449 
6450 /** analyzes an LP exceeding the objective limit and undoes additional bound changes while staying beyond the
6451  *  objective limit
6452  */
6453 static
undoBdchgsDualsol(SCIP_SET * set,SCIP_PROB * prob,SCIP_LP * lp,int currentdepth,SCIP_Real * curvarlbs,SCIP_Real * curvarubs,int * lbchginfoposs,int * ubchginfoposs,SCIP_LPBDCHGS * oldlpbdchgs,SCIP_LPBDCHGS * relaxedlpbdchgs,SCIP_Bool * valid,SCIP_Bool * resolve,SCIP_Real * dualcoefs,SCIP_Real duallhs,SCIP_Real * dualactivity)6454 SCIP_RETCODE undoBdchgsDualsol(
6455    SCIP_SET*             set,                /**< global SCIP settings */
6456    SCIP_PROB*            prob,               /**< problem data */
6457    SCIP_LP*              lp,                 /**< LP data */
6458    int                   currentdepth,       /**< current depth in the tree */
6459    SCIP_Real*            curvarlbs,          /**< current lower bounds of active problem variables */
6460    SCIP_Real*            curvarubs,          /**< current upper bounds of active problem variables */
6461    int*                  lbchginfoposs,      /**< positions of currently active lower bound change information in variables' arrays */
6462    int*                  ubchginfoposs,      /**< positions of currently active upper bound change information in variables' arrays */
6463    SCIP_LPBDCHGS*        oldlpbdchgs,        /**< old LP bound changes used for reset the LP bound change, or NULL */
6464    SCIP_LPBDCHGS*        relaxedlpbdchgs,    /**< relaxed LP bound changes used for reset the LP bound change, or NULL */
6465    SCIP_Bool*            valid,              /**< pointer to store whether the unfixings are valid */
6466    SCIP_Bool*            resolve,            /**< pointer to store whether the changed LP should be resolved again */
6467    SCIP_Real*            dualcoefs,          /**< coefficients in the proof constraint */
6468    SCIP_Real             duallhs,            /**< lhs of the proof constraint */
6469    SCIP_Real*            dualactivity        /**< maximal activity of the proof constraint */
6470    )
6471 {
6472    SCIP_LPI* lpi;
6473 
6474    assert(set != NULL);
6475    assert(prob != NULL);
6476    assert(lp != NULL);
6477    assert(lp->flushed);
6478    assert(lp->solved);
6479    assert(curvarlbs != NULL);
6480    assert(curvarubs != NULL);
6481    assert(lbchginfoposs != NULL);
6482    assert(ubchginfoposs != NULL);
6483    assert(valid != NULL);
6484    assert(resolve != NULL);
6485 
6486    *valid = FALSE;
6487    *resolve = FALSE;
6488 
6489    SCIPsetDebugMsg(set, "undoing bound changes in LP exceeding cutoff: cutoff=%g\n", lp->cutoffbound);
6490 
6491    /* get LP solver interface */
6492    lpi = SCIPlpGetLPI(lp);
6493 
6494    /* check, if the dual row is still violated (using current bounds and ignoring local rows) */
6495    if( SCIPsetIsFeasGT(set, duallhs, *dualactivity) )
6496    {
6497       /* undo bound changes while keeping the infeasibility proof valid */
6498       SCIP_CALL( undoBdchgsProof(set, prob, currentdepth, dualcoefs, duallhs, dualactivity, curvarlbs, curvarubs, \
6499             lbchginfoposs, ubchginfoposs, oldlpbdchgs, relaxedlpbdchgs, resolve, lpi) );
6500 
6501       *valid = TRUE;
6502    }
6503 
6504    return SCIP_OKAY;
6505 }
6506 
6507 /** applies conflict analysis starting with given bound changes, that could not be undone during previous
6508  *  infeasibility analysis
6509  */
6510 static
conflictAnalyzeRemainingBdchgs(SCIP_CONFLICT * conflict,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * prob,SCIP_TREE * tree,SCIP_Bool diving,int * lbchginfoposs,int * ubchginfoposs,int * nconss,int * nliterals,int * nreconvconss,int * nreconvliterals)6511 SCIP_RETCODE conflictAnalyzeRemainingBdchgs(
6512    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
6513    BMS_BLKMEM*           blkmem,             /**< block memory of transformed problem */
6514    SCIP_SET*             set,                /**< global SCIP settings */
6515    SCIP_STAT*            stat,               /**< problem statistics */
6516    SCIP_PROB*            prob,               /**< problem data */
6517    SCIP_TREE*            tree,               /**< branch and bound tree */
6518    SCIP_Bool             diving,             /**< are we in strong branching or diving mode? */
6519    int*                  lbchginfoposs,      /**< positions of currently active lower bound change information in variables' arrays */
6520    int*                  ubchginfoposs,      /**< positions of currently active upper bound change information in variables' arrays */
6521    int*                  nconss,             /**< pointer to store the number of generated conflict constraints */
6522    int*                  nliterals,          /**< pointer to store the number of literals in generated conflict constraints */
6523    int*                  nreconvconss,       /**< pointer to store the number of generated reconvergence constraints */
6524    int*                  nreconvliterals     /**< pointer to store the number of literals generated reconvergence constraints */
6525    )
6526 {
6527    SCIP_VAR** vars;
6528    SCIP_VAR* var;
6529    SCIP_CONFTYPE conftype;
6530    SCIP_Bool usescutoffbound;
6531    int nvars;
6532    int v;
6533    int nbdchgs;
6534    int maxsize;
6535 
6536    assert(prob != NULL);
6537    assert(lbchginfoposs != NULL);
6538    assert(ubchginfoposs != NULL);
6539    assert(nconss != NULL);
6540    assert(nliterals != NULL);
6541    assert(nreconvconss != NULL);
6542    assert(nreconvliterals != NULL);
6543 
6544    *nconss = 0;
6545    *nliterals = 0;
6546    *nreconvconss = 0;
6547    *nreconvliterals = 0;
6548 
6549    vars = prob->vars;
6550    nvars = prob->nvars;
6551    assert(nvars == 0 || vars != NULL);
6552 
6553    maxsize = 2*conflictCalcMaxsize(set, prob);
6554 
6555    /* initialize conflict data */
6556    conftype = conflict->conflictset->conflicttype;
6557    usescutoffbound = conflict->conflictset->usescutoffbound;
6558 
6559    SCIP_CALL( SCIPconflictInit(conflict, set, stat, prob, conftype, usescutoffbound) );
6560 
6561    conflict->conflictset->conflicttype = conftype;
6562    conflict->conflictset->usescutoffbound = usescutoffbound;
6563 
6564    /* add remaining bound changes to conflict queue */
6565    SCIPsetDebugMsg(set, "initial conflict set after undoing bound changes:\n");
6566 
6567    nbdchgs = 0;
6568    for( v = 0; v < nvars && nbdchgs < maxsize; ++v )
6569    {
6570       var = vars[v];
6571       assert(var != NULL);
6572       assert(var->nlbchginfos >= 0);
6573       assert(var->nubchginfos >= 0);
6574       assert(-1 <= lbchginfoposs[v] && lbchginfoposs[v] <= var->nlbchginfos);
6575       assert(-1 <= ubchginfoposs[v] && ubchginfoposs[v] <= var->nubchginfos);
6576 
6577       if( lbchginfoposs[v] == var->nlbchginfos || ubchginfoposs[v] == var->nubchginfos )
6578       {
6579          SCIP_BDCHGINFO* bdchginfo;
6580          SCIP_Real relaxedbd;
6581 
6582          /* the strong branching or diving bound stored in the column is responsible for the conflict:
6583           * it cannot be resolved and therefore has to be directly put into the conflict set
6584           */
6585          assert((lbchginfoposs[v] == var->nlbchginfos) != (ubchginfoposs[v] == var->nubchginfos)); /* only one can be tight in the dual! */
6586          assert(lbchginfoposs[v] < var->nlbchginfos || SCIPvarGetLbLP(var, set) > SCIPvarGetLbLocal(var));
6587          assert(ubchginfoposs[v] < var->nubchginfos || SCIPvarGetUbLP(var, set) < SCIPvarGetUbLocal(var));
6588 
6589          /* create an artificial bound change information for the diving/strong branching bound change;
6590           * they are freed in the SCIPconflictFlushConss() call
6591           */
6592          if( lbchginfoposs[v] == var->nlbchginfos )
6593          {
6594             SCIP_CALL( conflictCreateTmpBdchginfo(conflict, blkmem, set, var, SCIP_BOUNDTYPE_LOWER,
6595                   SCIPvarGetLbLocal(var), SCIPvarGetLbLP(var, set), &bdchginfo) );
6596             relaxedbd = SCIPvarGetLbLP(var, set);
6597          }
6598          else
6599          {
6600             SCIP_CALL( conflictCreateTmpBdchginfo(conflict, blkmem, set, var, SCIP_BOUNDTYPE_UPPER,
6601                   SCIPvarGetUbLocal(var), SCIPvarGetUbLP(var, set), &bdchginfo) );
6602             relaxedbd = SCIPvarGetUbLP(var, set);
6603          }
6604 
6605          /* put variable into the conflict set */
6606          SCIPsetDebugMsg(set, "   force: <%s> %s %g [status: %d, type: %d, dive/strong]\n",
6607             SCIPvarGetName(var), lbchginfoposs[v] == var->nlbchginfos ? ">=" : "<=",
6608             lbchginfoposs[v] == var->nlbchginfos ? SCIPvarGetLbLP(var, set) : SCIPvarGetUbLP(var, set),
6609             SCIPvarGetStatus(var), SCIPvarGetType(var));
6610          SCIP_CALL( conflictAddConflictBound(conflict, blkmem, set, bdchginfo, relaxedbd) );
6611 
6612          /* each variable which is add to the conflict graph gets an increase in the VSIDS
6613           *
6614           * @note That is different to the VSIDS preseted in the literature
6615           */
6616          SCIP_CALL( incVSIDS(var, blkmem, set, stat, SCIPbdchginfoGetBoundtype(bdchginfo), relaxedbd, set->conf_conflictgraphweight) );
6617          nbdchgs++;
6618       }
6619       else
6620       {
6621          /* put remaining bound changes into conflict candidate queue */
6622          if( lbchginfoposs[v] >= 0 )
6623          {
6624             SCIP_CALL( conflictAddBound(conflict, blkmem, set, stat, var, SCIP_BOUNDTYPE_LOWER, \
6625                   &var->lbchginfos[lbchginfoposs[v]], SCIPbdchginfoGetNewbound(&var->lbchginfos[lbchginfoposs[v]])) );
6626             nbdchgs++;
6627          }
6628          if( ubchginfoposs[v] >= 0 )
6629          {
6630             assert(!SCIPbdchginfoIsRedundant(&var->ubchginfos[ubchginfoposs[v]]));
6631             SCIP_CALL( conflictAddBound(conflict, blkmem, set, stat, var, SCIP_BOUNDTYPE_UPPER, \
6632                   &var->ubchginfos[ubchginfoposs[v]], SCIPbdchginfoGetNewbound(&var->ubchginfos[ubchginfoposs[v]])) );
6633             nbdchgs++;
6634          }
6635       }
6636    }
6637 
6638    if( v == nvars )
6639    {
6640       /* analyze the conflict set, and create conflict constraints on success */
6641       SCIP_CALL( conflictAnalyze(conflict, blkmem, set, stat, prob, tree, diving, 0, FALSE, nconss, nliterals, \
6642             nreconvconss, nreconvliterals) );
6643    }
6644 
6645    return SCIP_OKAY;
6646 }
6647 
6648 /** adds a weighted LP row to an aggregation row */
6649 static
addRowToAggrRow(SCIP_SET * set,SCIP_ROW * row,SCIP_Real weight,SCIP_AGGRROW * aggrrow)6650 SCIP_RETCODE addRowToAggrRow(
6651    SCIP_SET*             set,                /**< global SCIP settings */
6652    SCIP_ROW*             row,                /**< LP row */
6653    SCIP_Real             weight,             /**< weight for scaling */
6654    SCIP_AGGRROW*         aggrrow             /**< aggregation row */
6655    )
6656 {
6657    assert(set != NULL);
6658    assert(row != NULL);
6659    assert(weight != 0.0);
6660 
6661    /* add minimal value to dual row's left hand side: y_i < 0 -> lhs, y_i > 0 -> rhs */
6662    if( weight < 0.0 )
6663    {
6664       assert(!SCIPsetIsInfinity(set, -row->lhs));
6665       SCIP_CALL( SCIPaggrRowAddRow(set->scip, aggrrow, row, weight, -1) );
6666    }
6667    else
6668    {
6669       assert(!SCIPsetIsInfinity(set, row->rhs));
6670       SCIP_CALL( SCIPaggrRowAddRow(set->scip, aggrrow, row, weight, +1) );
6671    }
6672    SCIPsetDebugMsg(set, " -> add %s row <%s>[%g,%g](lp depth: %d): dual=%g -> dualrhs=%g\n",
6673       row->local ? "local" : "global",
6674       SCIProwGetName(row), row->lhs - row->constant, row->rhs - row->constant,
6675       row->lpdepth, weight, SCIPaggrRowGetRhs(aggrrow));
6676 
6677    return SCIP_OKAY;
6678 }
6679 
6680 /** checks validity of an LP row and a corresponding weight */
6681 static
checkDualFeasibility(SCIP_SET * set,SCIP_ROW * row,SCIP_Real weight,SCIP_Bool * zerocontribution)6682 SCIP_Bool checkDualFeasibility(
6683    SCIP_SET*             set,                /**< global SCIP settings */
6684    SCIP_ROW*             row,                /**< LP row */
6685    SCIP_Real             weight,             /**< weight for scaling */
6686    SCIP_Bool*            zerocontribution    /**< pointer to store whether every row entry is zero within tolerances */
6687    )
6688 {
6689    SCIP_Bool valid = TRUE;
6690 
6691    *zerocontribution = TRUE;
6692 
6693    /* dual solution values of 0.0 are always valid */
6694    if( REALABS(weight) > QUAD_EPSILON )
6695    {
6696       *zerocontribution = FALSE;
6697 
6698       /* check dual feasibility */
6699       if( (SCIPsetIsInfinity(set, -row->lhs) && weight > 0.0) || (SCIPsetIsInfinity(set, row->rhs) && weight < 0.0) )
6700       {
6701          int i;
6702 
6703          /* ignore slight numerical violations if the contribution of every component of the row is close to zero */
6704          if( weight > 0.0 )
6705             *zerocontribution = SCIPsetIsDualfeasZero(set, row->rhs * weight);
6706          else
6707             *zerocontribution = SCIPsetIsDualfeasZero(set, row->lhs * weight);
6708 
6709          for( i = 0; i < row->len && *zerocontribution; i++ )
6710          {
6711             if( !SCIPsetIsDualfeasZero(set, weight * row->vals[i]) )
6712                *zerocontribution = FALSE;
6713          }
6714 
6715          if( !(*zerocontribution) )
6716          {
6717             SCIPsetDebugMsg(set, " -> invalid dual solution value %g for row <%s>: lhs=%g, rhs=%g\n",
6718                weight, SCIProwGetName(row), row->lhs, row->rhs);
6719 
6720             valid = FALSE;
6721          }
6722       }
6723    }
6724 
6725    return valid;
6726 }
6727 
6728 /** sort local rows by increasing depth and number of nonzeros as tie-breaker */
6729 static
sortLocalRows(SCIP_SET * set,SCIP_AGGRROW * aggrrow,SCIP_ROW ** rows,int * rowinds,int * rowdepth,int nrows)6730 SCIP_RETCODE sortLocalRows(
6731    SCIP_SET*             set,                /**< global SCIP settings */
6732    SCIP_AGGRROW*         aggrrow,            /**< aggregation row */
6733    SCIP_ROW**            rows,               /**< array of local rows */
6734    int*                  rowinds,            /**< array of row indices */
6735    int*                  rowdepth,           /**< array of LP depths */
6736    int                   nrows               /**< number of local rows */
6737    )
6738 {
6739    int* rownnz;
6740    int i;
6741 
6742    assert(aggrrow != NULL);
6743    assert(rows != NULL);
6744    assert(nrows > 0);
6745    assert(rowinds != NULL);
6746    assert(rowdepth != NULL);
6747 
6748    /* sort row indices by increasing depth */
6749    SCIPsortIntInt(rowdepth, rowinds, nrows);
6750    assert(rowdepth[0] <= rowdepth[nrows-1]);
6751 
6752    SCIP_CALL( SCIPsetAllocBufferArray(set, &rownnz, nrows) );
6753 
6754    /* get number of nonzero entries for every row */
6755    for( i = 0; i < nrows; i++ )
6756    {
6757       SCIP_ROW* row = rows[rowinds[i]];
6758       assert(row != NULL);
6759 
6760       rownnz[i] = row->len;
6761    }
6762 
6763    /* since SCIP has no stable sorting function we sort each bucket separately */
6764    for( i = 0; i < nrows; i++ )
6765    {
6766       int j = i;
6767       int d = rowdepth[i];
6768 
6769       /* search for the next row with a greater depth */
6770       while( j+1 < nrows && rowdepth[j+1] == d )
6771          j++;
6772 
6773       /* the bucket has size one */
6774       if( j == i )
6775          continue;
6776 
6777       assert(j-i+1 <= nrows);
6778 
6779       /* sort row indices by increasing number of nonzero elements */
6780       SCIPsortIntIntInt(&rownnz[i], &rowdepth[i], &rowinds[i], j-i+1);
6781       assert(rownnz[i] <= rownnz[j]);
6782 
6783       i = j;
6784    } /*lint --e{850} i is modified in the body of the for loop */
6785 
6786 #ifndef NDEBUG
6787    for( i = 0; i < nrows-1; i++ )
6788       assert(rowdepth[i] < rowdepth[i+1] || (rowdepth[i] == rowdepth[i+1] && rownnz[i] <= rownnz[i+1]));
6789 #endif
6790 
6791    SCIPsetFreeBufferArray(set, &rownnz);
6792 
6793    return SCIP_OKAY;
6794 }
6795 
6796 /** adds locally valid rows to the proof constraint */
6797 static
addLocalRows(SCIP_SET * set,SCIP_PROB * transprob,SCIP_LP * lp,SCIP_AGGRROW * proofrow,SCIP_ROW ** rows,SCIP_Real * dualsols,int * localrowinds,int * localrowdepth,int nlocalrows,SCIP_Real * proofact,int * validdepth,SCIP_Real * curvarlbs,SCIP_Real * curvarubs,SCIP_Bool * valid)6798 SCIP_RETCODE addLocalRows(
6799    SCIP_SET*             set,                /**< global SCIP settings */
6800    SCIP_PROB*            transprob,          /**< transformed problem */
6801    SCIP_LP*              lp,                 /**< LP data */
6802    SCIP_AGGRROW*         proofrow,           /**< aggregated row representing the proof */
6803    SCIP_ROW**            rows,               /**< array if locally valid rows */
6804    SCIP_Real*            dualsols,           /**< dual solution vector */
6805    int*                  localrowinds,       /**< array of row indecies */
6806    int*                  localrowdepth,      /**< array of row depths */
6807    int                   nlocalrows,         /**< number of local rows stored in rows array */
6808    SCIP_Real*            proofact,           /**< pointer to store the activity of the proof constraint */
6809    int*                  validdepth,         /**< pointer to store the depth where the proof constraint is valid */
6810    SCIP_Real*            curvarlbs,          /**< current lower bounds of active problem variables */
6811    SCIP_Real*            curvarubs,          /**< current upper bounds of active problem variables */
6812    SCIP_Bool*            valid               /**< pointer store whether the proof constraint is valid */
6813    )
6814 {
6815    SCIP_Bool infdelta;
6816    int i;
6817 
6818    assert(set != NULL);
6819    assert(lp != NULL);
6820 
6821    *validdepth = 0;
6822 
6823    if( !set->conf_uselocalrows )
6824       return SCIP_OKAY;
6825 
6826    SCIPsetDebugMsg(set, "add local rows to dual proof:\n");
6827 
6828    /* check whether the proof is already valid, e.g., violated within the local bounds */
6829    *proofact = aggrRowGetMinActivity(set, transprob, proofrow, curvarlbs, curvarubs, &infdelta);
6830 
6831    /* we stop if the minimal activity is infinite but all variables have a finite activity delta (bad numerics) */
6832    if( !infdelta && SCIPsetIsInfinity(set, REALABS(*proofact)) )
6833    {
6834       *valid = FALSE;
6835       return SCIP_OKAY;
6836    }
6837 
6838    /* break if the proof is valid w.r.t local bounds
6839     * note: it can happen that the proof contains a variable with an infinite activity delta.
6840     *       here, we don't break immediately because we might be able to fix it by adding local rows
6841     */
6842    if( !infdelta && SCIPsetIsGT(set, *proofact, SCIPaggrRowGetRhs(proofrow)) )
6843    {
6844       *valid = TRUE;
6845       return SCIP_OKAY;
6846    }
6847 
6848    /* sort local rows by depth */
6849    SCIP_CALL( sortLocalRows(set, proofrow, rows, localrowinds, localrowdepth, nlocalrows) );
6850 
6851    /* add successively local rows */
6852    for( i = 0; i < nlocalrows; ++i )
6853    {
6854       SCIP_ROW* row;
6855       int r;
6856 
6857       r = localrowinds[i];
6858       row = rows[r];
6859 
6860       assert(row != NULL);
6861       assert(row->len == 0 || row->cols != NULL);
6862       assert(row->len == 0 || row->vals != NULL);
6863       assert(row == lp->lpirows[r]);
6864       assert(row->local);
6865       assert(row->lpdepth == localrowdepth[i]);
6866 
6867       /* ignore dual solution values of 0.0 (in this case: y_i == 0) */
6868       if( REALABS(dualsols[r]) > 0.0 )
6869       {
6870 #ifndef NDEBUG
6871          SCIP_Bool zerocontribution;
6872 
6873          /* check dual feasibility */
6874          *valid = checkDualFeasibility(set, row, dualsols[r], &zerocontribution);
6875          assert(*valid);
6876          assert(!zerocontribution);
6877 #endif
6878 
6879          if( SCIPsetIsDualfeasZero(set, dualsols[r]) )
6880             continue;
6881 
6882          /* add row to dual proof */
6883          SCIP_CALL( addRowToAggrRow(set, row, -dualsols[r], proofrow) );
6884 
6885          /* update depth where the proof is valid */
6886          if( *validdepth < localrowdepth[i] )
6887             *validdepth = localrowdepth[i];
6888 
6889          /* get the new minimal activity */
6890          *proofact = aggrRowGetMinActivity(set, transprob, proofrow, curvarlbs, curvarubs, &infdelta);
6891 
6892          /* we stop if the minimal activity is infinite but all variables have a finite activity delta (bad numerics) */
6893          if( !infdelta && SCIPsetIsInfinity(set, REALABS(*proofact)) )
6894          {
6895             *valid = FALSE;
6896             goto TERMINATE;
6897          }
6898 
6899          /* break if the proof is valid w.r.t local bounds */
6900          if( !infdelta && SCIPsetIsGT(set, *proofact, SCIPaggrRowGetRhs(proofrow)) )
6901          {
6902             *valid = TRUE;
6903             break;
6904          }
6905       }
6906    }
6907 
6908    /* remove all nearly zero coefficients */
6909    SCIPaggrRowRemoveZeros(set->scip, proofrow, TRUE, valid);
6910 
6911   TERMINATE:
6912    if( !(*valid) )
6913    {
6914       SCIPsetDebugMsg(set, " -> proof is not valid: %g <= %g\n", *proofact, SCIPaggrRowGetRhs(proofrow));
6915       SCIPsetDebugMsg(set, " -> stop due to numerical troubles\n");
6916    }
6917    else
6918    {
6919       *proofact = aggrRowGetMinActivity(set, transprob, proofrow, curvarlbs, curvarubs, &infdelta);
6920 
6921       /* we stop if the minimal activity is infinite but all variables have a finite activity delta (bad numerics) */
6922       if( !infdelta && SCIPsetIsInfinity(set, REALABS(*proofact)) )
6923       {
6924          *valid = FALSE;
6925          SCIPsetDebugMsg(set, " -> proof is not valid: %g <= %g [infdelta: %d]\n", *proofact, SCIPaggrRowGetRhs(proofrow), infdelta);
6926       }
6927       else if( infdelta || SCIPsetIsLE(set, *proofact, SCIPaggrRowGetRhs(proofrow)) )
6928       {
6929          *valid = FALSE;
6930          SCIPsetDebugMsg(set, " -> proof is not valid: %g <= %g [infdelta: %d]\n", *proofact, SCIPaggrRowGetRhs(proofrow), infdelta);
6931       }
6932    }
6933 
6934    return SCIP_OKAY;
6935 }
6936 
6937 /** calculates a Farkas proof from the current dual LP solution */
6938 static
getFarkasProof(SCIP_SET * set,SCIP_PROB * prob,SCIP_LP * lp,SCIP_LPI * lpi,SCIP_TREE * tree,SCIP_AGGRROW * farkasrow,SCIP_Real * farkasact,int * validdepth,SCIP_Real * curvarlbs,SCIP_Real * curvarubs,SCIP_Bool * valid)6939 SCIP_RETCODE getFarkasProof(
6940    SCIP_SET*             set,                /**< global SCIP settings */
6941    SCIP_PROB*            prob,               /**< transformed problem */
6942    SCIP_LP*              lp,                 /**< LP data */
6943    SCIP_LPI*             lpi,                /**< LPI data */
6944    SCIP_TREE*            tree,               /**< tree data */
6945    SCIP_AGGRROW*         farkasrow,          /**< aggregated row representing the proof */
6946    SCIP_Real*            farkasact,          /**< maximal activity of the proof constraint */
6947    int*                  validdepth,         /**< pointer to store the valid depth of the proof constraint */
6948    SCIP_Real*            curvarlbs,          /**< current lower bounds of active problem variables */
6949    SCIP_Real*            curvarubs,          /**< current upper bounds of active problem variables */
6950    SCIP_Bool*            valid               /**< pointer store whether the proof constraint is valid */
6951    )
6952 {
6953    SCIP_ROW** rows;
6954    SCIP_Real* dualfarkas;
6955    SCIP_ROW* row;
6956    int* localrowinds;
6957    int* localrowdepth;
6958    SCIP_Bool infdelta;
6959    int nlocalrows;
6960    int nrows;
6961    int r;
6962 
6963    assert(set != NULL);
6964    assert(prob != NULL);
6965    assert(lp != NULL);
6966    assert(lp->flushed);
6967    assert(lp->solved);
6968    assert(curvarlbs != NULL);
6969    assert(curvarubs != NULL);
6970    assert(valid != NULL);
6971 
6972    assert(SCIPlpiIsPrimalInfeasible(lpi) || SCIPlpiIsObjlimExc(lpi) || SCIPlpiIsDualFeasible(lpi));
6973    assert(SCIPlpiIsPrimalInfeasible(lpi) || !SCIPlpDivingObjChanged(lp));
6974 
6975    /* get LP rows and problem variables */
6976    rows = SCIPlpGetRows(lp);
6977    nrows = SCIPlpGetNRows(lp);
6978    assert(nrows == 0 || rows != NULL);
6979    assert(nrows == lp->nlpirows);
6980 
6981    /* it can happen that infeasibility is detetected within LP presolve. in that case, the LP solver may not be able to
6982     * to return the dual ray.
6983     */
6984    if( !SCIPlpiHasDualRay(lpi) )
6985    {
6986       *valid = FALSE;
6987       return SCIP_OKAY;
6988    }
6989 
6990    assert(farkasrow != NULL);
6991 
6992    /* allocate temporary memory */
6993    SCIP_CALL( SCIPsetAllocBufferArray(set, &dualfarkas, nrows) );
6994    BMSclearMemoryArray(dualfarkas, nrows);
6995 
6996    /* get dual Farkas values of rows */
6997    SCIP_CALL( SCIPlpiGetDualfarkas(lpi, dualfarkas) );
6998 
6999    localrowinds = NULL;
7000    localrowdepth = NULL;
7001    nlocalrows = 0;
7002 
7003    /* calculate the Farkas row */
7004    (*valid) = TRUE;
7005    (*validdepth) = 0;
7006 
7007    for( r = 0; r < nrows; ++r )
7008    {
7009       row = rows[r];
7010       assert(row != NULL);
7011       assert(row->len == 0 || row->cols != NULL);
7012       assert(row->len == 0 || row->vals != NULL);
7013       assert(row == lp->lpirows[r]);
7014 
7015       /* ignore dual ray values of 0.0 (in this case: y_i == z_i == 0) */
7016       if( REALABS(dualfarkas[r]) > 0.0 )
7017       {
7018          SCIP_Bool zerocontribution;
7019 
7020          /* check dual feasibility */
7021          *valid = checkDualFeasibility(set, row, dualfarkas[r], &zerocontribution);
7022 
7023          if( !(*valid) )
7024             goto TERMINATE;
7025 
7026          if( zerocontribution )
7027             continue;
7028 
7029          if( SCIPsetIsDualfeasZero(set, dualfarkas[r]) )
7030             continue;
7031 
7032          if( !row->local )
7033          {
7034             SCIP_CALL( addRowToAggrRow(set, row, -dualfarkas[r], farkasrow) );
7035 
7036             /* due to numerical reasons we want to stop */
7037             if( REALABS(SCIPaggrRowGetRhs(farkasrow)) > NUMSTOP )
7038             {
7039                (*valid) = FALSE;
7040                goto TERMINATE;
7041             }
7042          }
7043          else
7044          {
7045             int lpdepth = SCIProwGetLPDepth(row);
7046 
7047             if( nlocalrows == 0 && lpdepth < SCIPtreeGetFocusDepth(tree) )
7048             {
7049                SCIP_CALL( SCIPsetAllocBufferArray(set, &localrowinds, nrows-r) );
7050                SCIP_CALL( SCIPsetAllocBufferArray(set, &localrowdepth, nrows-r) );
7051             }
7052 
7053             if( lpdepth < SCIPtreeGetFocusDepth(tree) )
7054             {
7055                assert(localrowinds != NULL);
7056                assert(localrowdepth != NULL);
7057 
7058                localrowinds[nlocalrows] = r;
7059                localrowdepth[nlocalrows++] = lpdepth;
7060             }
7061          }
7062       }
7063    }
7064 
7065    /* remove all coefficients that are too close to zero */
7066    SCIPaggrRowRemoveZeros(set->scip, farkasrow, TRUE, valid);
7067 
7068    if( !(*valid) )
7069       goto TERMINATE;
7070 
7071    infdelta = FALSE;
7072 
7073    /* calculate the current Farkas activity, always using the best bound w.r.t. the Farkas coefficient */
7074    *farkasact = aggrRowGetMinActivity(set, prob, farkasrow, curvarlbs, curvarubs, &infdelta);
7075 
7076    SCIPsetDebugMsg(set, " -> farkasact=%g farkasrhs=%g [infdelta: %d], \n",
7077       (*farkasact), SCIPaggrRowGetRhs(farkasrow), infdelta);
7078 
7079    /* The constructed proof is not valid, this can happen due to numerical reasons,
7080     * e.g., we only consider rows r with !SCIPsetIsZero(set, dualfarkas[r]),
7081     * or because of local rows were ignored so far.
7082     * Due to the latter case, it might happen at least one variable contributes
7083     * with an infinite value to the activity (see: https://git.zib.de/integer/scip/issues/2743)
7084     */
7085    if( infdelta || SCIPsetIsFeasLE(set, *farkasact, SCIPaggrRowGetRhs(farkasrow)))
7086    {
7087       /* add contribution of local rows */
7088       if( nlocalrows > 0 && set->conf_uselocalrows > 0 )
7089       {
7090          SCIP_CALL( addLocalRows(set, prob, lp, farkasrow, rows, dualfarkas, localrowinds, localrowdepth,
7091                nlocalrows, farkasact, validdepth, curvarlbs, curvarubs, valid) );
7092       }
7093       else
7094       {
7095          (*valid) = FALSE;
7096          SCIPsetDebugMsg(set, " -> proof is not valid to due infinite activity delta\n");
7097       }
7098    }
7099 
7100   TERMINATE:
7101 
7102    SCIPfreeBufferArrayNull(set->scip, &localrowdepth);
7103    SCIPfreeBufferArrayNull(set->scip, &localrowinds);
7104    SCIPsetFreeBufferArray(set, &dualfarkas);
7105 
7106    return SCIP_OKAY;
7107 }
7108 
7109 /** calculates a Farkas proof from the current dual LP solution */
7110 static
getDualProof(SCIP_SET * set,SCIP_PROB * transprob,SCIP_LP * lp,SCIP_LPI * lpi,SCIP_TREE * tree,SCIP_AGGRROW * farkasrow,SCIP_Real * farkasact,int * validdepth,SCIP_Real * curvarlbs,SCIP_Real * curvarubs,SCIP_Bool * valid)7111 SCIP_RETCODE getDualProof(
7112    SCIP_SET*             set,                /**< global SCIP settings */
7113    SCIP_PROB*            transprob,          /**< transformed problem */
7114    SCIP_LP*              lp,                 /**< LP data */
7115    SCIP_LPI*             lpi,                /**< LPI data */
7116    SCIP_TREE*            tree,               /**< tree data */
7117    SCIP_AGGRROW*         farkasrow,          /**< aggregated row representing the proof */
7118    SCIP_Real*            farkasact,          /**< maximal activity of the proof constraint */
7119    int*                  validdepth,         /**< pointer to store the valid depth of the proof constraint */
7120    SCIP_Real*            curvarlbs,          /**< current lower bounds of active problem variables */
7121    SCIP_Real*            curvarubs,          /**< current upper bounds of active problem variables */
7122    SCIP_Bool*            valid               /**< pointer store whether the proof constraint is valid */
7123    )
7124 {
7125    SCIP_RETCODE retcode;
7126    SCIP_ROW** rows;
7127    SCIP_ROW* row;
7128    SCIP_Real* primsols;
7129    SCIP_Real* dualsols;
7130    SCIP_Real* redcosts;
7131    int* localrowinds;
7132    int* localrowdepth;
7133    SCIP_Real maxabsdualsol;
7134    SCIP_Bool infdelta;
7135    int nlocalrows;
7136    int nrows;
7137    int ncols;
7138    int r;
7139 
7140    assert(set != NULL);
7141    assert(transprob != NULL);
7142    assert(lp != NULL);
7143    assert(lp->flushed);
7144    assert(lp->solved);
7145    assert(curvarlbs != NULL);
7146    assert(curvarubs != NULL);
7147    assert(valid != NULL);
7148 
7149    *validdepth = 0;
7150    *valid = TRUE;
7151 
7152    localrowinds = NULL;
7153    localrowdepth = NULL;
7154    nlocalrows = 0;
7155 
7156    /* get LP rows and problem variables */
7157    rows = SCIPlpGetRows(lp);
7158    nrows = SCIPlpGetNRows(lp);
7159    ncols = SCIPlpGetNCols(lp);
7160    assert(nrows == 0 || rows != NULL);
7161    assert(nrows == lp->nlpirows);
7162 
7163    /* get temporary memory */
7164    SCIP_CALL( SCIPsetAllocBufferArray(set, &primsols, ncols) );
7165    SCIP_CALL( SCIPsetAllocBufferArray(set, &dualsols, nrows) );
7166    SCIP_CALL( SCIPsetAllocBufferArray(set, &redcosts, ncols) );
7167 
7168    /* get solution from LPI */
7169    retcode = SCIPlpiGetSol(lpi, NULL, primsols, dualsols, NULL, redcosts);
7170    if( retcode == SCIP_LPERROR ) /* on an error in the LP solver, just abort the conflict analysis */
7171    {
7172       (*valid) = FALSE;
7173       goto TERMINATE;
7174    }
7175    SCIP_CALL( retcode );
7176 #ifdef SCIP_DEBUG
7177    {
7178       SCIP_Real objval;
7179       SCIP_CALL( SCIPlpiGetObjval(lpi, &objval) );
7180       SCIPsetDebugMsg(set, " -> LP objval: %g\n", objval);
7181    }
7182 #endif
7183 
7184    /* check whether the dual solution is numerically stable */
7185    maxabsdualsol = 0;
7186    for( r = 0; r < nrows; r++ )
7187    {
7188       SCIP_Real absdualsol = REALABS(dualsols[r]);
7189 
7190       if( absdualsol > maxabsdualsol )
7191          maxabsdualsol = absdualsol;
7192    }
7193 
7194    /* don't consider dual solution with maxabsdualsol > 1e+07, this would almost cancel out the objective constraint */
7195    if( maxabsdualsol > 1e+07 )
7196    {
7197       (*valid) = FALSE;
7198       goto TERMINATE;
7199    }
7200 
7201    /* clear the proof */
7202    SCIPaggrRowClear(farkasrow);
7203 
7204    /* Let y be the dual solution and r be the reduced cost vector. Let z be defined as
7205     *    z_i := y_i if i is a global row,
7206     *    z_i := 0   if i is a local row.
7207     * Define the set X := {x | lhs <= Ax <= rhs, lb <= x <= ub, c^Tx <= c*}, with c* being the current primal bound.
7208     * Then the following inequalities are valid for all x \in X:
7209     *                                 - c* <= -c^Tx
7210     *   <=>                     z^TAx - c* <= (z^TA - c^T) x
7211     *   <=>                     z^TAx - c* <= (y^TA - c^T - (y-z)^TA) x
7212     *   <=>                     z^TAx - c* <= (-r^T - (y-z)^TA) x         (dual feasibility of (y,r): y^TA + r^T == c^T)
7213     * Because lhs <= Ax <= rhs and lb <= x <= ub, the inequality can be relaxed to give
7214     *     min{z^Tq | lhs <= q <= rhs} - c* <= max{(-r^T - (y-z)^TA) x | lb <= x <= ub}, or X = {}.
7215     *
7216     * The resulting dual row is:  z^T{lhs,rhs} - c* <= (-r^T - (y-z)^TA){lb,ub},
7217     * where lhs, rhs, lb, and ub are selected in order to maximize the feasibility of the row.
7218     */
7219 
7220    /* add the objective function to the aggregation row with current cutoff bound as right-hand side
7221     *
7222     * use a slightly tighter cutoff bound, because solutions with equal objective value should also be declared
7223     * infeasible
7224     */
7225    SCIP_CALL( SCIPaggrRowAddObjectiveFunction(set->scip, farkasrow, lp->cutoffbound - SCIPsetSumepsilon(set), 1.0) );
7226 
7227    /* dual row: z^T{lhs,rhs} - c* <= (-r^T - (y-z)^TA){lb,ub}
7228     * process rows: add z^T{lhs,rhs} to the dual row's left hand side, and -(y-z)^TA to the dual row's coefficients
7229     */
7230    for( r = 0; r < nrows; ++r )
7231    {
7232       row = rows[r];
7233       assert(row != NULL);
7234       assert(row->len == 0 || row->cols != NULL);
7235       assert(row->len == 0 || row->vals != NULL);
7236       assert(row == lp->lpirows[r]);
7237 
7238       /* ignore dual solution values of 0.0 (in this case: y_i == z_i == 0) */
7239       if( REALABS(dualsols[r]) > 0.0 )
7240       {
7241          SCIP_Bool zerocontribution;
7242 
7243          /* check dual feasibility */
7244          *valid = checkDualFeasibility(set, row, dualsols[r], &zerocontribution);
7245 
7246          if( !(*valid) )
7247             goto TERMINATE;
7248 
7249          if( zerocontribution )
7250             continue;
7251 
7252          if( SCIPsetIsDualfeasZero(set, dualsols[r]) )
7253             continue;
7254 
7255          /* skip local row */
7256          if( !row->local )
7257          {
7258             SCIP_CALL( addRowToAggrRow(set, row, -dualsols[r], farkasrow) );
7259 
7260             /* due to numerical reasons we want to stop */
7261             if( REALABS(SCIPaggrRowGetRhs(farkasrow)) > NUMSTOP )
7262             {
7263                (*valid) = FALSE;
7264                goto TERMINATE;
7265             }
7266          }
7267          else
7268          {
7269             int lpdepth = SCIProwGetLPDepth(row);
7270 
7271             if( nlocalrows == 0 && lpdepth < SCIPtreeGetFocusDepth(tree) )
7272             {
7273                SCIP_CALL( SCIPsetAllocBufferArray(set, &localrowinds, nrows-r) );
7274                SCIP_CALL( SCIPsetAllocBufferArray(set, &localrowdepth, nrows-r) );
7275             }
7276 
7277             if( lpdepth < SCIPtreeGetFocusDepth(tree) )
7278             {
7279                assert(localrowinds != NULL);
7280                assert(localrowdepth != NULL);
7281 
7282                localrowinds[nlocalrows] = r;
7283                localrowdepth[nlocalrows++] = lpdepth;
7284             }
7285          }
7286       }
7287    }
7288 
7289    /* remove all nearly zero coefficients */
7290    SCIPaggrRowRemoveZeros(set->scip, farkasrow, TRUE, valid);
7291 
7292    if( !(*valid) )
7293       goto TERMINATE;
7294 
7295    infdelta = FALSE;
7296 
7297    /* check validity of the proof */
7298    *farkasact = aggrRowGetMinActivity(set, transprob, farkasrow, curvarlbs, curvarubs, &infdelta);
7299 
7300    SCIPsetDebugMsg(set, " -> farkasact=%g farkasrhs=%g [infdelta: %d], \n",
7301       (*farkasact), SCIPaggrRowGetRhs(farkasrow), infdelta);
7302 
7303    /* The constructed proof is not valid, this can happen due to numerical reasons,
7304     * e.g., we only consider rows r with !SCIPsetIsZero(set, dualsol[r]),
7305     * or because of local rows were ignored so far.
7306     * Due to the latter case, it might happen at least one variable contributes
7307     * with an infinite value to the activity (see: https://git.zib.de/integer/scip/issues/2743)
7308     */
7309    if( infdelta || SCIPsetIsFeasLE(set, *farkasact, SCIPaggrRowGetRhs(farkasrow)))
7310    {
7311       /* add contribution of local rows */
7312       if( nlocalrows > 0 && set->conf_uselocalrows > 0 )
7313       {
7314          SCIP_CALL( addLocalRows(set, transprob, lp, farkasrow, rows, dualsols, localrowinds, localrowdepth,
7315                nlocalrows, farkasact, validdepth, curvarlbs, curvarubs, valid) );
7316       }
7317       else
7318       {
7319          (*valid) = FALSE;
7320          SCIPsetDebugMsg(set, " -> proof is not valid to due infinite activity delta\n");
7321       }
7322    }
7323 
7324   TERMINATE:
7325 
7326    SCIPfreeBufferArrayNull(set->scip, &localrowdepth);
7327    SCIPfreeBufferArrayNull(set->scip, &localrowinds);
7328    SCIPsetFreeBufferArray(set, &redcosts);
7329    SCIPsetFreeBufferArray(set, &dualsols);
7330    SCIPsetFreeBufferArray(set, &primsols);
7331 
7332    return SCIP_OKAY;
7333 }
7334 
7335 #ifdef SCIP_DEBUG
7336 static
debugPrintViolationInfo(SCIP_SET * set,SCIP_Real minact,SCIP_Real rhs,const char * infostr)7337 void debugPrintViolationInfo(
7338    SCIP_SET*             set,                /**< global SCIP settings */
7339    SCIP_Real             minact,             /**< min activity */
7340    SCIP_Real             rhs,                /**< right hand side */
7341    const char*           infostr             /**< additional info for this debug message, or NULL */
7342    )
7343 {
7344    SCIPsetDebugMsg(set, "-> %sminact=%.15g rhs=%.15g violation=%.15g\n",infostr != NULL ? infostr : "" , minact, rhs, minact - rhs);
7345 }
7346 #else
7347 #define debugPrintViolationInfo(...) /**/
7348 #endif
7349 
7350 /** apply coefficient tightening */
7351 static
tightenCoefficients(SCIP_SET * set,SCIP_PROOFSET * proofset,int * nchgcoefs,SCIP_Bool * redundant)7352 void tightenCoefficients(
7353    SCIP_SET*             set,                /**< global SCIP settings */
7354    SCIP_PROOFSET*        proofset,           /**< proof set */
7355    int*                  nchgcoefs,          /**< pointer to store number of changed coefficients */
7356    SCIP_Bool*            redundant           /**< pointer to store whether the proof set is redundant */
7357    )
7358 {
7359 #ifdef SCIP_DEBUG
7360    SCIP_Real absmax = 0.0;
7361    SCIP_Real absmin = SCIPsetInfinity(set);
7362    int i;
7363 
7364    for( i = 0; i < proofset->nnz; i++ )
7365    {
7366       absmax = MAX(absmax, REALABS(proofset->vals[i]));
7367       absmin = MIN(absmin, REALABS(proofset->vals[i]));
7368    }
7369 #endif
7370 
7371    (*redundant) = SCIPcutsTightenCoefficients(set->scip, FALSE, proofset->vals, &proofset->rhs, proofset->inds, &proofset->nnz, nchgcoefs);
7372 
7373 #ifdef SCIP_DEBUG
7374    {
7375       SCIP_Real newabsmax = 0.0;
7376       SCIP_Real newabsmin = SCIPsetInfinity(set);
7377 
7378       for( i = 0; i < proofset->nnz; i++ )
7379       {
7380          newabsmax = MAX(newabsmax, REALABS(proofset->vals[i]));
7381          newabsmin = MIN(newabsmin, REALABS(proofset->vals[i]));
7382       }
7383 
7384       SCIPsetDebugMsg(set, "coefficient tightening: [%.15g,%.15g] -> [%.15g,%.15g] (nnz: %d, nchg: %d rhs: %.15g)\n",
7385             absmin, absmax, newabsmin, newabsmax, proofsetGetNVars(proofset), *nchgcoefs, proofsetGetRhs(proofset));
7386       printf("coefficient tightening: [%.15g,%.15g] -> [%.15g,%.15g] (nnz: %d, nchg: %d rhs: %.15g)\n",
7387             absmin, absmax, newabsmin, newabsmax, proofsetGetNVars(proofset), *nchgcoefs, proofsetGetRhs(proofset));
7388    }
7389 #endif
7390 }
7391 
7392 /** try to generate alternative proofs by applying subadditive functions */
7393 static
separateAlternativeProofs(SCIP_CONFLICT * conflict,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * transprob,SCIP_TREE * tree,BMS_BLKMEM * blkmem,SCIP_AGGRROW * proofrow,SCIP_Real * curvarlbs,SCIP_Real * curvarubs,SCIP_CONFTYPE conflicttype)7394 SCIP_RETCODE separateAlternativeProofs(
7395    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
7396    SCIP_SET*             set,                /**< global SCIP settings */
7397    SCIP_STAT*            stat,               /**< dynamic SCIP statistics */
7398    SCIP_PROB*            transprob,          /**< transformed problem */
7399    SCIP_TREE*            tree,               /**< tree data */
7400    BMS_BLKMEM*           blkmem,             /**< block memory */
7401    SCIP_AGGRROW*         proofrow,           /**< proof rows data */
7402    SCIP_Real*            curvarlbs,          /**< current lower bounds of active problem variables */
7403    SCIP_Real*            curvarubs,          /**< current upper bounds of active problem variables */
7404    SCIP_CONFTYPE         conflicttype        /**< type of the conflict */
7405    )
7406 {
7407    SCIP_VAR** vars;
7408    SCIP_SOL* refsol;
7409    SCIP_Real* cutcoefs;
7410    SCIP_Real cutefficacy;
7411    SCIP_Real cutrhs;
7412    SCIP_Real proofefficiacy;
7413    SCIP_Real efficiacynorm;
7414    SCIP_Bool islocal;
7415    SCIP_Bool cutsuccess;
7416    SCIP_Bool success;
7417    SCIP_Bool infdelta;
7418    int* cutinds;
7419    int* inds;
7420    int cutnnz;
7421    int nnz;
7422    int nvars;
7423    int i;
7424 
7425    vars = SCIPprobGetVars(transprob);
7426    nvars = SCIPprobGetNVars(transprob);
7427 
7428    inds = SCIPaggrRowGetInds(proofrow);
7429    nnz = SCIPaggrRowGetNNz(proofrow);
7430 
7431    proofefficiacy = aggrRowGetMinActivity(set, transprob, proofrow, curvarlbs, curvarubs, &infdelta);
7432 
7433    if( infdelta )
7434       return SCIP_OKAY;
7435 
7436    proofefficiacy -= SCIPaggrRowGetRhs(proofrow);
7437 
7438    efficiacynorm = SCIPaggrRowCalcEfficacyNorm(set->scip, proofrow);
7439    proofefficiacy /= MAX(1e-6, efficiacynorm);
7440 
7441    /* create reference solution */
7442    SCIP_CALL( SCIPcreateSol(set->scip, &refsol, NULL) );
7443 
7444    /* initialize with average solution */
7445    for( i = 0; i < nvars; i++ )
7446    {
7447       SCIP_CALL( SCIPsolSetVal(refsol, set, stat, tree, vars[i], SCIPvarGetAvgSol(vars[i])) );
7448    }
7449 
7450    /* set all variables that are part of the proof to its active local bound */
7451    for( i = 0; i < nnz; i++ )
7452    {
7453       SCIP_Real val = SCIPaggrRowGetProbvarValue(proofrow, inds[i]);
7454 
7455       if( val > 0.0 )
7456       {
7457          SCIP_CALL( SCIPsolSetVal(refsol, set, stat, tree, vars[inds[i]], curvarubs[inds[i]]) );
7458       }
7459       else
7460       {
7461          SCIP_CALL( SCIPsolSetVal(refsol, set, stat, tree, vars[inds[i]], curvarlbs[inds[i]]) );
7462       }
7463    }
7464 
7465    SCIP_CALL( SCIPsetAllocBufferArray(set, &cutcoefs, nvars) );
7466    SCIP_CALL( SCIPsetAllocBufferArray(set, &cutinds, nvars) );
7467 
7468    cutnnz = 0;
7469    cutefficacy = -SCIPsetInfinity(set);
7470 
7471    /* apply flow cover */
7472    SCIP_CALL( SCIPcalcFlowCover(set->scip, refsol, POSTPROCESS, BOUNDSWITCH, ALLOWLOCAL, proofrow, \
7473          cutcoefs, &cutrhs, cutinds, &cutnnz, &cutefficacy, NULL, &islocal, &cutsuccess) );
7474    success = cutsuccess;
7475 
7476    /* apply MIR */
7477    SCIP_CALL( SCIPcutGenerationHeuristicCMIR(set->scip, refsol, POSTPROCESS, BOUNDSWITCH, USEVBDS, ALLOWLOCAL, INT_MAX, \
7478          NULL, NULL, MINFRAC, MAXFRAC, proofrow, cutcoefs, &cutrhs, cutinds, &cutnnz, &cutefficacy, NULL, \
7479          &islocal, &cutsuccess) );
7480    success = (success || cutsuccess);
7481 
7482    /* replace the current proof */
7483    if( success && !islocal && SCIPsetIsPositive(set, cutefficacy) && cutefficacy * nnz > proofefficiacy * cutnnz )
7484    {
7485       SCIP_PROOFSET* alternativeproofset;
7486       SCIP_Bool redundant;
7487       int nchgcoefs;
7488 
7489       SCIP_CALL( proofsetCreate(&alternativeproofset, blkmem) );
7490       alternativeproofset->conflicttype = (conflicttype == SCIP_CONFTYPE_INFEASLP ? SCIP_CONFTYPE_ALTINFPROOF : SCIP_CONFTYPE_ALTBNDPROOF);
7491 
7492       SCIP_CALL( proofsetAddSparseData(alternativeproofset, blkmem, cutcoefs, cutinds, cutnnz, cutrhs) );
7493 
7494       /* apply coefficient tightening */
7495       tightenCoefficients(set, alternativeproofset, &nchgcoefs, &redundant);
7496 
7497       if( !redundant )
7498       {
7499          SCIP_CALL( conflictInsertProofset(conflict, set, alternativeproofset) );
7500       }
7501       else
7502       {
7503          proofsetFree(&alternativeproofset, blkmem);
7504       }
7505    }  /*lint !e438*/
7506 
7507    SCIPsetFreeBufferArray(set, &cutinds);
7508    SCIPsetFreeBufferArray(set, &cutcoefs);
7509 
7510    SCIP_CALL( SCIPfreeSol(set->scip, &refsol) );
7511 
7512    return SCIP_OKAY;
7513 }
7514 
7515 /** tighten a given infeasibility proof a^Tx <= b with minact > b w.r.t. local bounds
7516  *
7517  *  1) Apply cut generating functions
7518  *    - c-MIR
7519  *    - Flow-cover
7520  *    - TODO: implement other subadditive functions
7521  *  2) Remove continuous variables contributing with its global bound
7522  *    - TODO: implement a variant of non-zero-cancellation
7523  */
7524 static
tightenDualproof(SCIP_CONFLICT * conflict,SCIP_SET * set,SCIP_STAT * stat,BMS_BLKMEM * blkmem,SCIP_PROB * transprob,SCIP_TREE * tree,SCIP_AGGRROW * proofrow,int validdepth,SCIP_Real * curvarlbs,SCIP_Real * curvarubs,SCIP_Bool initialproof)7525 SCIP_RETCODE tightenDualproof(
7526    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
7527    SCIP_SET*             set,                /**< global SCIP settings */
7528    SCIP_STAT*            stat,               /**< dynamic SCIP statistics */
7529    BMS_BLKMEM*           blkmem,             /**< block memory */
7530    SCIP_PROB*            transprob,          /**< transformed problem */
7531    SCIP_TREE*            tree,               /**< tree data */
7532    SCIP_AGGRROW*         proofrow,           /**< aggregated row representing the proof */
7533    int                   validdepth,         /**< depth where the proof is valid */
7534    SCIP_Real*            curvarlbs,          /**< current lower bounds of active problem variables */
7535    SCIP_Real*            curvarubs,          /**< current upper bounds of active problem variables */
7536    SCIP_Bool             initialproof        /**< do we analyze the initial reason of infeasibility? */
7537    )
7538 {
7539    SCIP_VAR** vars;
7540    SCIP_Real* vals;
7541    int* inds;
7542    SCIP_PROOFSET* proofset;
7543    SCIP_Bool valid;
7544    SCIP_Bool redundant;
7545    int nnz;
7546    int nchgcoefs;
7547    int nbinvars;
7548    int ncontvars;
7549    int nintvars;
7550    int i;
7551 
7552    assert(conflict->proofset != NULL);
7553    assert(curvarlbs != NULL);
7554    assert(curvarubs != NULL);
7555 
7556    vars = SCIPprobGetVars(transprob);
7557    nbinvars = 0;
7558    nintvars = 0;
7559    ncontvars = 0;
7560 
7561    inds = SCIPaggrRowGetInds(proofrow);
7562    nnz = SCIPaggrRowGetNNz(proofrow);
7563 
7564    /* count number of binary, integer, and continuous variables */
7565    for( i = 0; i < nnz; i++ )
7566    {
7567       assert(SCIPvarGetProbindex(vars[inds[i]]) == inds[i]);
7568 
7569       if( SCIPvarIsBinary(vars[inds[i]]) )
7570          ++nbinvars;
7571       else if( SCIPvarIsIntegral(vars[inds[i]]) )
7572          ++nintvars;
7573       else
7574          ++ncontvars;
7575    }
7576 
7577    SCIPsetDebugMsg(set, "start dual proof tightening:\n");
7578    SCIPsetDebugMsg(set, "-> tighten dual proof: nvars=%d (bin=%d, int=%d, cont=%d)\n",
7579          nnz, nbinvars, nintvars, ncontvars);
7580    debugPrintViolationInfo(set, aggrRowGetMinActivity(set, transprob, proofrow, curvarlbs, curvarubs, NULL), SCIPaggrRowGetRhs(proofrow), NULL);
7581 
7582    /* try to find an alternative proof of local infeasibility that is stronger */
7583    if( set->conf_sepaaltproofs )
7584    {
7585       SCIP_CALL( separateAlternativeProofs(conflict, set, stat, transprob, tree, blkmem, proofrow, curvarlbs, curvarubs,
7586             conflict->conflictset->conflicttype) );
7587    }
7588 
7589    if( initialproof )
7590       proofset = conflict->proofset;
7591    else
7592    {
7593       SCIP_CALL( proofsetCreate(&proofset, blkmem) );
7594    }
7595 
7596    /* start with a proofset containing all variables with a non-zero coefficient in the dual proof */
7597    SCIP_CALL( proofsetAddAggrrow(proofset, set, blkmem, proofrow) );
7598    proofset->conflicttype = conflict->conflictset->conflicttype;
7599    proofset->validdepth = validdepth;
7600 
7601    /* get proof data */
7602    vals = proofsetGetVals(proofset);
7603    inds = proofsetGetInds(proofset);
7604    nnz = proofsetGetNVars(proofset);
7605 
7606 #ifndef NDEBUG
7607    for( i = 0; i < nnz; i++ )
7608    {
7609       int idx = inds[i];
7610       if( vals[i] > 0.0 )
7611          assert(!SCIPsetIsInfinity(set, -curvarlbs[idx]));
7612       if( vals[i] < 0.0 )
7613          assert(!SCIPsetIsInfinity(set, curvarubs[idx]));
7614    }
7615 #endif
7616 
7617    /* remove continuous variable contributing with their global bound
7618     *
7619     * todo: check whether we also want to do that for bound exceeding proofs, but then we cannot update the
7620     *       conflict anymore
7621     */
7622    if( proofset->conflicttype == SCIP_CONFTYPE_INFEASLP )
7623    {
7624       /* remove all continuous variables that have equal global and local bounds (ub or lb depend on the sign)
7625        * from the proof
7626        */
7627 
7628       for( i = 0; i < nnz && nnz > 1; )
7629       {
7630          SCIP_Real val;
7631          int idx = inds[i];
7632 
7633          assert(vars[idx] != NULL);
7634 
7635          val = vals[i];
7636          assert(!SCIPsetIsZero(set, val));
7637 
7638          /* skip integral variables */
7639          if( SCIPvarGetType(vars[idx]) != SCIP_VARTYPE_CONTINUOUS && SCIPvarGetType(vars[idx]) != SCIP_VARTYPE_IMPLINT )
7640          {
7641             i++;
7642             continue;
7643          }
7644          else
7645          {
7646             SCIP_Real glbbd;
7647             SCIP_Real locbd;
7648 
7649             /* get appropriate global and local bounds */
7650             glbbd = (val < 0.0 ? SCIPvarGetUbGlobal(vars[idx]) : SCIPvarGetLbGlobal(vars[idx]));
7651             locbd = (val < 0.0 ? curvarubs[idx] : curvarlbs[idx]);
7652 
7653             if( !SCIPsetIsEQ(set, glbbd, locbd) )
7654             {
7655                i++;
7656                continue;
7657             }
7658 
7659             SCIPsetDebugMsg(set, "-> remove continuous variable <%s>: glb=[%g,%g], loc=[%g,%g], val=%g\n",
7660                   SCIPvarGetName(vars[idx]), SCIPvarGetLbGlobal(vars[idx]), SCIPvarGetUbGlobal(vars[idx]),
7661                   curvarlbs[idx], curvarubs[idx], val);
7662 
7663             proofsetCancelVarWithBound(proofset, set, vars[idx], i, &valid);
7664             assert(valid); /* this should be always fulfilled at this place */
7665 
7666             --nnz;
7667          }
7668       }
7669    }
7670 
7671    /* apply coefficient tightening to initial proof */
7672    tightenCoefficients(set, proofset, &nchgcoefs, &redundant);
7673 
7674    /* it can happen that the constraints is almost globally redundant w.r.t to the maximal activity,
7675     * e.g., due to numerics. in this case, we want to discard the proof
7676     */
7677    if( redundant )
7678    {
7679 #ifndef NDEBUG
7680       SCIP_Real eps = MIN(0.01, 10.0*set->num_feastol);
7681       assert(proofset->rhs - getMaxActivity(set, transprob, proofset->vals, proofset->inds, proofset->nnz, NULL, NULL) < eps);
7682 #endif
7683       if( initialproof )
7684       {
7685          proofsetClear(proofset);
7686       }
7687       else
7688       {
7689          proofsetFree(&proofset, blkmem);
7690       }
7691    }
7692    else
7693    {
7694       if( !initialproof )
7695       {
7696          SCIP_CALL( conflictInsertProofset(conflict, set, proofset) );
7697       }
7698 
7699       if( nchgcoefs > 0 )
7700       {
7701          if( proofset->conflicttype == SCIP_CONFTYPE_INFEASLP )
7702             proofset->conflicttype = SCIP_CONFTYPE_ALTINFPROOF;
7703          else if( proofset->conflicttype == SCIP_CONFTYPE_BNDEXCEEDING )
7704             proofset->conflicttype = SCIP_CONFTYPE_ALTBNDPROOF;
7705       }
7706    }
7707 
7708    return SCIP_OKAY;
7709 }
7710 
7711 /** perform conflict analysis based on a dual unbounded ray
7712  *
7713  *  given an aggregation of rows lhs <= a^Tx such that lhs > maxactivity. if the constraint has size one we add a
7714  *  bound change instead of the constraint.
7715  */
7716 static
conflictAnalyzeDualProof(SCIP_CONFLICT * conflict,SCIP_SET * set,SCIP_STAT * stat,BMS_BLKMEM * blkmem,SCIP_PROB * origprob,SCIP_PROB * transprob,SCIP_TREE * tree,SCIP_REOPT * reopt,SCIP_LP * lp,SCIP_AGGRROW * proofrow,int validdepth,SCIP_Real * curvarlbs,SCIP_Real * curvarubs,SCIP_Bool initialproof,SCIP_Bool * globalinfeasible,SCIP_Bool * success)7717 SCIP_RETCODE conflictAnalyzeDualProof(
7718    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
7719    SCIP_SET*             set,                /**< global SCIP settings */
7720    SCIP_STAT*            stat,               /**< dynamic SCIP statistics */
7721    BMS_BLKMEM*           blkmem,             /**< block memory */
7722    SCIP_PROB*            origprob,           /**< original problem */
7723    SCIP_PROB*            transprob,          /**< transformed problem */
7724    SCIP_TREE*            tree,               /**< tree data */
7725    SCIP_REOPT*           reopt,              /**< reoptimization data */
7726    SCIP_LP*              lp,                 /**< LP data */
7727    SCIP_AGGRROW*         proofrow,           /**< aggregated row representing the proof */
7728    int                   validdepth,         /**< valid depth of the dual proof */
7729    SCIP_Real*            curvarlbs,          /**< current lower bounds of active problem variables */
7730    SCIP_Real*            curvarubs,          /**< current upper bounds of active problem variables */
7731    SCIP_Bool             initialproof,       /**< do we analyze the initial reason of infeasibility? */
7732    SCIP_Bool*            globalinfeasible,   /**< pointer to store whether global infeasibility could be proven */
7733    SCIP_Bool*            success             /**< pointer to store success result */
7734    )
7735 {
7736    SCIP_Real rhs;
7737    SCIP_Real minact;
7738    SCIP_Bool infdelta;
7739    int nnz;
7740 
7741    assert(set != NULL);
7742    assert(transprob != NULL);
7743    assert(validdepth >= 0);
7744    assert(validdepth == 0 || validdepth < SCIPtreeGetFocusDepth(tree));
7745 
7746    /* get sparse data */
7747    nnz = SCIPaggrRowGetNNz(proofrow);
7748    rhs = SCIPaggrRowGetRhs(proofrow);
7749 
7750    *globalinfeasible = FALSE;
7751    *success = FALSE;
7752 
7753    /* get minimal activity w.r.t. local bounds */
7754    minact = aggrRowGetMinActivity(set, transprob, proofrow, curvarlbs, curvarubs, &infdelta);
7755 
7756    if( infdelta )
7757       return SCIP_OKAY;
7758 
7759    /* only run is the proof proves local infeasibility */
7760    if( SCIPsetIsFeasLE(set, minact, rhs) )
7761       return SCIP_OKAY;
7762 
7763    /* if the farkas-proof is empty, the node and its sub tree can be cut off completely */
7764    if( nnz == 0 )
7765    {
7766       SCIPsetDebugMsg(set, " -> empty farkas-proof in depth %d cuts off sub tree at depth %d\n", SCIPtreeGetFocusDepth(tree), validdepth);
7767 
7768       SCIP_CALL( SCIPnodeCutoff(tree->path[validdepth], set, stat, tree, transprob, origprob, reopt, lp, blkmem) );
7769 
7770       *globalinfeasible = TRUE;
7771       *success = TRUE;
7772 
7773       ++conflict->ndualproofsinfsuccess;
7774 
7775       return SCIP_OKAY;
7776    }
7777 
7778    /* try to enforce the constraint based on a dual ray */
7779    SCIP_CALL( tightenDualproof(conflict, set, stat, blkmem, transprob, tree, proofrow, validdepth,
7780       curvarlbs, curvarubs, initialproof) );
7781 
7782    if( *globalinfeasible )
7783    {
7784       SCIPsetDebugMsg(set, "detect global: cutoff root node\n");
7785       SCIP_CALL( SCIPnodeCutoff(tree->path[0], set, stat, tree, transprob, origprob, reopt, lp, blkmem) );
7786       *success = TRUE;
7787 
7788       ++conflict->ndualproofsinfsuccess;
7789    }
7790 
7791    return SCIP_OKAY;
7792 }
7793 
7794 /** try to find a subset of changed bounds leading to an infeasible LP
7795  *
7796  *  1. call undoBdchgsDualfarkas() or undoBdchgsDualsol()
7797  *     -> update lb/ubchginfoposs arrays
7798  *     -> store additional changes in bdchg and curvarlbs/ubs arrays
7799  *     -> apply additional changes to the LPI
7800  *  2. (optional) if additional bound changes were undone:
7801  *     -> resolve LP
7802  *     -> goto 1.
7803  *  3. redo all bound changes in the LPI to restore the LPI to its original state
7804  *  4. analyze conflict
7805  *     -> put remaining changed bounds (see lb/ubchginfoposs arrays) into starting conflict set
7806  */
7807 static
runBoundHeuristic(SCIP_CONFLICT * conflict,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * origprob,SCIP_PROB * transprob,SCIP_TREE * tree,SCIP_REOPT * reopt,SCIP_LP * lp,SCIP_LPI * lpi,BMS_BLKMEM * blkmem,SCIP_Real * proofcoefs,SCIP_Real * prooflhs,SCIP_Real * proofactivity,SCIP_Real * curvarlbs,SCIP_Real * curvarubs,int * lbchginfoposs,int * ubchginfoposs,int * iterations,SCIP_Bool marklpunsolved,SCIP_Bool * dualproofsuccess,SCIP_Bool * valid)7808 SCIP_RETCODE runBoundHeuristic(
7809    SCIP_CONFLICT*        conflict,           /**< conflict data */
7810    SCIP_SET*             set,                /**< global SCIP settings */
7811    SCIP_STAT*            stat,               /**< problem statistics */
7812    SCIP_PROB*            origprob,           /**< original problem */
7813    SCIP_PROB*            transprob,          /**< transformed problem */
7814    SCIP_TREE*            tree,               /**< branch and bound tree */
7815    SCIP_REOPT*           reopt,              /**< reoptimization data */
7816    SCIP_LP*              lp,                 /**< LP data */
7817    SCIP_LPI*             lpi,                /**< LPI data */
7818    BMS_BLKMEM*           blkmem,             /**< block memory */
7819    SCIP_Real*            proofcoefs,         /**< coefficients in the proof constraint */
7820    SCIP_Real*            prooflhs,           /**< lhs of the proof constraint */
7821    SCIP_Real*            proofactivity,      /**< maximal activity of the proof constraint */
7822    SCIP_Real*            curvarlbs,          /**< current lower bounds of active problem variables */
7823    SCIP_Real*            curvarubs,          /**< current upper bounds of active problem variables */
7824    int*                  lbchginfoposs,      /**< positions of currently active lower bound change information in variables' arrays */
7825    int*                  ubchginfoposs,      /**< positions of currently active upper bound change information in variables' arrays */
7826    int*                  iterations,         /**< pointer to store the total number of LP iterations used */
7827    SCIP_Bool             marklpunsolved,     /**< whether LP should be marked unsolved after analysis (needed for strong branching) */
7828    SCIP_Bool*            dualproofsuccess,   /**< pointer to store success result of dual proof analysis */
7829    SCIP_Bool*            valid               /**< pointer to store whether the result is still a valid proof */
7830    )
7831 {
7832    SCIP_LPBDCHGS* oldlpbdchgs;
7833    SCIP_LPBDCHGS* relaxedlpbdchgs;
7834    SCIP_Bool solvelp;
7835    SCIP_Bool resolve;
7836    int ncols;
7837 
7838    assert(set != NULL);
7839 
7840    /* get number of columns in the LP */
7841    ncols = SCIPlpGetNCols(lp);
7842 
7843    /* get temporary memory for remembering bound changes on LPI columns */
7844    SCIP_CALL( lpbdchgsCreate(&oldlpbdchgs, set, ncols) );
7845    SCIP_CALL( lpbdchgsCreate(&relaxedlpbdchgs, set, ncols) );
7846 
7847    /* undo as many bound changes as possible with the current LP solution */
7848    resolve = FALSE;
7849    if( (*valid) )
7850    {
7851       int currentdepth;
7852       currentdepth = SCIPtreeGetCurrentDepth(tree);
7853 
7854       if( SCIPlpiIsPrimalInfeasible(lpi) )
7855       {
7856          SCIP_CALL( undoBdchgsDualfarkas(set, transprob, lp, currentdepth, curvarlbs, curvarubs, lbchginfoposs, \
7857                ubchginfoposs, oldlpbdchgs, relaxedlpbdchgs, valid, &resolve, proofcoefs, *prooflhs, proofactivity) );
7858       }
7859       else
7860       {
7861          assert(SCIPlpiIsDualFeasible(lpi) || SCIPlpiIsObjlimExc(lpi));
7862          SCIP_CALL( undoBdchgsDualsol(set, transprob, lp, currentdepth, curvarlbs, curvarubs, lbchginfoposs, ubchginfoposs, \
7863                oldlpbdchgs, relaxedlpbdchgs, valid, &resolve, proofcoefs, *prooflhs, proofactivity) );
7864       }
7865    }
7866 
7867    /* check if we want to solve the LP */
7868    assert(SCIPprobAllColsInLP(transprob, set, lp));
7869    solvelp = (set->conf_maxlploops != 0 && set->conf_lpiterations != 0);
7870 
7871    if( (*valid) && resolve && solvelp )
7872    {
7873       SCIP_RETCODE retcode;
7874       SCIP_ROW** rows;
7875       int* sidechginds;
7876       SCIP_Real* sidechgoldlhss;
7877       SCIP_Real* sidechgoldrhss;
7878       SCIP_Real* sidechgnewlhss;
7879       SCIP_Real* sidechgnewrhss;
7880       SCIP_Real lpiinfinity;
7881       SCIP_Bool globalinfeasible;
7882       int maxlploops;
7883       int lpiterations;
7884       int sidechgssize;
7885       int nsidechgs;
7886       int nrows;
7887       int nloops;
7888       int r;
7889 
7890       /* get infinity value of LP solver */
7891       lpiinfinity = SCIPlpiInfinity(lpi);
7892 
7893       /* temporarily disable objective limit and install an iteration limit */
7894       maxlploops = (set->conf_maxlploops >= 0 ? set->conf_maxlploops : INT_MAX);
7895       lpiterations = (set->conf_lpiterations >= 0 ? set->conf_lpiterations : INT_MAX);
7896       SCIP_CALL( SCIPlpiSetRealpar(lpi, SCIP_LPPAR_OBJLIM, lpiinfinity) );
7897       SCIP_CALL( SCIPlpiSetIntpar(lpi, SCIP_LPPAR_LPITLIM, lpiterations) );
7898 
7899       /* get LP rows */
7900       rows = SCIPlpGetRows(lp);
7901       nrows = SCIPlpGetNRows(lp);
7902       assert(nrows == 0 || rows != NULL);
7903 
7904       /* get temporary memory for remembering side changes on LPI rows */
7905       SCIP_CALL( SCIPsetAllocBufferArray(set, &sidechginds, nrows) );
7906       SCIP_CALL( SCIPsetAllocBufferArray(set, &sidechgoldlhss, nrows) );
7907       SCIP_CALL( SCIPsetAllocBufferArray(set, &sidechgoldrhss, nrows) );
7908       SCIP_CALL( SCIPsetAllocBufferArray(set, &sidechgnewlhss, nrows) );
7909       SCIP_CALL( SCIPsetAllocBufferArray(set, &sidechgnewrhss, nrows) );
7910       sidechgssize = nrows;
7911       nsidechgs = 0;
7912 
7913       /* remove all local rows by setting their sides to infinity;
7914        * finite sides are only changed to near infinity, such that the row's sense in the LP solver
7915        * is not affected (e.g. CPLEX cannot handle free rows)
7916        */
7917       for( r = 0; r < nrows; ++r )
7918       {
7919          assert(SCIProwGetLPPos(rows[r]) == r);
7920 
7921          if( SCIProwIsLocal(rows[r]) )
7922          {
7923             SCIPsetDebugMsg(set, " -> removing local row <%s> [%g,%g]\n",
7924                SCIProwGetName(rows[r]), SCIProwGetLhs(rows[r]), SCIProwGetRhs(rows[r]));
7925             SCIP_CALL( addSideRemoval(set, rows[r], lpiinfinity, &sidechginds, &sidechgoldlhss, &sidechgoldrhss,
7926                   &sidechgnewlhss, &sidechgnewrhss, &sidechgssize, &nsidechgs) );
7927          }
7928       }
7929 
7930       /* apply changes of local rows to the LP solver */
7931       if( nsidechgs > 0 )
7932       {
7933          SCIP_CALL( SCIPlpiChgSides(lpi, nsidechgs, sidechginds, sidechgnewlhss, sidechgnewrhss) );
7934       }
7935 
7936       /* undo as many additional bound changes as possible by resolving the LP */
7937       assert((*valid));
7938       assert(resolve);
7939       nloops = 0;
7940       globalinfeasible = FALSE;
7941       while( (*valid) && resolve && nloops < maxlploops )
7942       {
7943          int iter;
7944 
7945          assert(!globalinfeasible);
7946 
7947          nloops++;
7948          resolve = FALSE;
7949 
7950          SCIPsetDebugMsg(set, "infeasible LP conflict analysis loop %d (changed col bounds: %d)\n", nloops, relaxedlpbdchgs->nbdchgs);
7951 
7952          /* apply bound changes to the LP solver */
7953          assert(relaxedlpbdchgs->nbdchgs >= 0);
7954          if( relaxedlpbdchgs->nbdchgs > 0 )
7955          {
7956             SCIPsetDebugMsg(set, " -> applying %d bound changes to the LP solver\n", relaxedlpbdchgs->nbdchgs);
7957             SCIP_CALL( SCIPlpiChgBounds(lpi, relaxedlpbdchgs->nbdchgs, relaxedlpbdchgs->bdchginds, \
7958                   relaxedlpbdchgs->bdchglbs, relaxedlpbdchgs->bdchgubs) );
7959 
7960             /* reset conflict LP bound change data structure */
7961             lpbdchgsReset(relaxedlpbdchgs, ncols);
7962          }
7963 
7964          /* start LP timer */
7965          SCIPclockStart(stat->conflictlptime, set);
7966 
7967          /* resolve LP */
7968          retcode = SCIPlpiSolveDual(lpi);
7969 
7970          /* stop LP timer */
7971          SCIPclockStop(stat->conflictlptime, set);
7972 
7973          /* check return code of LP solving call */
7974          if( retcode == SCIP_LPERROR )
7975          {
7976             (*valid) = FALSE;
7977             break;
7978          }
7979          SCIP_CALL( retcode );
7980 
7981          /* count number of LP iterations */
7982          SCIP_CALL( SCIPlpiGetIterations(lpi, &iter) );
7983          (*iterations) += iter;
7984          stat->nconflictlps++;
7985          stat->nconflictlpiterations += iter;
7986          SCIPsetDebugMsg(set, " -> resolved LP in %d iterations (total: %" SCIP_LONGINT_FORMAT ") (infeasible:%u)\n",
7987             iter, stat->nconflictlpiterations, SCIPlpiIsPrimalInfeasible(lpi));
7988 
7989          /* evaluate result */
7990          if( SCIPlpiIsDualFeasible(lpi) || SCIPlpiIsObjlimExc(lpi) )
7991          {
7992             SCIP_Real objval;
7993 
7994             SCIP_CALL( SCIPlpiGetObjval(lpi, &objval) );
7995             (*valid) = (objval >= lp->lpiobjlim && !SCIPlpDivingObjChanged(lp));
7996          }
7997          else
7998             (*valid) = SCIPlpiIsPrimalInfeasible(lpi);
7999 
8000          if( (*valid) )
8001          {
8002             int currentdepth;
8003             currentdepth = SCIPtreeGetCurrentDepth(tree);
8004 
8005             /* undo additional bound changes */
8006             if( SCIPlpiIsPrimalInfeasible(lpi) )
8007             {
8008                SCIP_AGGRROW* farkasrow;
8009                int* inds;
8010                int validdepth;
8011                int nnz;
8012                int v;
8013 
8014 #ifndef NDEBUG
8015                SCIP_VAR** vars = SCIPprobGetVars(transprob);
8016 #endif
8017 
8018                SCIP_CALL( SCIPaggrRowCreate(set->scip, &farkasrow) );
8019 
8020                /* the original LP exceeds the current cutoff bound, thus, we have not constructed the Farkas proof */
8021                SCIP_CALL( getFarkasProof(set, transprob, lp, lpi, tree, farkasrow, proofactivity, &validdepth,
8022                   curvarlbs, curvarubs, valid) );
8023 
8024                /* the constructed Farkas proof is not valid, we need to break here */
8025                if( !(*valid) )
8026                {
8027                   SCIPaggrRowFree(set->scip, &farkasrow);
8028                   break;
8029                }
8030 
8031                /* start dual proof analysis */
8032                if( set->conf_useinflp == 'd' || set->conf_useinflp == 'b' )
8033                {
8034                   /* change the conflict type */
8035                   SCIP_CONFTYPE oldconftype = conflict->conflictset->conflicttype;
8036                   conflict->conflictset->conflicttype = SCIP_CONFTYPE_INFEASLP;
8037 
8038                   /* start dual proof analysis */
8039                   SCIP_CALL( conflictAnalyzeDualProof(conflict, set, stat, blkmem, origprob, transprob, tree, reopt, lp, \
8040                         farkasrow, validdepth, curvarlbs, curvarubs, FALSE, &globalinfeasible, dualproofsuccess) );
8041 
8042                   conflict->conflictset->conflicttype = oldconftype;
8043                }
8044 
8045                /* todo: in theory, we could apply conflict graph analysis for locally valid proofs, too, but this needs to be implemented */
8046                if( globalinfeasible || validdepth > SCIPtreeGetEffectiveRootDepth(tree) )
8047                {
8048                   SCIPaggrRowFree(set->scip, &farkasrow);
8049                   goto TERMINATE;
8050                }
8051 
8052                BMSclearMemoryArray(proofcoefs, SCIPprobGetNVars(transprob));
8053                (*prooflhs) = -SCIPaggrRowGetRhs(farkasrow);
8054                (*proofactivity) = -(*proofactivity);
8055 
8056                inds = SCIPaggrRowGetInds(farkasrow);
8057                nnz = SCIPaggrRowGetNNz(farkasrow);
8058 
8059                for( v = 0; v < nnz; v++ )
8060                {
8061                   int i = inds[v];
8062 
8063                   assert(SCIPvarGetProbindex(vars[i]) == inds[v]);
8064 
8065                   proofcoefs[i] = -SCIPaggrRowGetProbvarValue(farkasrow, i);
8066                }
8067 
8068                /* free aggregation rows */
8069                SCIPaggrRowFree(set->scip, &farkasrow);
8070 
8071                SCIP_CALL( undoBdchgsDualfarkas(set, transprob, lp, currentdepth, curvarlbs, curvarubs, lbchginfoposs, \
8072                      ubchginfoposs,  oldlpbdchgs, relaxedlpbdchgs, valid, &resolve, proofcoefs, (*prooflhs), proofactivity) );
8073             }
8074             else
8075             {
8076                SCIP_AGGRROW* proofrow;
8077                int* inds;
8078                int validdepth;
8079                int nnz;
8080                int v;
8081 
8082 #ifndef NDEBUG
8083                SCIP_VAR** vars = SCIPprobGetVars(transprob);
8084 #endif
8085 
8086                assert(SCIPlpiIsDualFeasible(lpi) || SCIPlpiIsObjlimExc(lpi));
8087 
8088                SCIP_CALL( SCIPaggrRowCreate(set->scip, &proofrow) );
8089 
8090                SCIP_CALL( getDualProof(set, transprob, lp, lpi, tree, proofrow, proofactivity, &validdepth,
8091                   curvarlbs, curvarubs, valid) );
8092 
8093                /* the constructed dual proof is not valid, we need to break here */
8094                if( !(*valid) || validdepth > SCIPtreeGetEffectiveRootDepth(tree) )
8095                {
8096                   SCIPaggrRowFree(set->scip, &proofrow);
8097                   break;
8098                }
8099                /* in contrast to the infeasible case we don't want to analyze the (probably identical) proof again. */
8100 
8101                BMSclearMemoryArray(proofcoefs, SCIPprobGetNVars(transprob));
8102                (*prooflhs) = -SCIPaggrRowGetRhs(proofrow);
8103                (*proofactivity) = -(*proofactivity);
8104 
8105                inds = SCIPaggrRowGetInds(proofrow);
8106                nnz = SCIPaggrRowGetNNz(proofrow);
8107 
8108                for( v = 0; v < nnz; v++ )
8109                {
8110                   int i = inds[v];
8111 
8112                   assert(SCIPvarGetProbindex(vars[i]) == inds[v]);
8113 
8114                   proofcoefs[i] = -SCIPaggrRowGetProbvarValue(proofrow, i);
8115                }
8116 
8117                /* free aggregation rows */
8118                SCIPaggrRowFree(set->scip, &proofrow);
8119 
8120                SCIP_CALL( undoBdchgsDualsol(set, transprob, lp, currentdepth, curvarlbs, curvarubs, lbchginfoposs, \
8121                      ubchginfoposs, oldlpbdchgs, relaxedlpbdchgs, valid, &resolve, proofcoefs, *prooflhs, proofactivity) );
8122             }
8123          }
8124          assert(!resolve || (*valid));
8125          assert(!resolve || relaxedlpbdchgs->nbdchgs > 0);
8126          SCIPsetDebugMsg(set, " -> finished infeasible LP conflict analysis loop %d (iter: %d, nbdchgs: %d)\n",
8127             nloops, iter, relaxedlpbdchgs->nbdchgs);
8128       }
8129 
8130       SCIPsetDebugMsg(set, "finished undoing bound changes after %d loops (valid=%u, nbdchgs: %d)\n",
8131          nloops, (*valid), oldlpbdchgs->nbdchgs);
8132 
8133    TERMINATE:
8134       /* reset variables to local bounds */
8135       if( oldlpbdchgs->nbdchgs > 0 )
8136       {
8137          SCIP_CALL( SCIPlpiChgBounds(lpi, oldlpbdchgs->nbdchgs, oldlpbdchgs->bdchginds, oldlpbdchgs->bdchglbs, oldlpbdchgs->bdchgubs) );
8138       }
8139 
8140       /* reset changes of local rows */
8141       if( nsidechgs > 0 )
8142       {
8143          SCIP_CALL( SCIPlpiChgSides(lpi, nsidechgs, sidechginds, sidechgoldlhss, sidechgoldrhss) );
8144       }
8145 
8146       /* mark the LP unsolved */
8147       if( oldlpbdchgs->nbdchgs > 0 || nsidechgs > 0 )
8148       {
8149          /* The LPI data are out of sync with LP data. Thus, the LP should be marked
8150           * unsolved. However, for strong branching calls, the LP has to have status 'solved'; in
8151           * this case, marklpunsolved is FALSE and synchronization is performed later. */
8152          if ( marklpunsolved )
8153          {
8154             lp->solved = FALSE;
8155             lp->primalfeasible = FALSE;
8156             lp->primalchecked = FALSE;
8157             lp->dualfeasible = FALSE;
8158             lp->dualchecked = FALSE;
8159             lp->lpobjval = SCIP_INVALID;
8160             lp->lpsolstat = SCIP_LPSOLSTAT_NOTSOLVED;
8161          }
8162       }
8163 
8164       /* reinstall old objective and iteration limits in LP solver */
8165       SCIP_CALL( SCIPlpiSetRealpar(lpi, SCIP_LPPAR_OBJLIM, lp->lpiobjlim) );
8166       SCIP_CALL( SCIPlpiSetIntpar(lpi, SCIP_LPPAR_LPITLIM, lp->lpiitlim) );
8167 
8168       /* free temporary memory */
8169       SCIPsetFreeBufferArray(set, &sidechgnewrhss);
8170       SCIPsetFreeBufferArray(set, &sidechgnewlhss);
8171       SCIPsetFreeBufferArray(set, &sidechgoldrhss);
8172       SCIPsetFreeBufferArray(set, &sidechgoldlhss);
8173       SCIPsetFreeBufferArray(set, &sidechginds);
8174    }
8175 
8176    /* free temporary memory */
8177    lpbdchgsFree(&relaxedlpbdchgs, set);
8178    lpbdchgsFree(&oldlpbdchgs, set);
8179 
8180    return SCIP_OKAY;
8181 }
8182 
8183 /** actually performs analysis of infeasible LP */
8184 static
conflictAnalyzeLP(SCIP_CONFLICT * conflict,SCIP_CONFLICTSTORE * conflictstore,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * transprob,SCIP_PROB * origprob,SCIP_TREE * tree,SCIP_REOPT * reopt,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_EVENTQUEUE * eventqueue,SCIP_CLIQUETABLE * cliquetable,SCIP_Bool diving,SCIP_Bool * dualproofsuccess,int * iterations,int * nconss,int * nliterals,int * nreconvconss,int * nreconvliterals,SCIP_Bool marklpunsolved)8185 SCIP_RETCODE conflictAnalyzeLP(
8186    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
8187    SCIP_CONFLICTSTORE*   conflictstore,      /**< conflict store */
8188    BMS_BLKMEM*           blkmem,             /**< block memory of transformed problem */
8189    SCIP_SET*             set,                /**< global SCIP settings */
8190    SCIP_STAT*            stat,               /**< problem statistics */
8191    SCIP_PROB*            transprob,          /**< transformed problem */
8192    SCIP_PROB*            origprob,           /**< original problem */
8193    SCIP_TREE*            tree,               /**< branch and bound tree */
8194    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
8195    SCIP_LP*              lp,                 /**< LP data */
8196    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
8197    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
8198    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
8199    SCIP_Bool             diving,             /**< are we in strong branching or diving mode? */
8200    SCIP_Bool*            dualproofsuccess,   /**< pointer to store success result of dual proof analysis */
8201    int*                  iterations,         /**< pointer to store the total number of LP iterations used */
8202    int*                  nconss,             /**< pointer to store the number of generated conflict constraints */
8203    int*                  nliterals,          /**< pointer to store the number of literals in generated conflict constraints */
8204    int*                  nreconvconss,       /**< pointer to store the number of generated reconvergence constraints */
8205    int*                  nreconvliterals,    /**< pointer to store the number of literals generated reconvergence constraints */
8206    SCIP_Bool             marklpunsolved      /**< whether LP should be marked unsolved after analysis (needed for strong branching) */
8207    )
8208 {
8209    SCIP_VAR** vars;
8210    SCIP_AGGRROW* farkasrow;
8211    SCIP_LPI* lpi;
8212    SCIP_Bool valid;
8213    SCIP_Bool globalinfeasible;
8214    int* lbchginfoposs;
8215    int* ubchginfoposs;
8216    int validdepth;
8217    int nvars;
8218    int v;
8219    SCIP_Real* curvarlbs;
8220    SCIP_Real* curvarubs;
8221    SCIP_Real farkasactivity;
8222 
8223    assert(conflict != NULL);
8224    assert(conflict->nconflictsets == 0);
8225    assert(set != NULL);
8226    assert(SCIPprobAllColsInLP(transprob, set, lp)); /* LP conflict analysis is only valid, if all variables are known */
8227    assert(stat != NULL);
8228    assert(transprob != NULL);
8229    assert(lp != NULL);
8230    assert(lp->flushed);
8231    assert(lp->solved);
8232    assert(iterations != NULL);
8233    assert(nconss != NULL);
8234    assert(nliterals != NULL);
8235    assert(nreconvconss != NULL);
8236    assert(nreconvliterals != NULL);
8237 
8238    *iterations = 0;
8239    *nconss = 0;
8240    *nliterals = 0;
8241    *nreconvconss = 0;
8242    *nreconvliterals = 0;
8243 
8244    vars = transprob->vars;
8245    nvars = transprob->nvars;
8246 
8247    valid = TRUE;
8248    validdepth = 0;
8249 
8250    /* get LP solver interface */
8251    lpi = SCIPlpGetLPI(lp);
8252    assert(SCIPlpiIsPrimalInfeasible(lpi) || SCIPlpiIsObjlimExc(lpi) || SCIPlpiIsDualFeasible(lpi));
8253    assert(SCIPlpiIsPrimalInfeasible(lpi) || !SCIPlpDivingObjChanged(lp));
8254 
8255    if( !SCIPlpiIsPrimalInfeasible(lpi) )
8256    {
8257       SCIP_Real objval;
8258 
8259       assert(!SCIPlpDivingObjChanged(lp));
8260 
8261       /* make sure, a dual feasible solution exists, that exceeds the objective limit;
8262        * With FASTMIP setting, CPLEX does not apply the final pivot to reach the dual solution exceeding the objective
8263        * limit. Therefore, we have to either turn off FASTMIP and resolve the problem or continue solving it without
8264        * objective limit for at least one iteration. It seems that the strategy to continue with FASTMIP for one
8265        * additional simplex iteration yields better results.
8266        */
8267       SCIP_CALL( SCIPlpiGetObjval(lpi, &objval) );
8268       if( objval < lp->lpiobjlim )
8269       {
8270          SCIP_RETCODE retcode;
8271 
8272          /* temporarily disable objective limit and install an iteration limit */
8273          SCIP_CALL( SCIPlpiSetRealpar(lpi, SCIP_LPPAR_OBJLIM, SCIPlpiInfinity(lpi)) );
8274          SCIP_CALL( SCIPlpiSetIntpar(lpi, SCIP_LPPAR_LPITLIM, 1) );
8275 
8276          /* start LP timer */
8277          SCIPclockStart(stat->conflictlptime, set);
8278 
8279          /* resolve LP */
8280          retcode = SCIPlpiSolveDual(lpi);
8281 
8282          /* stop LP timer */
8283          SCIPclockStop(stat->conflictlptime, set);
8284 
8285          /* check return code of LP solving call */
8286          valid = (retcode != SCIP_LPERROR);
8287          if( valid )
8288          {
8289             int iter;
8290 
8291             SCIP_CALL( retcode );
8292 
8293             /* count number of LP iterations */
8294             SCIP_CALL( SCIPlpiGetIterations(lpi, &iter) );
8295             (*iterations) += iter;
8296             stat->nconflictlps++;
8297             stat->nconflictlpiterations += iter;
8298             SCIPsetDebugMsg(set, " -> resolved objlim exceeding LP in %d iterations (total: %" SCIP_LONGINT_FORMAT ") (infeasible:%u, objlim: %u, optimal:%u)\n",
8299                iter, stat->nconflictlpiterations, SCIPlpiIsPrimalInfeasible(lpi), SCIPlpiIsObjlimExc(lpi), SCIPlpiIsOptimal(lpi));
8300             valid = (SCIPlpiIsObjlimExc(lpi) || SCIPlpiIsPrimalInfeasible(lpi) || SCIPlpiIsDualFeasible(lpi));
8301          }
8302 
8303          /* reinstall old objective and iteration limits in LP solver */
8304          SCIP_CALL( SCIPlpiSetRealpar(lpi, SCIP_LPPAR_OBJLIM, lp->lpiobjlim) );
8305          SCIP_CALL( SCIPlpiSetIntpar(lpi, SCIP_LPPAR_LPITLIM, lp->lpiitlim) );
8306 
8307          /* abort, if the LP produced an error */
8308          if( !valid )
8309             return SCIP_OKAY;
8310       }
8311    }
8312    assert(SCIPlpiIsPrimalInfeasible(lpi) || SCIPlpiIsObjlimExc(lpi) || SCIPlpiIsDualFeasible(lpi));
8313 
8314    if( !SCIPlpiIsPrimalInfeasible(lpi) )
8315    {
8316       SCIP_Real objval;
8317 
8318       assert(!SCIPlpDivingObjChanged(lp));
8319 
8320       SCIP_CALL( SCIPlpiGetObjval(lpi, &objval) );
8321       if( objval < lp->lpiobjlim )
8322       {
8323          SCIPsetDebugMsg(set, " -> LP does not exceed the cutoff bound: obj=%g, cutoff=%g\n", objval, lp->lpiobjlim);
8324          return SCIP_OKAY;
8325       }
8326       else
8327       {
8328          SCIPsetDebugMsg(set, " -> LP exceeds the cutoff bound: obj=%g, cutoff=%g\n", objval, lp->lpiobjlim);
8329       }
8330    }
8331 
8332    assert(valid);
8333 
8334    SCIP_CALL( SCIPaggrRowCreate(set->scip, &farkasrow) );
8335    SCIP_CALL( SCIPsetAllocBufferArray(set, &lbchginfoposs, transprob->nvars) );
8336    SCIP_CALL( SCIPsetAllocBufferArray(set, &ubchginfoposs, transprob->nvars) );
8337 
8338    farkasactivity = 0.0;
8339 
8340    /* get temporary memory for remembering variables' current bounds and corresponding bound change information
8341     * positions in variable's bound change information arrays
8342     */
8343    SCIP_CALL( SCIPsetAllocBufferArray(set, &curvarlbs, nvars) );
8344    SCIP_CALL( SCIPsetAllocBufferArray(set, &curvarubs, nvars) );
8345 
8346    /* get current bounds and current positions in lb/ubchginfos arrays of variables */
8347    valid = TRUE;
8348    for( v = 0; v < nvars && valid; ++v )
8349    {
8350       SCIP_VAR* var;
8351 
8352       var = vars[v];
8353 
8354       curvarlbs[v] = SCIPvarGetLbLP(var, set);
8355       curvarubs[v] = SCIPvarGetUbLP(var, set);
8356       lbchginfoposs[v] = var->nlbchginfos-1;
8357       ubchginfoposs[v] = var->nubchginfos-1;
8358       assert(diving || SCIPsetIsEQ(set, curvarlbs[v], SCIPvarGetLbLocal(var)));
8359       assert(diving || SCIPsetIsEQ(set, curvarubs[v], SCIPvarGetUbLocal(var)));
8360 
8361       /* check, if last bound changes were due to strong branching or diving */
8362       if( diving )
8363       {
8364          SCIP_Real lb;
8365          SCIP_Real ub;
8366 
8367          lb = SCIPvarGetLbLocal(var);
8368          ub = SCIPvarGetUbLocal(var);
8369          if( SCIPsetIsGT(set, curvarlbs[v], lb) )
8370             lbchginfoposs[v] = var->nlbchginfos;
8371          else if( SCIPsetIsLT(set, curvarlbs[v], lb) )
8372          {
8373             /* the bound in the diving LP was relaxed -> the LP is not a subproblem of the current node -> abort! */
8374             /**@todo we could still analyze such a conflict, but we would have to take care with our data structures */
8375             valid = FALSE;
8376          }
8377          if( SCIPsetIsLT(set, curvarubs[v], ub) )
8378             ubchginfoposs[v] = var->nubchginfos;
8379          else if( SCIPsetIsGT(set, curvarubs[v], ub) )
8380          {
8381             /* the bound in the diving LP was relaxed -> the LP is not a subproblem of the current node -> abort! */
8382             /**@todo we could still analyze such a conflict, but we would have to take care with our data structures */
8383             valid = FALSE;
8384          }
8385       }
8386    }
8387 
8388    if( !valid )
8389       goto TERMINATE;
8390 
8391    /* the LP is prooven to be infeasible */
8392    if( SCIPlpiIsPrimalInfeasible(lpi) )
8393    {
8394       SCIP_CALL( getFarkasProof(set, transprob, lp, lpi, tree, farkasrow, &farkasactivity, &validdepth,
8395          curvarlbs, curvarubs, &valid) );
8396    }
8397    /* the LP is dual feasible and/or exceeds the current incumbant solution */
8398    else
8399    {
8400       assert(SCIPlpiIsDualFeasible(lpi) || SCIPlpiIsObjlimExc(lpi));
8401       SCIP_CALL( getDualProof(set, transprob, lp, lpi, tree, farkasrow, &farkasactivity, &validdepth,
8402          curvarlbs, curvarubs, &valid) );
8403    }
8404 
8405    if( !valid || validdepth >= SCIPtreeGetCurrentDepth(tree) )
8406       goto TERMINATE;
8407 
8408    globalinfeasible = FALSE;
8409 
8410    /* start dual proof analysis */
8411    if( ((set->conf_useinflp == 'b' || set->conf_useinflp == 'd') && conflict->conflictset->conflicttype == SCIP_CONFTYPE_INFEASLP)
8412       || ((set->conf_useboundlp == 'b' || set->conf_useboundlp == 'd') && conflict->conflictset->conflicttype == SCIP_CONFTYPE_BNDEXCEEDING) )
8413    {
8414       /* start dual proof analysis */
8415       SCIP_CALL( conflictAnalyzeDualProof(conflict, set, stat, blkmem, origprob, transprob, tree, reopt, lp, farkasrow, \
8416          validdepth, curvarlbs, curvarubs, TRUE, &globalinfeasible, dualproofsuccess) );
8417    }
8418 
8419    assert(valid);
8420 
8421    /* todo: in theory, we could apply conflict graph analysis for locally valid proofs, too, but this needs to be implemented */
8422    if( !globalinfeasible && validdepth <= SCIPtreeGetEffectiveRootDepth(tree)
8423       && (((set->conf_useinflp == 'b' || set->conf_useinflp == 'c') && conflict->conflictset->conflicttype == SCIP_CONFTYPE_INFEASLP)
8424       || ((set->conf_useboundlp == 'b' || set->conf_useboundlp == 'c') && conflict->conflictset->conflicttype == SCIP_CONFTYPE_BNDEXCEEDING)) )
8425    {
8426       SCIP_Real* farkascoefs;
8427       SCIP_Real farkaslhs;
8428       int* inds;
8429       int nnz;
8430 
8431 #ifdef SCIP_DEBUG
8432       {
8433          SCIP_Real objlim;
8434          SCIPsetDebugMsg(set, "analyzing conflict on infeasible LP (infeasible: %u, objlimexc: %u, optimal:%u) in depth %d (diving: %u)\n",
8435                SCIPlpiIsPrimalInfeasible(lpi), SCIPlpiIsObjlimExc(lpi), SCIPlpiIsOptimal(lpi), SCIPtreeGetCurrentDepth(tree), diving);
8436 
8437          SCIP_CALL( SCIPlpiGetRealpar(lpi, SCIP_LPPAR_OBJLIM, &objlim) );
8438          SCIPsetDebugMsg(set, " -> objective limit in LP solver: %g (in LP: %g)\n", objlim, lp->lpiobjlim);
8439       }
8440 #endif
8441 
8442       SCIP_CALL( SCIPsetAllocBufferArray(set, &farkascoefs, SCIPprobGetNVars(transprob)) );
8443       BMSclearMemoryArray(farkascoefs, SCIPprobGetNVars(transprob));
8444 
8445       farkaslhs = -SCIPaggrRowGetRhs(farkasrow);
8446       farkasactivity = -farkasactivity;
8447 
8448       inds = SCIPaggrRowGetInds(farkasrow);
8449       nnz = SCIPaggrRowGetNNz(farkasrow);
8450 
8451       for( v = 0; v < nnz; v++ )
8452       {
8453          int i = inds[v];
8454 
8455          assert(SCIPvarGetProbindex(vars[i]) == inds[v]);
8456 
8457          farkascoefs[i] = -SCIPaggrRowGetProbvarValue(farkasrow, i);
8458       }
8459 
8460       SCIP_CALL( runBoundHeuristic(conflict, set, stat, origprob, transprob, tree, reopt, lp, lpi, blkmem, farkascoefs,
8461             &farkaslhs, &farkasactivity, curvarlbs, curvarubs, lbchginfoposs, ubchginfoposs, iterations, marklpunsolved,
8462             dualproofsuccess, &valid) );
8463 
8464       SCIPsetFreeBufferArray(set, &farkascoefs);
8465 
8466       if( !valid )
8467          goto FLUSHPROOFSETS;
8468 
8469       /* analyze the conflict starting with remaining bound changes */
8470       SCIP_CALL( conflictAnalyzeRemainingBdchgs(conflict, blkmem, set, stat, transprob, tree, diving, \
8471             lbchginfoposs, ubchginfoposs, nconss, nliterals, nreconvconss, nreconvliterals) );
8472 
8473       /* flush conflict set storage */
8474       SCIP_CALL( SCIPconflictFlushConss(conflict, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, \
8475             eventqueue, cliquetable) );
8476    }
8477 
8478   FLUSHPROOFSETS:
8479    /* flush proof set */
8480    if( proofsetGetNVars(conflict->proofset) > 0 || conflict->nproofsets > 0 )
8481    {
8482       SCIP_CALL( conflictFlushProofset(conflict, conflictstore, blkmem, set, stat, transprob, origprob, tree, reopt, lp, \
8483             branchcand, eventqueue, cliquetable) );
8484    }
8485 
8486   TERMINATE:
8487    SCIPsetFreeBufferArray(set, &curvarubs);
8488    SCIPsetFreeBufferArray(set, &curvarlbs);
8489    SCIPsetFreeBufferArray(set, &ubchginfoposs);
8490    SCIPsetFreeBufferArray(set, &lbchginfoposs);
8491    SCIPaggrRowFree(set->scip, &farkasrow);
8492 
8493    return SCIP_OKAY;
8494 }
8495 
8496 /** analyzes an infeasible LP to find out the bound changes on variables that were responsible for the infeasibility;
8497  *  on success, calls standard conflict analysis with the responsible variables as starting conflict set, thus creating
8498  *  a conflict constraint out of the resulting conflict set;
8499  *  updates statistics for infeasible LP conflict analysis
8500  */
8501 static
conflictAnalyzeInfeasibleLP(SCIP_CONFLICT * conflict,SCIP_CONFLICTSTORE * conflictstore,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * transprob,SCIP_PROB * origprob,SCIP_TREE * tree,SCIP_REOPT * reopt,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_EVENTQUEUE * eventqueue,SCIP_CLIQUETABLE * cliquetable,SCIP_Bool * success)8502 SCIP_RETCODE conflictAnalyzeInfeasibleLP(
8503    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
8504    SCIP_CONFLICTSTORE*   conflictstore,      /**< conflict store */
8505    BMS_BLKMEM*           blkmem,             /**< block memory of transformed problem */
8506    SCIP_SET*             set,                /**< global SCIP settings */
8507    SCIP_STAT*            stat,               /**< problem statistics */
8508    SCIP_PROB*            transprob,          /**< transformed problem */
8509    SCIP_PROB*            origprob,           /**< original problem */
8510    SCIP_TREE*            tree,               /**< branch and bound tree */
8511    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
8512    SCIP_LP*              lp,                 /**< LP data */
8513    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
8514    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
8515    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
8516    SCIP_Bool*            success             /**< pointer to store whether a conflict constraint was created, or NULL */
8517    )
8518 {
8519    SCIP_Bool dualraysuccess = FALSE;
8520    SCIP_Longint olddualproofsuccess;
8521    int iterations;
8522    int nconss;
8523    int nliterals;
8524    int nreconvconss;
8525    int nreconvliterals;
8526 
8527    assert(conflict != NULL);
8528    assert(set != NULL);
8529    assert(lp != NULL);
8530    assert(SCIPprobAllColsInLP(transprob, set, lp)); /* LP conflict analysis is only valid, if all variables are known */
8531 
8532    assert(success == NULL || *success == FALSE);
8533 
8534    /* check, if infeasible LP conflict analysis is enabled */
8535    if( !set->conf_enable || set->conf_useinflp == 'o' )
8536       return SCIP_OKAY;
8537 
8538    /* check, if there are any conflict handlers to use a conflict set */
8539    if( set->nconflicthdlrs == 0 )
8540       return SCIP_OKAY;
8541 
8542    SCIPsetDebugMsg(set, "analyzing conflict on infeasible LP in depth %d (solstat: %d, objchanged: %u)\n",
8543       SCIPtreeGetCurrentDepth(tree), SCIPlpGetSolstat(lp), SCIPlpDivingObjChanged(lp));
8544 
8545    /* start timing */
8546    SCIPclockStart(conflict->inflpanalyzetime, set);
8547    conflict->ninflpcalls++;
8548 
8549    conflict->conflictset->conflicttype = SCIP_CONFTYPE_INFEASLP;
8550 
8551    olddualproofsuccess = conflict->ndualproofsinfsuccess;
8552 
8553    /* perform conflict analysis */
8554    SCIP_CALL( conflictAnalyzeLP(conflict, conflictstore, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue, \
8555          cliquetable, SCIPlpDiving(lp), &dualraysuccess, &iterations, &nconss, &nliterals, &nreconvconss, &nreconvliterals, TRUE) );
8556    conflict->ninflpsuccess += ((nconss > 0 || conflict->ndualproofsinfsuccess > olddualproofsuccess) ? 1 : 0);
8557    conflict->ninflpiterations += iterations;
8558    conflict->ninflpconfconss += nconss;
8559    conflict->ninflpconfliterals += nliterals;
8560    conflict->ninflpreconvconss += nreconvconss;
8561    conflict->ninflpreconvliterals += nreconvliterals;
8562    if( success != NULL )
8563       *success = (nconss > 0 || conflict->ndualproofsinfsuccess > olddualproofsuccess);
8564 
8565    /* stop timing */
8566    SCIPclockStop(conflict->inflpanalyzetime, set);
8567 
8568    return SCIP_OKAY;
8569 }
8570 
8571 /** analyzes a bound exceeding LP to find out the bound changes on variables that were responsible for exceeding the
8572  *  primal bound;
8573  *  on success, calls standard conflict analysis with the responsible variables as starting conflict set, thus creating
8574  *  a conflict constraint out of the resulting conflict set;
8575  *  updates statistics for bound exceeding LP conflict analysis
8576  */
8577 static
conflictAnalyzeBoundexceedingLP(SCIP_CONFLICT * conflict,SCIP_CONFLICTSTORE * conflictstore,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * transprob,SCIP_PROB * origprob,SCIP_TREE * tree,SCIP_REOPT * reopt,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_EVENTQUEUE * eventqueue,SCIP_CLIQUETABLE * cliquetable,SCIP_Bool * success)8578 SCIP_RETCODE conflictAnalyzeBoundexceedingLP(
8579    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
8580    SCIP_CONFLICTSTORE*   conflictstore,      /**< conflict store */
8581    BMS_BLKMEM*           blkmem,             /**< block memory of transformed problem */
8582    SCIP_SET*             set,                /**< global SCIP settings */
8583    SCIP_STAT*            stat,               /**< problem statistics */
8584    SCIP_PROB*            transprob,          /**< transformed problem */
8585    SCIP_PROB*            origprob,           /**< original problem */
8586    SCIP_TREE*            tree,               /**< branch and bound tree */
8587    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
8588    SCIP_LP*              lp,                 /**< LP data */
8589    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
8590    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
8591    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
8592    SCIP_Bool*            success             /**< pointer to store whether a conflict constraint was created, or NULL */
8593    )
8594 {
8595    SCIP_Bool dualraysuccess;
8596    SCIP_Longint oldnsuccess;
8597    int iterations;
8598    int nconss;
8599    int nliterals;
8600    int nreconvconss;
8601    int nreconvliterals;
8602 
8603    assert(conflict != NULL);
8604    assert(set != NULL);
8605    assert(lp != NULL);
8606    assert(!SCIPlpDivingObjChanged(lp));
8607    assert(SCIPprobAllColsInLP(transprob, set, lp)); /* LP conflict analysis is only valid, if all variables are known */
8608 
8609    assert(success == NULL || *success == FALSE);
8610 
8611    /* check, if bound exceeding LP conflict analysis is enabled */
8612    if( !set->conf_enable || set->conf_useboundlp == 'o')
8613       return SCIP_OKAY;
8614 
8615    /* check, if there are any conflict handlers to use a conflict set */
8616    if( set->nconflicthdlrs == 0 )
8617       return SCIP_OKAY;
8618 
8619    SCIPsetDebugMsg(set, "analyzing conflict on bound exceeding LP in depth %d (solstat: %d)\n",
8620       SCIPtreeGetCurrentDepth(tree), SCIPlpGetSolstat(lp));
8621 
8622    /* start timing */
8623    SCIPclockStart(conflict->boundlpanalyzetime, set);
8624    conflict->nboundlpcalls++;
8625 
8626    /* mark the conflict to depend on the cutoff bound */
8627    conflict->conflictset->conflicttype = SCIP_CONFTYPE_BNDEXCEEDING;
8628    conflict->conflictset->usescutoffbound = TRUE;
8629 
8630    oldnsuccess = conflict->ndualproofsbndsuccess + conflict->ndualproofsinfsuccess;
8631 
8632    /* perform conflict analysis */
8633    SCIP_CALL( conflictAnalyzeLP(conflict, conflictstore, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue, \
8634          cliquetable, SCIPlpDiving(lp), &dualraysuccess, &iterations, &nconss, &nliterals, &nreconvconss, &nreconvliterals, TRUE) );
8635    conflict->nboundlpsuccess += ((nconss > 0 || conflict->ndualproofsbndsuccess + conflict->ndualproofsinfsuccess > oldnsuccess) ? 1 : 0);
8636    conflict->nboundlpiterations += iterations;
8637    conflict->nboundlpconfconss += nconss;
8638    conflict->nboundlpconfliterals += nliterals;
8639    conflict->nboundlpreconvconss += nreconvconss;
8640    conflict->nboundlpreconvliterals += nreconvliterals;
8641    if( success != NULL )
8642       *success = (nconss > 0 || conflict->ndualproofsbndsuccess + conflict->ndualproofsinfsuccess > oldnsuccess);
8643 
8644    /* stop timing */
8645    SCIPclockStop(conflict->boundlpanalyzetime, set);
8646 
8647    return SCIP_OKAY;
8648 }
8649 
8650 /** analyzes an infeasible or bound exceeding LP to find out the bound changes on variables that were responsible for the
8651  *  infeasibility or for exceeding the primal bound;
8652  *  on success, calls standard conflict analysis with the responsible variables as starting conflict set, thus creating
8653  *  a conflict constraint out of the resulting conflict set;
8654  *  updates statistics for infeasible or bound exceeding LP conflict analysis;
8655  *  may only be called if SCIPprobAllColsInLP()
8656  */
SCIPconflictAnalyzeLP(SCIP_CONFLICT * conflict,SCIP_CONFLICTSTORE * conflictstore,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * transprob,SCIP_PROB * origprob,SCIP_TREE * tree,SCIP_REOPT * reopt,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_EVENTQUEUE * eventqueue,SCIP_CLIQUETABLE * cliquetable,SCIP_Bool * success)8657 SCIP_RETCODE SCIPconflictAnalyzeLP(
8658    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
8659    SCIP_CONFLICTSTORE*   conflictstore,      /**< conflict store */
8660    BMS_BLKMEM*           blkmem,             /**< block memory of transformed problem */
8661    SCIP_SET*             set,                /**< global SCIP settings */
8662    SCIP_STAT*            stat,               /**< problem statistics */
8663    SCIP_PROB*            transprob,          /**< transformed problem */
8664    SCIP_PROB*            origprob,           /**< original problem */
8665    SCIP_TREE*            tree,               /**< branch and bound tree */
8666    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
8667    SCIP_LP*              lp,                 /**< LP data */
8668    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
8669    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
8670    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
8671    SCIP_Bool*            success             /**< pointer to store whether a conflict constraint was created, or NULL */
8672    )
8673 {
8674    SCIP_LPSOLVALS storedsolvals;
8675    SCIP_COLSOLVALS* storedcolsolvals;
8676    SCIP_ROWSOLVALS* storedrowsolvals;
8677    int c;
8678    int r;
8679 
8680    if( success != NULL )
8681       *success = FALSE;
8682 
8683    /* check if the conflict analysis is applicable */
8684    if( !set->conf_enable || (set->conf_useinflp == 'o' && set->conf_useboundlp == 'o') )
8685       return SCIP_OKAY;
8686 
8687    /* in rare cases, it might happen that the solution stati of the LP and the LPI are out of sync; in particular this
8688     * happens when a new incumbent which cuts off the current node is found during the LP solving loop; in this case the
8689     * LP has status objlimit, but if diving has been used, the LPI only has the basis information, but is not solved
8690     *
8691     * @todo: alternatively, solve the LPI
8692     */
8693    if( !SCIPlpiWasSolved(SCIPlpGetLPI(lp)) )
8694       return SCIP_OKAY;
8695 
8696    /* LP conflict analysis is only valid, if all variables are known */
8697    assert( SCIPprobAllColsInLP(transprob, set, lp) );
8698    assert( SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_INFEASIBLE || SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_OBJLIMIT
8699       || (SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_OPTIMAL && set->lp_disablecutoff == 1) );
8700 
8701    /* save status */
8702    storedsolvals.lpsolstat = lp->lpsolstat;
8703    storedsolvals.lpobjval = lp->lpobjval;
8704    storedsolvals.primalfeasible = lp->primalfeasible;
8705    storedsolvals.primalchecked = lp->primalchecked;
8706    storedsolvals.dualfeasible = lp->dualfeasible;
8707    storedsolvals.dualchecked = lp->dualchecked;
8708    storedsolvals.solisbasic = lp->solisbasic;
8709    storedsolvals.lpissolved = lp->solved;
8710 
8711    /* store solution values */
8712    SCIP_CALL( SCIPsetAllocBufferArray(set, &storedcolsolvals, lp->ncols) );
8713    SCIP_CALL( SCIPsetAllocBufferArray(set, &storedrowsolvals, lp->nrows) );
8714    for (c = 0; c < lp->ncols; ++c)
8715    {
8716       SCIP_COL* col;
8717 
8718       col = lp->cols[c];
8719       assert( col != NULL );
8720 
8721       storedcolsolvals[c].primsol = col->primsol;
8722       storedcolsolvals[c].redcost = col->redcost;
8723       storedcolsolvals[c].basisstatus = col->basisstatus; /*lint !e641 !e732*/
8724    }
8725    for (r = 0; r < lp->nrows; ++r)
8726    {
8727       SCIP_ROW* row;
8728 
8729       row = lp->rows[r];
8730       assert( row != NULL );
8731 
8732       if ( lp->lpsolstat == SCIP_LPSOLSTAT_INFEASIBLE )
8733          storedrowsolvals[r].dualsol = row->dualfarkas;
8734       else
8735       {
8736          assert( lp->lpsolstat == SCIP_LPSOLSTAT_OBJLIMIT ||
8737             (SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_OPTIMAL && set->lp_disablecutoff == 1) );
8738          storedrowsolvals[r].dualsol = row->dualsol;
8739       }
8740       storedrowsolvals[r].activity = row->activity;
8741       storedrowsolvals[r].basisstatus = row->basisstatus; /*lint !e641 !e732*/
8742    }
8743 
8744    /* check, if the LP was infeasible or bound exceeding */
8745    if( SCIPlpiIsPrimalInfeasible(SCIPlpGetLPI(lp)) )
8746    {
8747       SCIP_CALL( conflictAnalyzeInfeasibleLP(conflict, conflictstore, blkmem, set, stat, transprob, origprob, tree, \
8748             reopt, lp, branchcand, eventqueue, cliquetable, success) );
8749    }
8750    else
8751    {
8752       SCIP_CALL( conflictAnalyzeBoundexceedingLP(conflict, conflictstore, blkmem, set, stat, transprob, origprob, tree, \
8753             reopt, lp, branchcand, eventqueue, cliquetable, success) );
8754    }
8755 
8756    /* possibly restore solution values */
8757    if( lp->flushed && SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_NOTSOLVED )
8758    {
8759       /* restore status */
8760       lp->lpsolstat = storedsolvals.lpsolstat;
8761       lp->lpobjval = storedsolvals.lpobjval;
8762       lp->primalfeasible = storedsolvals.primalfeasible;
8763       lp->primalchecked = storedsolvals.primalchecked;
8764       lp->dualfeasible = storedsolvals.dualfeasible;
8765       lp->dualchecked = storedsolvals.dualchecked;
8766       lp->solisbasic = storedsolvals.solisbasic;
8767       lp->solved = storedsolvals.lpissolved;
8768 
8769       for (c = 0; c < lp->ncols; ++c)
8770       {
8771          SCIP_COL* col;
8772 
8773          col = lp->cols[c];
8774          assert( col != NULL );
8775          col->primsol = storedcolsolvals[c].primsol;
8776          col->redcost = storedcolsolvals[c].redcost;
8777          col->basisstatus = storedcolsolvals[c].basisstatus; /*lint !e641 !e732*/
8778       }
8779       for (r = 0; r < lp->nrows; ++r)
8780       {
8781          SCIP_ROW* row;
8782 
8783          row = lp->rows[r];
8784          assert( row != NULL );
8785 
8786          if ( lp->lpsolstat == SCIP_LPSOLSTAT_INFEASIBLE )
8787             row->dualfarkas = storedrowsolvals[r].dualsol;
8788          else
8789          {
8790             assert( lp->lpsolstat == SCIP_LPSOLSTAT_OBJLIMIT );
8791             row->dualsol = storedrowsolvals[r].dualsol;
8792          }
8793          row->activity = storedrowsolvals[r].activity;
8794          row->basisstatus = storedrowsolvals[r].basisstatus; /*lint !e641 !e732*/
8795       }
8796    }
8797    SCIPsetFreeBufferArray(set, &storedrowsolvals);
8798    SCIPsetFreeBufferArray(set, &storedcolsolvals);
8799 
8800    return SCIP_OKAY;
8801 }
8802 
8803 /** gets time in seconds used for analyzing infeasible LP conflicts */
SCIPconflictGetInfeasibleLPTime(SCIP_CONFLICT * conflict)8804 SCIP_Real SCIPconflictGetInfeasibleLPTime(
8805    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
8806    )
8807 {
8808    assert(conflict != NULL);
8809 
8810    return SCIPclockGetTime(conflict->inflpanalyzetime);
8811 }
8812 
8813 /** gets number of calls to infeasible LP conflict analysis */
SCIPconflictGetNInfeasibleLPCalls(SCIP_CONFLICT * conflict)8814 SCIP_Longint SCIPconflictGetNInfeasibleLPCalls(
8815    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
8816    )
8817 {
8818    assert(conflict != NULL);
8819 
8820    return conflict->ninflpcalls;
8821 }
8822 
8823 /** gets number of calls to infeasible LP conflict analysis that yield at least one conflict constraint */
SCIPconflictGetNInfeasibleLPSuccess(SCIP_CONFLICT * conflict)8824 SCIP_Longint SCIPconflictGetNInfeasibleLPSuccess(
8825    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
8826    )
8827 {
8828    assert(conflict != NULL);
8829 
8830    return conflict->ninflpsuccess;
8831 }
8832 
8833 /** gets number of conflict constraints detected in infeasible LP conflict analysis */
SCIPconflictGetNInfeasibleLPConflictConss(SCIP_CONFLICT * conflict)8834 SCIP_Longint SCIPconflictGetNInfeasibleLPConflictConss(
8835    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
8836    )
8837 {
8838    assert(conflict != NULL);
8839 
8840    return conflict->ninflpconfconss;
8841 }
8842 
8843 /** gets total number of literals in conflict constraints created in infeasible LP conflict analysis */
SCIPconflictGetNInfeasibleLPConflictLiterals(SCIP_CONFLICT * conflict)8844 SCIP_Longint SCIPconflictGetNInfeasibleLPConflictLiterals(
8845    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
8846    )
8847 {
8848    assert(conflict != NULL);
8849 
8850    return conflict->ninflpconfliterals;
8851 }
8852 
8853 /** gets number of reconvergence constraints detected in infeasible LP conflict analysis */
SCIPconflictGetNInfeasibleLPReconvergenceConss(SCIP_CONFLICT * conflict)8854 SCIP_Longint SCIPconflictGetNInfeasibleLPReconvergenceConss(
8855    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
8856    )
8857 {
8858    assert(conflict != NULL);
8859 
8860    return conflict->ninflpreconvconss;
8861 }
8862 
8863 /** gets total number of literals in reconvergence constraints created in infeasible LP conflict analysis */
SCIPconflictGetNInfeasibleLPReconvergenceLiterals(SCIP_CONFLICT * conflict)8864 SCIP_Longint SCIPconflictGetNInfeasibleLPReconvergenceLiterals(
8865    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
8866    )
8867 {
8868    assert(conflict != NULL);
8869 
8870    return conflict->ninflpreconvliterals;
8871 }
8872 
8873 /** gets number of LP iterations in infeasible LP conflict analysis */
SCIPconflictGetNInfeasibleLPIterations(SCIP_CONFLICT * conflict)8874 SCIP_Longint SCIPconflictGetNInfeasibleLPIterations(
8875    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
8876    )
8877 {
8878    assert(conflict != NULL);
8879 
8880    return conflict->ninflpiterations;
8881 }
8882 
8883 /** gets time in seconds used for analyzing bound exceeding LP conflicts */
SCIPconflictGetBoundexceedingLPTime(SCIP_CONFLICT * conflict)8884 SCIP_Real SCIPconflictGetBoundexceedingLPTime(
8885    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
8886    )
8887 {
8888    assert(conflict != NULL);
8889 
8890    return SCIPclockGetTime(conflict->boundlpanalyzetime);
8891 }
8892 
8893 /** gets number of calls to bound exceeding LP conflict analysis */
SCIPconflictGetNBoundexceedingLPCalls(SCIP_CONFLICT * conflict)8894 SCIP_Longint SCIPconflictGetNBoundexceedingLPCalls(
8895    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
8896    )
8897 {
8898    assert(conflict != NULL);
8899 
8900    return conflict->nboundlpcalls;
8901 }
8902 
8903 /** gets number of calls to bound exceeding LP conflict analysis that yield at least one conflict constraint */
SCIPconflictGetNBoundexceedingLPSuccess(SCIP_CONFLICT * conflict)8904 SCIP_Longint SCIPconflictGetNBoundexceedingLPSuccess(
8905    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
8906    )
8907 {
8908    assert(conflict != NULL);
8909 
8910    return conflict->nboundlpsuccess;
8911 }
8912 
8913 /** gets number of conflict constraints detected in bound exceeding LP conflict analysis */
SCIPconflictGetNBoundexceedingLPConflictConss(SCIP_CONFLICT * conflict)8914 SCIP_Longint SCIPconflictGetNBoundexceedingLPConflictConss(
8915    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
8916    )
8917 {
8918    assert(conflict != NULL);
8919 
8920    return conflict->nboundlpconfconss;
8921 }
8922 
8923 /** gets total number of literals in conflict constraints created in bound exceeding LP conflict analysis */
SCIPconflictGetNBoundexceedingLPConflictLiterals(SCIP_CONFLICT * conflict)8924 SCIP_Longint SCIPconflictGetNBoundexceedingLPConflictLiterals(
8925    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
8926    )
8927 {
8928    assert(conflict != NULL);
8929 
8930    return conflict->nboundlpconfliterals;
8931 }
8932 
8933 /** gets number of reconvergence constraints detected in bound exceeding LP conflict analysis */
SCIPconflictGetNBoundexceedingLPReconvergenceConss(SCIP_CONFLICT * conflict)8934 SCIP_Longint SCIPconflictGetNBoundexceedingLPReconvergenceConss(
8935    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
8936    )
8937 {
8938    assert(conflict != NULL);
8939 
8940    return conflict->nboundlpreconvconss;
8941 }
8942 
8943 /** gets total number of literals in reconvergence constraints created in bound exceeding LP conflict analysis */
SCIPconflictGetNBoundexceedingLPReconvergenceLiterals(SCIP_CONFLICT * conflict)8944 SCIP_Longint SCIPconflictGetNBoundexceedingLPReconvergenceLiterals(
8945    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
8946    )
8947 {
8948    assert(conflict != NULL);
8949 
8950    return conflict->nboundlpreconvliterals;
8951 }
8952 
8953 /** gets number of LP iterations in bound exceeding LP conflict analysis */
SCIPconflictGetNBoundexceedingLPIterations(SCIP_CONFLICT * conflict)8954 SCIP_Longint SCIPconflictGetNBoundexceedingLPIterations(
8955    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
8956    )
8957 {
8958    assert(conflict != NULL);
8959 
8960    return conflict->nboundlpiterations;
8961 }
8962 
8963 
8964 
8965 
8966 /*
8967  * infeasible strong branching conflict analysis
8968  */
8969 
8970 /** analyses infeasible strong branching sub problems for conflicts */
SCIPconflictAnalyzeStrongbranch(SCIP_CONFLICT * conflict,SCIP_CONFLICTSTORE * conflictstore,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * transprob,SCIP_PROB * origprob,SCIP_TREE * tree,SCIP_REOPT * reopt,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_EVENTQUEUE * eventqueue,SCIP_CLIQUETABLE * cliquetable,SCIP_COL * col,SCIP_Bool * downconflict,SCIP_Bool * upconflict)8971 SCIP_RETCODE SCIPconflictAnalyzeStrongbranch(
8972    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
8973    SCIP_CONFLICTSTORE*   conflictstore,      /**< conflict store */
8974    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
8975    SCIP_SET*             set,                /**< global SCIP settings */
8976    SCIP_STAT*            stat,               /**< dynamic problem statistics */
8977    SCIP_PROB*            transprob,          /**< transformed problem */
8978    SCIP_PROB*            origprob,           /**< original problem */
8979    SCIP_TREE*            tree,               /**< branch and bound tree */
8980    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
8981    SCIP_LP*              lp,                 /**< LP data */
8982    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
8983    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
8984    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
8985    SCIP_COL*             col,                /**< LP column with at least one infeasible strong branching subproblem */
8986    SCIP_Bool*            downconflict,       /**< pointer to store whether a conflict constraint was created for an
8987                                               *   infeasible downwards branch, or NULL */
8988    SCIP_Bool*            upconflict          /**< pointer to store whether a conflict constraint was created for an
8989                                               *   infeasible upwards branch, or NULL */
8990    )
8991 {
8992    int* cstat;
8993    int* rstat;
8994    SCIP_RETCODE retcode;
8995    SCIP_Bool resolve;
8996    SCIP_Real oldlb;
8997    SCIP_Real oldub;
8998    SCIP_Real newlb;
8999    SCIP_Real newub;
9000    SCIP_Bool dualraysuccess;
9001    int iter;
9002    int nconss;
9003    int nliterals;
9004    int nreconvconss;
9005    int nreconvliterals;
9006 
9007    assert(stat != NULL);
9008    assert(lp != NULL);
9009    assert(lp->flushed);
9010    assert(lp->solved);
9011    assert(SCIPprobAllColsInLP(transprob, set, lp)); /* LP conflict analysis is only valid, if all variables are known */
9012    assert(col != NULL);
9013    assert((col->sbdownvalid && SCIPsetIsGE(set, col->sbdown, lp->cutoffbound)
9014          && SCIPsetFeasCeil(set, col->primsol-1.0) >= col->lb - 0.5)
9015       || (col->sbupvalid && SCIPsetIsGE(set, col->sbup, lp->cutoffbound)
9016          && SCIPsetFeasFloor(set, col->primsol+1.0) <= col->ub + 0.5));
9017    assert(SCIPtreeGetCurrentDepth(tree) > 0);
9018 
9019    if( downconflict != NULL )
9020       *downconflict = FALSE;
9021    if( upconflict != NULL )
9022       *upconflict = FALSE;
9023 
9024    /* check, if infeasible LP conflict analysis is enabled */
9025    if( !set->conf_enable || !set->conf_usesb )
9026       return SCIP_OKAY;
9027 
9028    /* check, if there are any conflict handlers to use a conflict set */
9029    if( set->nconflicthdlrs == 0 )
9030       return SCIP_OKAY;
9031 
9032    /* inform the LPI that strong branch is (temporarily) finished */
9033    SCIP_CALL( SCIPlpiEndStrongbranch(lp->lpi) );
9034 
9035    /* start timing */
9036    SCIPclockStart(conflict->sbanalyzetime, set);
9037 
9038    /* get temporary memory for storing current LP basis */
9039    SCIP_CALL( SCIPsetAllocBufferArray(set, &cstat, lp->nlpicols) );
9040    SCIP_CALL( SCIPsetAllocBufferArray(set, &rstat, lp->nlpirows) );
9041 
9042    /* get current LP basis */
9043    SCIP_CALL( SCIPlpiGetBase(lp->lpi, cstat, rstat) );
9044 
9045    /* remember old bounds */
9046    oldlb = col->lb;
9047    oldub = col->ub;
9048 
9049    resolve = FALSE;
9050 
9051    /* is down branch infeasible? */
9052    if( col->sbdownvalid && SCIPsetIsGE(set, col->sbdown, lp->cutoffbound) )
9053    {
9054       newub = SCIPsetFeasCeil(set, col->primsol-1.0);
9055       if( newub >= col->lb - 0.5 )
9056       {
9057          SCIPsetDebugMsg(set, "analyzing conflict on infeasible downwards strongbranch for variable <%s>[%g,%g] in depth %d\n",
9058             SCIPvarGetName(SCIPcolGetVar(col)), SCIPvarGetLbLocal(SCIPcolGetVar(col)), SCIPvarGetUbLocal(SCIPcolGetVar(col)),
9059             SCIPtreeGetCurrentDepth(tree));
9060 
9061          conflict->conflictset->conflicttype = SCIP_CONFTYPE_INFEASLP;
9062          conflict->nsbcalls++;
9063 
9064          /* change the upper bound */
9065          col->ub = newub;
9066          SCIP_CALL( SCIPlpiChgBounds(lp->lpi, 1, &col->lpipos, &col->lb, &col->ub) );
9067 
9068          /* start LP timer */
9069          SCIPclockStart(stat->conflictlptime, set);
9070 
9071          /* resolve the LP */
9072          retcode = SCIPlpiSolveDual(lp->lpi);
9073 
9074          /* stop LP timer */
9075          SCIPclockStop(stat->conflictlptime, set);
9076 
9077          /* check return code of LP solving call */
9078          if( retcode != SCIP_LPERROR )
9079          {
9080             SCIP_CALL( retcode );
9081 
9082             /* count number of LP iterations */
9083             SCIP_CALL( SCIPlpiGetIterations(lp->lpi, &iter) );
9084             stat->nconflictlps++;
9085             stat->nconflictlpiterations += iter;
9086             conflict->nsbiterations += iter;
9087             SCIPsetDebugMsg(set, " -> resolved downwards strong branching LP in %d iterations\n", iter);
9088 
9089             /* perform conflict analysis on infeasible LP; last parameter guarantees status 'solved' on return */
9090             SCIP_CALL( conflictAnalyzeLP(conflict, conflictstore, blkmem, set, stat, transprob, origprob, tree, reopt, \
9091                   lp, branchcand, eventqueue, cliquetable, TRUE, &dualraysuccess, &iter, &nconss, &nliterals, \
9092                   &nreconvconss, &nreconvliterals, FALSE) );
9093             conflict->nsbsuccess += ((nconss > 0 || dualraysuccess) ? 1 : 0);
9094             conflict->nsbiterations += iter;
9095             conflict->nsbconfconss += nconss;
9096             conflict->nsbconfliterals += nliterals;
9097             conflict->nsbreconvconss += nreconvconss;
9098             conflict->nsbreconvliterals += nreconvliterals;
9099             if( downconflict != NULL )
9100                *downconflict = (nconss > 0);
9101          }
9102 
9103          /* reset the upper bound */
9104          col->ub = oldub;
9105          SCIP_CALL( SCIPlpiChgBounds(lp->lpi, 1, &col->lpipos, &col->lb, &col->ub) );
9106 
9107          /* reset LP basis */
9108          SCIP_CALL( SCIPlpiSetBase(lp->lpi, cstat, rstat) );
9109 
9110          /* mark the LP to be resolved at the end */
9111          resolve = TRUE;
9112       }
9113    }
9114 
9115    /* is up branch infeasible? */
9116    if( col->sbupvalid && SCIPsetIsGE(set, col->sbup, lp->cutoffbound) )
9117    {
9118       newlb = SCIPsetFeasFloor(set, col->primsol+1.0);
9119       if( newlb <= col->ub + 0.5 )
9120       {
9121          SCIPsetDebugMsg(set, "analyzing conflict on infeasible upwards strongbranch for variable <%s>[%g,%g] in depth %d\n",
9122             SCIPvarGetName(SCIPcolGetVar(col)), SCIPvarGetLbLocal(SCIPcolGetVar(col)), SCIPvarGetUbLocal(SCIPcolGetVar(col)),
9123             SCIPtreeGetCurrentDepth(tree));
9124 
9125          conflict->conflictset->conflicttype = SCIP_CONFTYPE_INFEASLP;
9126          conflict->nsbcalls++;
9127 
9128          /* change the lower bound */
9129          col->lb = newlb;
9130          SCIP_CALL( SCIPlpiChgBounds(lp->lpi, 1, &col->lpipos, &col->lb, &col->ub) );
9131 
9132          /* start LP timer */
9133          SCIPclockStart(stat->conflictlptime, set);
9134 
9135          /* resolve the LP */
9136          retcode = SCIPlpiSolveDual(lp->lpi);
9137 
9138          /* stop LP timer */
9139          SCIPclockStop(stat->conflictlptime, set);
9140 
9141          /* check return code of LP solving call */
9142          if( retcode != SCIP_LPERROR )
9143          {
9144             SCIP_CALL( retcode );
9145 
9146             /* count number of LP iterations */
9147             SCIP_CALL( SCIPlpiGetIterations(lp->lpi, &iter) );
9148             stat->nconflictlps++;
9149             stat->nconflictlpiterations += iter;
9150             conflict->nsbiterations += iter;
9151             SCIPsetDebugMsg(set, " -> resolved upwards strong branching LP in %d iterations\n", iter);
9152 
9153             /* perform conflict analysis on infeasible LP; last parameter guarantees status 'solved' on return */
9154             SCIP_CALL( conflictAnalyzeLP(conflict, conflictstore, blkmem, set, stat, transprob, origprob, tree, reopt, \
9155                   lp, branchcand, eventqueue, cliquetable, TRUE, &dualraysuccess, &iter, &nconss, &nliterals, \
9156                   &nreconvconss, &nreconvliterals, FALSE) );
9157             conflict->nsbsuccess += ((nconss > 0 || dualraysuccess) ? 1 : 0);
9158             conflict->nsbiterations += iter;
9159             conflict->nsbconfconss += nconss;
9160             conflict->nsbconfliterals += nliterals;
9161             conflict->nsbreconvconss += nreconvconss;
9162             conflict->nsbreconvliterals += nreconvliterals;
9163             if( upconflict != NULL )
9164                *upconflict = (nconss > 0);
9165          }
9166 
9167          /* reset the lower bound */
9168          col->lb = oldlb;
9169          SCIP_CALL( SCIPlpiChgBounds(lp->lpi, 1, &col->lpipos, &col->lb, &col->ub) );
9170 
9171          /* reset LP basis */
9172          SCIP_CALL( SCIPlpiSetBase(lp->lpi, cstat, rstat) );
9173 
9174          /* mark the LP to be resolved at the end */
9175          resolve = TRUE;
9176       }
9177    }
9178 
9179    /* free temporary memory for storing current LP basis */
9180    SCIPsetFreeBufferArray(set, &rstat);
9181    SCIPsetFreeBufferArray(set, &cstat);
9182 
9183    assert(lp->flushed);
9184 
9185    /* resolve LP if something has changed in order to synchronize LPI and LP */
9186    if ( resolve )
9187    {
9188       /* start LP timer */
9189       SCIPclockStart(stat->conflictlptime, set);
9190 
9191       /* resolve the LP */
9192       SCIP_CALL( SCIPlpiSolveDual(lp->lpi) );
9193 
9194       /* stop LP timer */
9195       SCIPclockStop(stat->conflictlptime, set);
9196    }
9197 
9198    /* stop timing */
9199    SCIPclockStop(conflict->sbanalyzetime, set);
9200 
9201    /* inform the LPI that strong branch starts (again) */
9202    SCIP_CALL( SCIPlpiStartStrongbranch(lp->lpi) );
9203 
9204    return SCIP_OKAY;
9205 }
9206 
9207 /** gets time in seconds used for analyzing infeasible strong branching conflicts */
SCIPconflictGetStrongbranchTime(SCIP_CONFLICT * conflict)9208 SCIP_Real SCIPconflictGetStrongbranchTime(
9209    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
9210    )
9211 {
9212    assert(conflict != NULL);
9213 
9214    return SCIPclockGetTime(conflict->sbanalyzetime);
9215 }
9216 
9217 /** gets number of successful calls to dual proof analysis derived from infeasible LPs */
SCIPconflictGetNDualproofsInfSuccess(SCIP_CONFLICT * conflict)9218 SCIP_Longint SCIPconflictGetNDualproofsInfSuccess(
9219    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
9220    )
9221 {
9222    assert(conflict != NULL);
9223 
9224    return conflict->ndualproofsinfsuccess;
9225 }
9226 
9227 /** gets number of globally valid dual proof constraints derived from infeasible LPs */
SCIPconflictGetNDualproofsInfGlobal(SCIP_CONFLICT * conflict)9228 SCIP_Longint SCIPconflictGetNDualproofsInfGlobal(
9229    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
9230    )
9231 {
9232    assert(conflict != NULL);
9233 
9234    return conflict->ndualproofsinfglobal;
9235 }
9236 
9237 /** gets number of locally valid dual proof constraints derived from infeasible LPs */
SCIPconflictGetNDualproofsInfLocal(SCIP_CONFLICT * conflict)9238 SCIP_Longint SCIPconflictGetNDualproofsInfLocal(
9239    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
9240    )
9241 {
9242    assert(conflict != NULL);
9243 
9244    return conflict->ndualproofsinflocal;
9245 }
9246 
9247 /** gets average length of dual proof constraints derived from infeasible LPs */
SCIPconflictGetNDualproofsInfNonzeros(SCIP_CONFLICT * conflict)9248 SCIP_Longint SCIPconflictGetNDualproofsInfNonzeros(
9249    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
9250    )
9251 {
9252    assert(conflict != NULL);
9253 
9254    return conflict->dualproofsinfnnonzeros;
9255 }
9256 
9257 /** gets number of successfully analyzed dual proofs derived from bound exceeding LPs */
SCIPconflictGetNDualproofsBndSuccess(SCIP_CONFLICT * conflict)9258 SCIP_Longint SCIPconflictGetNDualproofsBndSuccess(
9259    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
9260    )
9261 {
9262    assert(conflict != NULL);
9263 
9264    return conflict->ndualproofsbndsuccess;
9265 }
9266 
9267 /** gets number of globally applied dual proofs derived from bound exceeding LPs */
SCIPconflictGetNDualproofsBndGlobal(SCIP_CONFLICT * conflict)9268 SCIP_Longint SCIPconflictGetNDualproofsBndGlobal(
9269    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
9270    )
9271 {
9272    assert(conflict != NULL);
9273 
9274    return conflict->ndualproofsbndglobal;
9275 }
9276 
9277 /** gets number of locally applied dual proofs derived from bound exceeding LPs */
SCIPconflictGetNDualproofsBndLocal(SCIP_CONFLICT * conflict)9278 SCIP_Longint SCIPconflictGetNDualproofsBndLocal(
9279    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
9280    )
9281 {
9282    assert(conflict != NULL);
9283 
9284    return conflict->ndualproofsbndlocal;
9285 }
9286 
9287 /** gets average length of dual proofs derived from bound exceeding LPs */
SCIPconflictGetNDualproofsBndNonzeros(SCIP_CONFLICT * conflict)9288 SCIP_Longint SCIPconflictGetNDualproofsBndNonzeros(
9289    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
9290    )
9291 {
9292    assert(conflict != NULL);
9293 
9294    return conflict->dualproofsbndnnonzeros;
9295 }
9296 
9297 /** gets number of calls to infeasible strong branching conflict analysis */
SCIPconflictGetNStrongbranchCalls(SCIP_CONFLICT * conflict)9298 SCIP_Longint SCIPconflictGetNStrongbranchCalls(
9299    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
9300    )
9301 {
9302    assert(conflict != NULL);
9303 
9304    return conflict->nsbcalls;
9305 }
9306 
9307 /** gets number of calls to infeasible strong branching conflict analysis that yield at least one conflict constraint */
SCIPconflictGetNStrongbranchSuccess(SCIP_CONFLICT * conflict)9308 SCIP_Longint SCIPconflictGetNStrongbranchSuccess(
9309    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
9310    )
9311 {
9312    assert(conflict != NULL);
9313 
9314    return conflict->nsbsuccess;
9315 }
9316 
9317 /** gets number of conflict constraints detected in infeasible strong branching conflict analysis */
SCIPconflictGetNStrongbranchConflictConss(SCIP_CONFLICT * conflict)9318 SCIP_Longint SCIPconflictGetNStrongbranchConflictConss(
9319    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
9320    )
9321 {
9322    assert(conflict != NULL);
9323 
9324    return conflict->nsbconfconss;
9325 }
9326 
9327 /** gets total number of literals in conflict constraints created in infeasible strong branching conflict analysis */
SCIPconflictGetNStrongbranchConflictLiterals(SCIP_CONFLICT * conflict)9328 SCIP_Longint SCIPconflictGetNStrongbranchConflictLiterals(
9329    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
9330    )
9331 {
9332    assert(conflict != NULL);
9333 
9334    return conflict->nsbconfliterals;
9335 }
9336 
9337 /** gets number of reconvergence constraints detected in infeasible strong branching conflict analysis */
SCIPconflictGetNStrongbranchReconvergenceConss(SCIP_CONFLICT * conflict)9338 SCIP_Longint SCIPconflictGetNStrongbranchReconvergenceConss(
9339    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
9340    )
9341 {
9342    assert(conflict != NULL);
9343 
9344    return conflict->nsbreconvconss;
9345 }
9346 
9347 /** gets total number of literals in reconvergence constraints created in infeasible strong branching conflict analysis */
SCIPconflictGetNStrongbranchReconvergenceLiterals(SCIP_CONFLICT * conflict)9348 SCIP_Longint SCIPconflictGetNStrongbranchReconvergenceLiterals(
9349    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
9350    )
9351 {
9352    assert(conflict != NULL);
9353 
9354    return conflict->nsbreconvliterals;
9355 }
9356 
9357 /** gets number of LP iterations in infeasible strong branching conflict analysis */
SCIPconflictGetNStrongbranchIterations(SCIP_CONFLICT * conflict)9358 SCIP_Longint SCIPconflictGetNStrongbranchIterations(
9359    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
9360    )
9361 {
9362    assert(conflict != NULL);
9363 
9364    return conflict->nsbiterations;
9365 }
9366 
9367 
9368 
9369 
9370 /*
9371  * pseudo solution conflict analysis
9372  */
9373 
9374 /** analyzes a pseudo solution with objective value exceeding the current cutoff to find out the bound changes on
9375  *  variables that were responsible for the objective value degradation;
9376  *  on success, calls standard conflict analysis with the responsible variables as starting conflict set, thus creating
9377  *  a conflict constraint out of the resulting conflict set;
9378  *  updates statistics for pseudo solution conflict analysis
9379  */
SCIPconflictAnalyzePseudo(SCIP_CONFLICT * conflict,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * transprob,SCIP_PROB * origprob,SCIP_TREE * tree,SCIP_REOPT * reopt,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_EVENTQUEUE * eventqueue,SCIP_CLIQUETABLE * cliquetable,SCIP_Bool * success)9380 SCIP_RETCODE SCIPconflictAnalyzePseudo(
9381    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
9382    BMS_BLKMEM*           blkmem,             /**< block memory of transformed problem */
9383    SCIP_SET*             set,                /**< global SCIP settings */
9384    SCIP_STAT*            stat,               /**< problem statistics */
9385    SCIP_PROB*            transprob,          /**< transformed problem */
9386    SCIP_PROB*            origprob,           /**< original problem */
9387    SCIP_TREE*            tree,               /**< branch and bound tree */
9388    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
9389    SCIP_LP*              lp,                 /**< LP data */
9390    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
9391    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
9392    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
9393    SCIP_Bool*            success             /**< pointer to store whether a conflict constraint was created, or NULL */
9394    )
9395 {
9396    SCIP_VAR** vars;
9397    SCIP_VAR* var;
9398    SCIP_Real* curvarlbs;
9399    SCIP_Real* curvarubs;
9400    int* lbchginfoposs;
9401    int* ubchginfoposs;
9402    SCIP_Real* pseudocoefs;
9403    SCIP_Real pseudolhs;
9404    SCIP_Real pseudoact;
9405    int nvars;
9406    int v;
9407 
9408    assert(conflict != NULL);
9409    assert(conflict->nconflictsets == 0);
9410    assert(set != NULL);
9411    assert(stat != NULL);
9412    assert(transprob != NULL);
9413    assert(lp != NULL);
9414    assert(!SCIPsetIsInfinity(set, -SCIPlpGetPseudoObjval(lp, set, transprob)));
9415    assert(!SCIPsetIsInfinity(set, lp->cutoffbound));
9416 
9417    if( success != NULL )
9418       *success = FALSE;
9419 
9420    /* check, if pseudo solution conflict analysis is enabled */
9421    if( !set->conf_enable || !set->conf_usepseudo )
9422       return SCIP_OKAY;
9423 
9424    /* check, if there are any conflict handlers to use a conflict set */
9425    if( set->nconflicthdlrs == 0 )
9426       return SCIP_OKAY;
9427 
9428    SCIPsetDebugMsg(set, "analyzing pseudo solution (obj: %g) that exceeds objective limit (%g)\n",
9429       SCIPlpGetPseudoObjval(lp, set, transprob), lp->cutoffbound);
9430 
9431    conflict->conflictset->conflicttype = SCIP_CONFTYPE_BNDEXCEEDING;
9432    conflict->conflictset->usescutoffbound = TRUE;
9433 
9434    /* start timing */
9435    SCIPclockStart(conflict->pseudoanalyzetime, set);
9436    conflict->npseudocalls++;
9437 
9438    vars = transprob->vars;
9439    nvars = transprob->nvars;
9440    assert(nvars == 0 || vars != NULL);
9441 
9442    /* The current primal bound c* gives an upper bound for the current pseudo objective value:
9443     *   min{c^T x | lb <= x <= ub} <= c*.
9444     * We have to transform this row into a >= inequality in order to use methods above:
9445     *                          -c* <= max{-c^T x | lb <= x <= ub}.
9446     * In the local subproblem, this row is violated. We want to undo bound changes while still keeping the
9447     * row violated.
9448     */
9449 
9450    /* get temporary memory for remembering variables' current bounds and corresponding bound change information
9451     * positions in variable's bound change information arrays
9452     */
9453    SCIP_CALL( SCIPsetAllocBufferArray(set, &curvarlbs, nvars) );
9454    SCIP_CALL( SCIPsetAllocBufferArray(set, &curvarubs, nvars) );
9455    SCIP_CALL( SCIPsetAllocBufferArray(set, &lbchginfoposs, nvars) );
9456    SCIP_CALL( SCIPsetAllocBufferArray(set, &ubchginfoposs, nvars) );
9457 
9458    /* get temporary memory for infeasibility proof coefficients */
9459    SCIP_CALL( SCIPsetAllocBufferArray(set, &pseudocoefs, nvars) );
9460 
9461    /* use a slightly tighter cutoff bound, because solutions with equal objective value should also be declared
9462     * infeasible
9463     */
9464    pseudolhs = -(lp->cutoffbound - SCIPsetSumepsilon(set));
9465 
9466    /* store the objective values as infeasibility proof coefficients, and recalculate the pseudo activity */
9467    pseudoact = 0.0;
9468    for( v = 0; v < nvars; ++v )
9469    {
9470       var = vars[v];
9471       pseudocoefs[v] = -SCIPvarGetObj(var);
9472       curvarlbs[v] = SCIPvarGetLbLocal(var);
9473       curvarubs[v] = SCIPvarGetUbLocal(var);
9474       lbchginfoposs[v] = var->nlbchginfos-1;
9475       ubchginfoposs[v] = var->nubchginfos-1;
9476 
9477       if( SCIPsetIsZero(set, pseudocoefs[v]) )
9478       {
9479          pseudocoefs[v] = 0.0;
9480          continue;
9481       }
9482 
9483       if( pseudocoefs[v] > 0.0 )
9484          pseudoact += pseudocoefs[v] * curvarubs[v];
9485       else
9486          pseudoact += pseudocoefs[v] * curvarlbs[v];
9487    }
9488    assert(SCIPsetIsFeasEQ(set, pseudoact, -SCIPlpGetPseudoObjval(lp, set, transprob)));
9489    SCIPsetDebugMsg(set, "  -> recalculated pseudo infeasibility proof:  %g <= %g\n", pseudolhs, pseudoact);
9490 
9491    /* check, if the pseudo row is still violated (after recalculation of pseudo activity) */
9492    if( SCIPsetIsFeasGT(set, pseudolhs, pseudoact) )
9493    {
9494       int nconss;
9495       int nliterals;
9496       int nreconvconss;
9497       int nreconvliterals;
9498 
9499       /* undo bound changes without destroying the infeasibility proof */
9500       SCIP_CALL( undoBdchgsProof(set, transprob, SCIPtreeGetCurrentDepth(tree), pseudocoefs, pseudolhs, &pseudoact,
9501             curvarlbs, curvarubs, lbchginfoposs, ubchginfoposs, NULL, NULL, NULL, lp->lpi) );
9502 
9503       /* analyze conflict on remaining bound changes */
9504       SCIP_CALL( conflictAnalyzeRemainingBdchgs(conflict, blkmem, set, stat, transprob, tree, FALSE, \
9505             lbchginfoposs, ubchginfoposs, &nconss, &nliterals, &nreconvconss, &nreconvliterals) );
9506       conflict->npseudosuccess += (nconss > 0 ? 1 : 0);
9507       conflict->npseudoconfconss += nconss;
9508       conflict->npseudoconfliterals += nliterals;
9509       conflict->npseudoreconvconss += nreconvconss;
9510       conflict->npseudoreconvliterals += nreconvliterals;
9511       if( success != NULL )
9512          *success = (nconss > 0);
9513    }
9514 
9515    /* free temporary memory */
9516    SCIPsetFreeBufferArray(set, &pseudocoefs);
9517    SCIPsetFreeBufferArray(set, &ubchginfoposs);
9518    SCIPsetFreeBufferArray(set, &lbchginfoposs);
9519    SCIPsetFreeBufferArray(set, &curvarubs);
9520    SCIPsetFreeBufferArray(set, &curvarlbs);
9521 
9522    /* flush conflict set storage */
9523    SCIP_CALL( SCIPconflictFlushConss(conflict, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue, cliquetable) );
9524 
9525    /* stop timing */
9526    SCIPclockStop(conflict->pseudoanalyzetime, set);
9527 
9528    return SCIP_OKAY;
9529 }
9530 
9531 /** gets time in seconds used for analyzing pseudo solution conflicts */
SCIPconflictGetPseudoTime(SCIP_CONFLICT * conflict)9532 SCIP_Real SCIPconflictGetPseudoTime(
9533    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
9534    )
9535 {
9536    assert(conflict != NULL);
9537 
9538    return SCIPclockGetTime(conflict->pseudoanalyzetime);
9539 }
9540 
9541 /** gets number of calls to pseudo solution conflict analysis */
SCIPconflictGetNPseudoCalls(SCIP_CONFLICT * conflict)9542 SCIP_Longint SCIPconflictGetNPseudoCalls(
9543    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
9544    )
9545 {
9546    assert(conflict != NULL);
9547 
9548    return conflict->npseudocalls;
9549 }
9550 
9551 /** gets number of calls to pseudo solution conflict analysis that yield at least one conflict constraint */
SCIPconflictGetNPseudoSuccess(SCIP_CONFLICT * conflict)9552 SCIP_Longint SCIPconflictGetNPseudoSuccess(
9553    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
9554    )
9555 {
9556    assert(conflict != NULL);
9557 
9558    return conflict->npseudosuccess;
9559 }
9560 
9561 /** gets number of conflict constraints detected in pseudo solution conflict analysis */
SCIPconflictGetNPseudoConflictConss(SCIP_CONFLICT * conflict)9562 SCIP_Longint SCIPconflictGetNPseudoConflictConss(
9563    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
9564    )
9565 {
9566    assert(conflict != NULL);
9567 
9568    return conflict->npseudoconfconss;
9569 }
9570 
9571 /** gets total number of literals in conflict constraints created in pseudo solution conflict analysis */
SCIPconflictGetNPseudoConflictLiterals(SCIP_CONFLICT * conflict)9572 SCIP_Longint SCIPconflictGetNPseudoConflictLiterals(
9573    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
9574    )
9575 {
9576    assert(conflict != NULL);
9577 
9578    return conflict->npseudoconfliterals;
9579 }
9580 
9581 /** gets number of reconvergence constraints detected in pseudo solution conflict analysis */
SCIPconflictGetNPseudoReconvergenceConss(SCIP_CONFLICT * conflict)9582 SCIP_Longint SCIPconflictGetNPseudoReconvergenceConss(
9583    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
9584    )
9585 {
9586    assert(conflict != NULL);
9587 
9588    return conflict->npseudoreconvconss;
9589 }
9590 
9591 /** gets total number of literals in reconvergence constraints created in pseudo solution conflict analysis */
SCIPconflictGetNPseudoReconvergenceLiterals(SCIP_CONFLICT * conflict)9592 SCIP_Longint SCIPconflictGetNPseudoReconvergenceLiterals(
9593    SCIP_CONFLICT*        conflict            /**< conflict analysis data */
9594    )
9595 {
9596    assert(conflict != NULL);
9597 
9598    return conflict->npseudoreconvliterals;
9599 }
9600 
9601 
9602 /** enables or disables all clocks of \p conflict, depending on the value of the flag */
SCIPconflictEnableOrDisableClocks(SCIP_CONFLICT * conflict,SCIP_Bool enable)9603 void SCIPconflictEnableOrDisableClocks(
9604    SCIP_CONFLICT*        conflict,           /**< the conflict analysis data for which all clocks should be enabled or disabled */
9605    SCIP_Bool             enable              /**< should the clocks of the conflict analysis data be enabled? */
9606    )
9607 {
9608    assert(conflict != NULL);
9609 
9610    SCIPclockEnableOrDisable(conflict->boundlpanalyzetime, enable);
9611    SCIPclockEnableOrDisable(conflict->dIBclock, enable);
9612    SCIPclockEnableOrDisable(conflict->inflpanalyzetime, enable);
9613    SCIPclockEnableOrDisable(conflict->propanalyzetime, enable);
9614    SCIPclockEnableOrDisable(conflict->pseudoanalyzetime, enable);
9615    SCIPclockEnableOrDisable(conflict->sbanalyzetime, enable);
9616 }
9617 
9618